diff --git a/.vs/ML9/v16/.suo b/.vs/ML9/v16/.suo
index ac3d5127c12d8d4c2b70b3525e1b9ff46b2cf58b..a5d24894595a87643cc3365cb9d5a1de64041e52 100644
Binary files a/.vs/ML9/v16/.suo and b/.vs/ML9/v16/.suo differ
diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite
index a0e6f4d8286839ef7d549b25b127627e8dbbd7de..e15795308276cecf38a1782faf1038db48eca292 100644
Binary files a/.vs/slnx.sqlite and b/.vs/slnx.sqlite differ
diff --git a/.vscode/.ropeproject/config.py b/.vscode/.ropeproject/config.py
new file mode 100644
index 0000000000000000000000000000000000000000..dee2d1ae9a6be9cf0248130b6c6b9e2668052079
--- /dev/null
+++ b/.vscode/.ropeproject/config.py
@@ -0,0 +1,114 @@
+# The default ``config.py``
+# flake8: noqa
+
+
+def set_prefs(prefs):
+    """This function is called before opening the project"""
+
+    # Specify which files and folders to ignore in the project.
+    # Changes to ignored resources are not added to the history and
+    # VCSs.  Also they are not returned in `Project.get_files()`.
+    # Note that ``?`` and ``*`` match all characters but slashes.
+    # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
+    # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
+    # '.svn': matches 'pkg/.svn' and all of its children
+    # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
+    # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
+    prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
+                                  '.hg', '.svn', '_svn', '.git', '.tox']
+
+    # Specifies which files should be considered python files.  It is
+    # useful when you have scripts inside your project.  Only files
+    # ending with ``.py`` are considered to be python files by
+    # default.
+    # prefs['python_files'] = ['*.py']
+
+    # Custom source folders:  By default rope searches the project
+    # for finding source folders (folders that should be searched
+    # for finding modules).  You can add paths to that list.  Note
+    # that rope guesses project source folders correctly most of the
+    # time; use this if you have any problems.
+    # The folders should be relative to project root and use '/' for
+    # separating folders regardless of the platform rope is running on.
+    # 'src/my_source_folder' for instance.
+    # prefs.add('source_folders', 'src')
+
+    # You can extend python path for looking up modules
+    # prefs.add('python_path', '~/python/')
+
+    # Should rope save object information or not.
+    prefs['save_objectdb'] = True
+    prefs['compress_objectdb'] = False
+
+    # If `True`, rope analyzes each module when it is being saved.
+    prefs['automatic_soa'] = True
+    # The depth of calls to follow in static object analysis
+    prefs['soa_followed_calls'] = 0
+
+    # If `False` when running modules or unit tests "dynamic object
+    # analysis" is turned off.  This makes them much faster.
+    prefs['perform_doa'] = True
+
+    # Rope can check the validity of its object DB when running.
+    prefs['validate_objectdb'] = True
+
+    # How many undos to hold?
+    prefs['max_history_items'] = 32
+
+    # Shows whether to save history across sessions.
+    prefs['save_history'] = True
+    prefs['compress_history'] = False
+
+    # Set the number spaces used for indenting.  According to
+    # :PEP:`8`, it is best to use 4 spaces.  Since most of rope's
+    # unit-tests use 4 spaces it is more reliable, too.
+    prefs['indent_size'] = 4
+
+    # Builtin and c-extension modules that are allowed to be imported
+    # and inspected by rope.
+    prefs['extension_modules'] = []
+
+    # Add all standard c-extensions to extension_modules list.
+    prefs['import_dynload_stdmods'] = True
+
+    # If `True` modules with syntax errors are considered to be empty.
+    # The default value is `False`; When `False` syntax errors raise
+    # `rope.base.exceptions.ModuleSyntaxError` exception.
+    prefs['ignore_syntax_errors'] = False
+
+    # If `True`, rope ignores unresolvable imports.  Otherwise, they
+    # appear in the importing namespace.
+    prefs['ignore_bad_imports'] = False
+
+    # If `True`, rope will insert new module imports as
+    # `from <package> import <module>` by default.
+    prefs['prefer_module_from_imports'] = False
+
+    # If `True`, rope will transform a comma list of imports into
+    # multiple separate import statements when organizing
+    # imports.
+    prefs['split_imports'] = False
+
+    # If `True`, rope will remove all top-level import statements and
+    # reinsert them at the top of the module when making changes.
+    prefs['pull_imports_to_top'] = True
+
+    # If `True`, rope will sort imports alphabetically by module name instead
+    # of alphabetically by import statement, with from imports after normal
+    # imports.
+    prefs['sort_imports_alphabetically'] = False
+
+    # Location of implementation of
+    # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general
+    # case, you don't have to change this value, unless you're an rope expert.
+    # Change this value to inject you own implementations of interfaces
+    # listed in module rope.base.oi.type_hinting.providers.interfaces
+    # For example, you can add you own providers for Django Models, or disable
+    # the search type-hinting in a class hierarchy, etc.
+    prefs['type_hinting_factory'] = (
+        'rope.base.oi.type_hinting.factory.default_type_hinting_factory')
+
+
+def project_opened(project):
+    """This function is called after opening the project"""
+    # Do whatever you like here!
diff --git a/.vscode/.ropeproject/objectdb b/.vscode/.ropeproject/objectdb
new file mode 100644
index 0000000000000000000000000000000000000000..0a47446c0ad231c193bdd44ff327ba2ab28bf3d8
Binary files /dev/null and b/.vscode/.ropeproject/objectdb differ
diff --git a/.vscode/settings.json b/.vscode/settings.json
index af5ad5b7a0df4f6e1d26951a92f015b4c491b83d..a9f5e278abb6e85f83fd1995e129b0ccb4472326 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,4 @@
 {
-    "python.pythonPath": "d:\\ProjetsGit\\ML9\\venv\\Scripts\\python.exe"
+    "python.pythonPath": "d:\\ProjetsGit\\ML9\\venv\\Scripts\\python.exe",
+    "git.ignoreLimitWarning": true
 }
\ No newline at end of file
diff --git a/__pycache__/features_extractor.cpython-37.pyc b/__pycache__/features_extractor.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1196aa739c171bd81e7dfac4fdc61647d8d68557
Binary files /dev/null and b/__pycache__/features_extractor.cpython-37.pyc differ
diff --git a/data_viz.py b/data_viz.py
new file mode 100644
index 0000000000000000000000000000000000000000..be3ace60ed2c92a6d26cf1ef1109cd0c37b449c2
--- /dev/null
+++ b/data_viz.py
@@ -0,0 +1,13 @@
+import pandas as pd
+import matplotlib.pyplot as plt
+
+csv_paths = ['train.csv', 'train_legacy.csv']
+data_list = []
+for csv_path in csv_paths:
+    data_list += [pd.read_csv(csv_path, index_col=0)]
+
+train_df = pd.concat(data_list, axis=0)
+train_df.fillna('NA', inplace=True)
+
+train_df[['chars_in_subject']].plot()
+plt.show()
\ No newline at end of file
diff --git a/features_extractor.py b/features_extractor.py
new file mode 100644
index 0000000000000000000000000000000000000000..8258824788e8ae76f18582839b84127a8540819d
--- /dev/null
+++ b/features_extractor.py
@@ -0,0 +1,196 @@
+import pandas as pd
+import numpy as np
+import xgboost as xgb
+from copy import copy
+
+from sklearn.preprocessing import OneHotEncoder, MinMaxScaler, StandardScaler
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
+from sklearn.decomposition import LatentDirichletAllocation
+from sklearn.model_selection import cross_val_predict, train_test_split
+from sklearn.cluster import MiniBatchKMeans
+
+
+class FeatureExtractor():
+
+    def __init__(self, csv_paths, test_size=None):
+
+        data_list = []
+        for csv_path in csv_paths:
+            data_list += [pd.read_csv(csv_path, index_col=0)]
+        
+        self.train_df = pd.concat(data_list, axis=0)
+        self.train_df.fillna('NA', inplace=True)
+
+        self.return_test = False
+        if test_size is not None:
+            self.return_test = True
+            self.train_df, self.test_df = train_test_split(self.train_df, test_size=test_size, random_state=42, shuffle=True)
+            self.y_test = np.ravel(self.test_df[['label']])
+        
+        self.y_true = np.ravel(self.train_df[['label']])
+
+        sample_per_class = np.sum(OneHotEncoder(sparse=False).fit_transform(self.train_df[['label']].to_numpy()), axis=0)
+        print(sample_per_class/np.sum(sample_per_class))
+
+    @staticmethod
+    def _timestampToMonthDayHour(dataframe, timestampcolumn):
+
+        def filter(timestamp, filter_type):
+            stamplist = timestamp.split(' ')
+            if len(stamplist) == 8:
+                stamplist = stamplist[:1] + stamplist[2:-1]
+                day, month, hour = stamplist[0][:-1], stamplist[-4], stamplist[-2][:2]
+            if len(stamplist) == 7:
+                stamplist = stamplist[:-1]
+                day, month, hour = stamplist[0][:-1], stamplist[-4], stamplist[-2][:2]
+            elif len(stamplist) == 2:
+                day, month, hour = 'NA', stamplist[0][3:6], stamplist[1][:2]
+            elif len(stamplist) == 5:
+                day, month, hour = 'NA', stamplist[-4], stamplist[-2][:2]
+            elif len(stamplist) == 6:
+                day, month, hour = stamplist[0][:-1], stamplist[-4], stamplist[-2][:2]
+            else:
+                day, month, hour = 'NA', 'NA', 'NA'
+            if day is None or month is None or hour is None:
+                day, month, hour = 'NA', 'NA', 'NA'
+            if filter_type == 'hour':
+                return hour
+            else:
+                return month
+        
+        dataframe['hour'] = timestampcolumn.apply(lambda timestamp: filter(timestamp, 'hour'))
+        dataframe['month'] = timestampcolumn.apply(lambda timestamp: filter(timestamp, 'month'))
+    
+    def extract_features(self, true_test_path, simple_categorical_variables=[], complex_categorical_variables=[], numerical_variables=[], numerical_variables_to_clusterise=[], time_variable=None, specific_class=None):
+
+        true_test_df = pd.read_csv(true_test_path, index_col=0)
+        true_test_df.fillna('NA', inplace=True)
+
+        x_train_list = []
+        x_true_test_list = []
+        features_labels = []
+
+        if len(simple_categorical_variables) > 0:
+            train_x_simple_categorical = self.train_df[simple_categorical_variables].to_numpy()
+            true_test_x_simple_categorical = true_test_df[simple_categorical_variables].to_numpy()
+
+            feat_enc_categorical = OneHotEncoder(handle_unknown='ignore', sparse=False)
+
+            train_x_simple_categorical = feat_enc_categorical.fit_transform(train_x_simple_categorical)
+            true_test_x_simple_categorical = feat_enc_categorical.transform(true_test_x_simple_categorical)
+
+            x_train_list.append(train_x_simple_categorical)
+            x_true_test_list.append(true_test_x_simple_categorical)
+
+            n_values = [2]*len(simple_categorical_variables)
+            variable_repetitions = [[simple_categorical_variables[i]]*n_values[i] for i in range(len(simple_categorical_variables))]
+            for variable_repetition in variable_repetitions:
+                features_labels += variable_repetition
+        
+        if specific_class is not None:
+            self.y_true = np.ravel(1-(self.train_df[['label']]==specific_class))
+        
+        if time_variable is not None:
+            self._timestampToMonthDayHour(self.train_df, self.train_df[time_variable])
+            self._timestampToMonthDayHour(true_test_df, true_test_df[time_variable])
+            complex_categorical_variables += ['hour']
+            complex_categorical_variables += ['month']
+
+
+        if len(complex_categorical_variables) > 0:
+            features_encoders = {}
+            ldas = {}
+            for variable in complex_categorical_variables:
+                train_x_var = self.train_df[[variable]].to_numpy()
+                true_test_x_var = true_test_df[[variable]].to_numpy()
+
+                feat_enc = OneHotEncoder(handle_unknown='ignore', sparse=False)
+                train_x_var = feat_enc.fit_transform(train_x_var)
+                true_test_x_var = feat_enc.transform(true_test_x_var)
+                features_encoders[variable] = copy(feat_enc)
+
+                lda = LinearDiscriminantAnalysis()
+                # lda = LatentDirichletAllocation(n_components=4)
+                train_x_var = lda.fit_transform(train_x_var, self.y_true)
+                true_test_x_var = lda.transform(true_test_x_var)
+                ldas[variable] = copy(lda)
+
+                x_train_list.append(train_x_var)
+                x_true_test_list.append(true_test_x_var)
+                features_labels += [variable]*train_x_var.shape[1]
+        
+        if len(numerical_variables) > 0:
+            features_encoders_num = {}
+            clusters = {}
+            for variable in numerical_variables:
+                train_x_numerical = self.train_df[[variable]].to_numpy()
+                true_test_x_var = true_test_df[[variable]].to_numpy()
+
+                feat_enc_numerical = StandardScaler()
+                train_x_numerical = feat_enc_numerical.fit_transform(train_x_numerical)
+                true_test_x_var = feat_enc_numerical.transform(true_test_x_var)
+                features_encoders_num[variable] = copy(feat_enc_numerical)
+
+                x_train_list.append(train_x_numerical)
+                x_true_test_list.append(true_test_x_var)
+
+                if variable in numerical_variables_to_clusterise:
+                    cluster = MiniBatchKMeans(n_clusters=4, max_iter=100, batch_size=100)
+                    train_x_numerical = cluster.fit_transform(train_x_numerical)
+                    true_test_x_var = cluster.transform(true_test_x_var)
+                    clusters[variable] = copy(cluster)
+
+                    x_train_list.append(train_x_numerical)
+                    x_true_test_list.append(true_test_x_var)
+
+                features_labels += numerical_variables
+
+        X_train = np.concatenate(x_train_list, axis=1)
+        print('n_features: {}'.format(X_train.shape))
+        Y_train = self.y_true
+
+        X_true_test = np.concatenate(x_true_test_list, axis=1)
+
+        if self.return_test:
+            x_test_list = []
+            if len(simple_categorical_variables) > 0:
+
+                test_x_simple_categorical = self.test_df[simple_categorical_variables].to_numpy()
+                test_x_simple_categorical = feat_enc_categorical.transform(test_x_simple_categorical)
+                x_test_list.append(test_x_simple_categorical)
+
+            if specific_class is not None:
+                self.y_test = np.ravel(1-(self.test_df[['label']]==specific_class))
+            
+            if time_variable is not None:
+                self._timestampToMonthDayHour(self.test_df, self.test_df[time_variable])
+
+            if len(complex_categorical_variables) > 0:
+
+                for variable in complex_categorical_variables:
+
+                    test_x_var = self.test_df[[variable]].to_numpy()
+                    test_x_var = features_encoders[variable].transform(test_x_var)
+                    test_x_var = ldas[variable].transform(test_x_var)
+
+                    x_test_list.append(test_x_var)
+
+            if len(numerical_variables) > 0:
+
+                for variable in numerical_variables:
+                    test_x_var = self.test_df[[variable]].to_numpy()
+                    test_x_var = features_encoders_num[variable].transform(test_x_var)
+
+                    x_test_list.append(test_x_var)
+
+                    if variable in numerical_variables_to_clusterise:
+                        test_x_var = clusters[variable].transform(test_x_var)
+                        x_test_list.append(test_x_var)
+            
+            X_test = np.concatenate(x_test_list, axis=1)
+            Y_test = self.y_test
+        
+            return X_train, Y_train, X_test, Y_test, X_true_test
+        
+        return X_train, Y_train, X_true_test
+
diff --git a/med_sample_submission.csv b/med_sample_submission.csv
new file mode 100644
index 0000000000000000000000000000000000000000..a32fe5d9418fc87648bd5e7067d7b1f3ee39b49b
--- /dev/null
+++ b/med_sample_submission.csv
@@ -0,0 +1,10746 @@
+Id,label
+0,2
+1,0
+2,0
+3,3
+4,0
+5,0
+6,0
+7,2
+8,2
+9,0
+10,2
+11,0
+12,0
+13,0
+14,3
+15,2
+16,1
+17,0
+18,1
+19,1
+20,0
+21,0
+22,1
+23,0
+24,3
+25,3
+26,1
+27,0
+28,1
+29,2
+30,0
+31,1
+32,0
+33,3
+34,0
+35,0
+36,0
+37,2
+38,3
+39,0
+40,0
+41,1
+42,0
+43,0
+44,1
+45,0
+46,3
+47,3
+48,3
+49,3
+50,2
+51,0
+52,3
+53,2
+54,0
+55,0
+56,3
+57,2
+58,1
+59,3
+60,0
+61,3
+62,2
+63,3
+64,3
+65,0
+66,3
+67,0
+68,0
+69,0
+70,1
+71,0
+72,2
+73,2
+74,3
+75,2
+76,0
+77,2
+78,2
+79,2
+80,1
+81,0
+82,0
+83,0
+84,2
+85,0
+86,2
+87,0
+88,2
+89,2
+90,3
+91,3
+92,3
+93,3
+94,0
+95,0
+96,0
+97,0
+98,2
+99,0
+100,2
+101,2
+102,2
+103,0
+104,3
+105,0
+106,2
+107,0
+108,0
+109,0
+110,1
+111,0
+112,0
+113,3
+114,1
+115,3
+116,2
+117,2
+118,3
+119,0
+120,3
+121,2
+122,0
+123,0
+124,3
+125,1
+126,3
+127,0
+128,1
+129,1
+130,0
+131,1
+132,2
+133,0
+134,1
+135,1
+136,3
+137,0
+138,0
+139,0
+140,0
+141,2
+142,0
+143,2
+144,2
+145,1
+146,2
+147,0
+148,0
+149,3
+150,2
+151,3
+152,3
+153,0
+154,2
+155,3
+156,3
+157,2
+158,0
+159,1
+160,1
+161,1
+162,2
+163,3
+164,0
+165,0
+166,0
+167,0
+168,0
+169,0
+170,0
+171,0
+172,0
+173,3
+174,0
+175,0
+176,0
+177,3
+178,3
+179,0
+180,3
+181,0
+182,3
+183,0
+184,0
+185,2
+186,0
+187,3
+188,0
+189,3
+190,2
+191,1
+192,0
+193,0
+194,3
+195,1
+196,3
+197,0
+198,3
+199,3
+200,1
+201,0
+202,0
+203,3
+204,0
+205,3
+206,2
+207,0
+208,2
+209,0
+210,0
+211,3
+212,3
+213,3
+214,3
+215,3
+216,3
+217,2
+218,3
+219,2
+220,0
+221,0
+222,2
+223,0
+224,3
+225,2
+226,1
+227,3
+228,0
+229,0
+230,3
+231,0
+232,0
+233,2
+234,2
+235,1
+236,0
+237,3
+238,0
+239,0
+240,0
+241,0
+242,2
+243,0
+244,0
+245,0
+246,2
+247,0
+248,0
+249,0
+250,0
+251,0
+252,0
+253,0
+254,0
+255,0
+256,3
+257,0
+258,0
+259,2
+260,0
+261,0
+262,2
+263,2
+264,0
+265,0
+266,2
+267,3
+268,2
+269,2
+270,0
+271,0
+272,0
+273,0
+274,0
+275,0
+276,3
+277,0
+278,3
+279,0
+280,1
+281,1
+282,0
+283,0
+284,2
+285,3
+286,3
+287,0
+288,0
+289,2
+290,2
+291,0
+292,3
+293,0
+294,2
+295,0
+296,2
+297,3
+298,0
+299,1
+300,1
+301,0
+302,3
+303,1
+304,0
+305,2
+306,0
+307,0
+308,0
+309,0
+310,0
+311,2
+312,2
+313,2
+314,1
+315,0
+316,1
+317,2
+318,0
+319,0
+320,3
+321,1
+322,3
+323,0
+324,3
+325,2
+326,2
+327,2
+328,3
+329,2
+330,0
+331,0
+332,3
+333,1
+334,0
+335,0
+336,2
+337,1
+338,1
+339,0
+340,0
+341,0
+342,1
+343,0
+344,0
+345,0
+346,0
+347,0
+348,3
+349,3
+350,0
+351,3
+352,1
+353,1
+354,1
+355,0
+356,2
+357,2
+358,0
+359,0
+360,0
+361,3
+362,0
+363,1
+364,3
+365,0
+366,3
+367,1
+368,0
+369,3
+370,3
+371,0
+372,2
+373,0
+374,1
+375,3
+376,0
+377,3
+378,0
+379,3
+380,0
+381,0
+382,1
+383,0
+384,3
+385,1
+386,2
+387,1
+388,1
+389,0
+390,2
+391,3
+392,2
+393,3
+394,0
+395,2
+396,0
+397,0
+398,0
+399,3
+400,0
+401,2
+402,1
+403,1
+404,0
+405,3
+406,0
+407,0
+408,0
+409,1
+410,2
+411,0
+412,3
+413,0
+414,3
+415,3
+416,3
+417,0
+418,3
+419,0
+420,0
+421,2
+422,2
+423,1
+424,3
+425,0
+426,1
+427,2
+428,2
+429,3
+430,3
+431,2
+432,2
+433,1
+434,1
+435,2
+436,0
+437,2
+438,3
+439,0
+440,3
+441,2
+442,2
+443,2
+444,0
+445,2
+446,2
+447,3
+448,0
+449,0
+450,1
+451,2
+452,3
+453,0
+454,1
+455,1
+456,0
+457,0
+458,1
+459,3
+460,0
+461,0
+462,3
+463,0
+464,3
+465,2
+466,0
+467,3
+468,0
+469,0
+470,2
+471,2
+472,0
+473,0
+474,1
+475,1
+476,0
+477,3
+478,2
+479,2
+480,0
+481,0
+482,0
+483,2
+484,3
+485,3
+486,0
+487,0
+488,3
+489,1
+490,0
+491,0
+492,3
+493,3
+494,0
+495,3
+496,0
+497,2
+498,2
+499,0
+500,3
+501,0
+502,3
+503,2
+504,3
+505,0
+506,0
+507,2
+508,0
+509,0
+510,0
+511,0
+512,3
+513,0
+514,3
+515,0
+516,0
+517,3
+518,3
+519,0
+520,0
+521,0
+522,0
+523,3
+524,2
+525,0
+526,3
+527,0
+528,0
+529,0
+530,0
+531,1
+532,0
+533,0
+534,0
+535,0
+536,2
+537,3
+538,1
+539,0
+540,1
+541,3
+542,0
+543,3
+544,0
+545,2
+546,0
+547,3
+548,0
+549,3
+550,0
+551,0
+552,3
+553,0
+554,0
+555,0
+556,1
+557,0
+558,1
+559,0
+560,0
+561,2
+562,3
+563,0
+564,0
+565,0
+566,2
+567,2
+568,0
+569,3
+570,1
+571,0
+572,3
+573,0
+574,0
+575,0
+576,0
+577,3
+578,3
+579,0
+580,0
+581,0
+582,0
+583,0
+584,0
+585,3
+586,0
+587,0
+588,0
+589,1
+590,2
+591,0
+592,0
+593,2
+594,0
+595,3
+596,0
+597,1
+598,0
+599,3
+600,3
+601,0
+602,0
+603,0
+604,2
+605,0
+606,1
+607,1
+608,1
+609,1
+610,2
+611,0
+612,2
+613,0
+614,1
+615,2
+616,2
+617,0
+618,2
+619,0
+620,0
+621,2
+622,2
+623,1
+624,0
+625,0
+626,2
+627,0
+628,3
+629,3
+630,3
+631,2
+632,0
+633,1
+634,0
+635,2
+636,0
+637,3
+638,3
+639,0
+640,0
+641,2
+642,0
+643,0
+644,0
+645,3
+646,0
+647,2
+648,1
+649,1
+650,0
+651,3
+652,1
+653,0
+654,2
+655,0
+656,0
+657,2
+658,0
+659,0
+660,0
+661,0
+662,3
+663,3
+664,1
+665,3
+666,3
+667,1
+668,2
+669,0
+670,2
+671,2
+672,3
+673,3
+674,0
+675,0
+676,3
+677,0
+678,3
+679,0
+680,2
+681,0
+682,1
+683,1
+684,3
+685,1
+686,3
+687,0
+688,1
+689,3
+690,1
+691,0
+692,0
+693,0
+694,2
+695,3
+696,0
+697,0
+698,1
+699,0
+700,0
+701,0
+702,2
+703,0
+704,0
+705,1
+706,0
+707,2
+708,2
+709,0
+710,0
+711,1
+712,0
+713,0
+714,3
+715,1
+716,0
+717,0
+718,0
+719,2
+720,3
+721,1
+722,2
+723,2
+724,2
+725,0
+726,0
+727,0
+728,3
+729,0
+730,0
+731,3
+732,2
+733,2
+734,1
+735,2
+736,0
+737,0
+738,0
+739,3
+740,0
+741,0
+742,0
+743,1
+744,0
+745,0
+746,1
+747,3
+748,3
+749,2
+750,3
+751,3
+752,0
+753,0
+754,3
+755,3
+756,3
+757,2
+758,2
+759,1
+760,3
+761,3
+762,0
+763,1
+764,3
+765,3
+766,3
+767,0
+768,0
+769,3
+770,2
+771,0
+772,0
+773,1
+774,0
+775,0
+776,0
+777,0
+778,0
+779,0
+780,3
+781,0
+782,0
+783,1
+784,3
+785,0
+786,0
+787,2
+788,0
+789,0
+790,1
+791,3
+792,2
+793,1
+794,3
+795,2
+796,2
+797,1
+798,3
+799,0
+800,0
+801,2
+802,2
+803,2
+804,3
+805,0
+806,0
+807,2
+808,2
+809,2
+810,2
+811,1
+812,1
+813,0
+814,2
+815,2
+816,3
+817,3
+818,3
+819,1
+820,1
+821,2
+822,1
+823,0
+824,0
+825,0
+826,0
+827,3
+828,1
+829,1
+830,3
+831,2
+832,1
+833,0
+834,0
+835,0
+836,3
+837,0
+838,3
+839,3
+840,1
+841,0
+842,2
+843,0
+844,0
+845,0
+846,1
+847,0
+848,3
+849,0
+850,0
+851,0
+852,0
+853,2
+854,0
+855,2
+856,0
+857,3
+858,1
+859,0
+860,0
+861,1
+862,3
+863,1
+864,1
+865,0
+866,2
+867,1
+868,3
+869,1
+870,2
+871,3
+872,3
+873,0
+874,0
+875,1
+876,3
+877,0
+878,0
+879,1
+880,3
+881,0
+882,3
+883,1
+884,1
+885,2
+886,0
+887,0
+888,0
+889,0
+890,0
+891,2
+892,0
+893,0
+894,0
+895,0
+896,2
+897,2
+898,2
+899,0
+900,0
+901,1
+902,0
+903,3
+904,2
+905,2
+906,2
+907,2
+908,0
+909,3
+910,0
+911,2
+912,1
+913,1
+914,2
+915,0
+916,2
+917,0
+918,3
+919,0
+920,0
+921,2
+922,0
+923,3
+924,0
+925,1
+926,0
+927,0
+928,3
+929,0
+930,2
+931,3
+932,1
+933,0
+934,3
+935,0
+936,3
+937,2
+938,3
+939,2
+940,0
+941,3
+942,0
+943,0
+944,0
+945,3
+946,3
+947,0
+948,2
+949,0
+950,0
+951,0
+952,1
+953,1
+954,0
+955,0
+956,3
+957,3
+958,2
+959,0
+960,1
+961,3
+962,0
+963,3
+964,0
+965,0
+966,0
+967,0
+968,2
+969,2
+970,2
+971,0
+972,0
+973,2
+974,1
+975,0
+976,1
+977,2
+978,2
+979,2
+980,3
+981,3
+982,3
+983,0
+984,3
+985,1
+986,0
+987,0
+988,0
+989,2
+990,1
+991,0
+992,0
+993,0
+994,3
+995,2
+996,3
+997,2
+998,0
+999,1
+1000,0
+1001,0
+1002,0
+1003,2
+1004,0
+1005,2
+1006,2
+1007,0
+1008,2
+1009,2
+1010,3
+1011,3
+1012,3
+1013,0
+1014,1
+1015,0
+1016,2
+1017,1
+1018,3
+1019,2
+1020,3
+1021,3
+1022,0
+1023,0
+1024,0
+1025,1
+1026,3
+1027,3
+1028,0
+1029,0
+1030,0
+1031,0
+1032,1
+1033,2
+1034,0
+1035,0
+1036,3
+1037,0
+1038,1
+1039,1
+1040,0
+1041,2
+1042,3
+1043,1
+1044,3
+1045,3
+1046,3
+1047,1
+1048,1
+1049,1
+1050,1
+1051,2
+1052,2
+1053,0
+1054,1
+1055,0
+1056,3
+1057,2
+1058,0
+1059,0
+1060,0
+1061,0
+1062,0
+1063,1
+1064,0
+1065,3
+1066,1
+1067,2
+1068,3
+1069,0
+1070,0
+1071,0
+1072,1
+1073,0
+1074,2
+1075,2
+1076,0
+1077,2
+1078,3
+1079,0
+1080,0
+1081,0
+1082,0
+1083,2
+1084,1
+1085,2
+1086,2
+1087,3
+1088,0
+1089,2
+1090,1
+1091,0
+1092,3
+1093,0
+1094,2
+1095,0
+1096,0
+1097,0
+1098,1
+1099,0
+1100,3
+1101,0
+1102,3
+1103,1
+1104,1
+1105,0
+1106,2
+1107,3
+1108,2
+1109,3
+1110,1
+1111,3
+1112,0
+1113,0
+1114,0
+1115,0
+1116,0
+1117,3
+1118,0
+1119,3
+1120,1
+1121,0
+1122,0
+1123,2
+1124,2
+1125,0
+1126,0
+1127,1
+1128,1
+1129,0
+1130,0
+1131,1
+1132,0
+1133,2
+1134,3
+1135,0
+1136,0
+1137,3
+1138,3
+1139,1
+1140,3
+1141,0
+1142,0
+1143,0
+1144,3
+1145,0
+1146,3
+1147,0
+1148,0
+1149,1
+1150,0
+1151,2
+1152,0
+1153,3
+1154,0
+1155,3
+1156,0
+1157,3
+1158,0
+1159,0
+1160,1
+1161,3
+1162,1
+1163,0
+1164,2
+1165,2
+1166,1
+1167,3
+1168,2
+1169,3
+1170,0
+1171,0
+1172,0
+1173,1
+1174,2
+1175,2
+1176,0
+1177,0
+1178,0
+1179,1
+1180,1
+1181,2
+1182,1
+1183,0
+1184,0
+1185,3
+1186,2
+1187,3
+1188,0
+1189,1
+1190,2
+1191,0
+1192,0
+1193,0
+1194,0
+1195,0
+1196,2
+1197,0
+1198,0
+1199,3
+1200,3
+1201,0
+1202,0
+1203,0
+1204,0
+1205,2
+1206,0
+1207,2
+1208,2
+1209,1
+1210,2
+1211,2
+1212,0
+1213,3
+1214,1
+1215,0
+1216,0
+1217,0
+1218,0
+1219,0
+1220,3
+1221,3
+1222,0
+1223,3
+1224,2
+1225,0
+1226,2
+1227,0
+1228,3
+1229,1
+1230,1
+1231,1
+1232,1
+1233,2
+1234,1
+1235,2
+1236,3
+1237,0
+1238,2
+1239,0
+1240,0
+1241,3
+1242,1
+1243,1
+1244,3
+1245,3
+1246,0
+1247,3
+1248,0
+1249,0
+1250,3
+1251,0
+1252,0
+1253,1
+1254,0
+1255,3
+1256,0
+1257,1
+1258,0
+1259,0
+1260,1
+1261,0
+1262,1
+1263,2
+1264,2
+1265,0
+1266,0
+1267,3
+1268,2
+1269,2
+1270,0
+1271,3
+1272,0
+1273,2
+1274,0
+1275,1
+1276,0
+1277,0
+1278,0
+1279,3
+1280,3
+1281,0
+1282,3
+1283,0
+1284,2
+1285,3
+1286,3
+1287,0
+1288,0
+1289,3
+1290,0
+1291,0
+1292,0
+1293,3
+1294,2
+1295,3
+1296,0
+1297,0
+1298,2
+1299,0
+1300,2
+1301,2
+1302,2
+1303,0
+1304,3
+1305,3
+1306,2
+1307,0
+1308,0
+1309,0
+1310,1
+1311,3
+1312,3
+1313,1
+1314,2
+1315,2
+1316,0
+1317,0
+1318,1
+1319,3
+1320,1
+1321,3
+1322,0
+1323,0
+1324,2
+1325,0
+1326,0
+1327,2
+1328,0
+1329,0
+1330,0
+1331,0
+1332,0
+1333,3
+1334,3
+1335,2
+1336,0
+1337,3
+1338,0
+1339,3
+1340,0
+1341,0
+1342,0
+1343,0
+1344,0
+1345,0
+1346,1
+1347,0
+1348,0
+1349,2
+1350,1
+1351,0
+1352,0
+1353,1
+1354,2
+1355,0
+1356,2
+1357,3
+1358,2
+1359,0
+1360,3
+1361,3
+1362,0
+1363,0
+1364,0
+1365,0
+1366,3
+1367,2
+1368,0
+1369,0
+1370,2
+1371,0
+1372,0
+1373,0
+1374,2
+1375,2
+1376,0
+1377,1
+1378,0
+1379,0
+1380,2
+1381,0
+1382,0
+1383,0
+1384,3
+1385,2
+1386,3
+1387,1
+1388,1
+1389,0
+1390,0
+1391,3
+1392,1
+1393,2
+1394,3
+1395,0
+1396,3
+1397,0
+1398,0
+1399,0
+1400,0
+1401,0
+1402,0
+1403,2
+1404,0
+1405,3
+1406,3
+1407,2
+1408,0
+1409,0
+1410,0
+1411,1
+1412,0
+1413,0
+1414,0
+1415,0
+1416,1
+1417,0
+1418,0
+1419,0
+1420,0
+1421,0
+1422,2
+1423,0
+1424,1
+1425,3
+1426,3
+1427,0
+1428,0
+1429,0
+1430,0
+1431,0
+1432,3
+1433,1
+1434,3
+1435,0
+1436,0
+1437,3
+1438,1
+1439,2
+1440,1
+1441,2
+1442,0
+1443,0
+1444,0
+1445,3
+1446,0
+1447,0
+1448,2
+1449,2
+1450,3
+1451,0
+1452,3
+1453,3
+1454,3
+1455,1
+1456,0
+1457,0
+1458,0
+1459,3
+1460,0
+1461,0
+1462,2
+1463,3
+1464,3
+1465,1
+1466,0
+1467,3
+1468,0
+1469,0
+1470,0
+1471,1
+1472,0
+1473,0
+1474,3
+1475,0
+1476,1
+1477,0
+1478,3
+1479,3
+1480,0
+1481,1
+1482,3
+1483,1
+1484,3
+1485,0
+1486,1
+1487,0
+1488,3
+1489,0
+1490,0
+1491,0
+1492,1
+1493,3
+1494,0
+1495,1
+1496,2
+1497,3
+1498,0
+1499,0
+1500,0
+1501,0
+1502,3
+1503,0
+1504,0
+1505,1
+1506,2
+1507,0
+1508,2
+1509,3
+1510,2
+1511,3
+1512,0
+1513,3
+1514,3
+1515,2
+1516,3
+1517,3
+1518,2
+1519,3
+1520,2
+1521,3
+1522,0
+1523,0
+1524,1
+1525,0
+1526,1
+1527,1
+1528,1
+1529,0
+1530,3
+1531,1
+1532,3
+1533,3
+1534,3
+1535,2
+1536,0
+1537,1
+1538,2
+1539,0
+1540,0
+1541,0
+1542,1
+1543,0
+1544,0
+1545,1
+1546,1
+1547,1
+1548,2
+1549,2
+1550,2
+1551,0
+1552,1
+1553,0
+1554,0
+1555,3
+1556,0
+1557,2
+1558,1
+1559,0
+1560,0
+1561,2
+1562,0
+1563,0
+1564,2
+1565,3
+1566,0
+1567,3
+1568,0
+1569,0
+1570,3
+1571,3
+1572,3
+1573,0
+1574,2
+1575,1
+1576,3
+1577,1
+1578,1
+1579,0
+1580,1
+1581,2
+1582,0
+1583,1
+1584,0
+1585,0
+1586,0
+1587,0
+1588,0
+1589,0
+1590,0
+1591,3
+1592,2
+1593,2
+1594,0
+1595,0
+1596,0
+1597,3
+1598,3
+1599,0
+1600,1
+1601,1
+1602,0
+1603,0
+1604,3
+1605,0
+1606,2
+1607,0
+1608,1
+1609,1
+1610,2
+1611,3
+1612,0
+1613,0
+1614,0
+1615,0
+1616,2
+1617,3
+1618,3
+1619,0
+1620,2
+1621,3
+1622,3
+1623,1
+1624,0
+1625,3
+1626,2
+1627,0
+1628,0
+1629,3
+1630,3
+1631,0
+1632,2
+1633,0
+1634,0
+1635,1
+1636,2
+1637,3
+1638,1
+1639,0
+1640,0
+1641,0
+1642,3
+1643,1
+1644,0
+1645,0
+1646,2
+1647,3
+1648,0
+1649,2
+1650,3
+1651,1
+1652,1
+1653,3
+1654,1
+1655,2
+1656,0
+1657,1
+1658,0
+1659,1
+1660,0
+1661,3
+1662,2
+1663,0
+1664,1
+1665,2
+1666,0
+1667,3
+1668,2
+1669,0
+1670,3
+1671,2
+1672,0
+1673,0
+1674,2
+1675,0
+1676,0
+1677,3
+1678,1
+1679,1
+1680,3
+1681,2
+1682,3
+1683,0
+1684,2
+1685,2
+1686,0
+1687,2
+1688,0
+1689,0
+1690,1
+1691,3
+1692,0
+1693,3
+1694,1
+1695,3
+1696,3
+1697,0
+1698,0
+1699,0
+1700,0
+1701,0
+1702,1
+1703,0
+1704,1
+1705,0
+1706,1
+1707,0
+1708,2
+1709,0
+1710,3
+1711,2
+1712,0
+1713,2
+1714,0
+1715,1
+1716,0
+1717,0
+1718,3
+1719,0
+1720,1
+1721,3
+1722,2
+1723,3
+1724,0
+1725,1
+1726,1
+1727,1
+1728,0
+1729,0
+1730,2
+1731,0
+1732,1
+1733,1
+1734,3
+1735,0
+1736,3
+1737,0
+1738,2
+1739,0
+1740,0
+1741,2
+1742,3
+1743,1
+1744,2
+1745,1
+1746,3
+1747,1
+1748,0
+1749,0
+1750,0
+1751,0
+1752,2
+1753,0
+1754,0
+1755,2
+1756,0
+1757,3
+1758,3
+1759,1
+1760,0
+1761,0
+1762,0
+1763,3
+1764,0
+1765,0
+1766,3
+1767,1
+1768,0
+1769,1
+1770,3
+1771,3
+1772,2
+1773,3
+1774,1
+1775,2
+1776,1
+1777,3
+1778,0
+1779,0
+1780,1
+1781,3
+1782,0
+1783,0
+1784,0
+1785,0
+1786,0
+1787,2
+1788,0
+1789,1
+1790,2
+1791,0
+1792,2
+1793,0
+1794,2
+1795,0
+1796,3
+1797,0
+1798,1
+1799,0
+1800,2
+1801,2
+1802,0
+1803,0
+1804,3
+1805,0
+1806,3
+1807,1
+1808,3
+1809,0
+1810,1
+1811,0
+1812,3
+1813,2
+1814,0
+1815,1
+1816,3
+1817,0
+1818,0
+1819,2
+1820,3
+1821,0
+1822,0
+1823,0
+1824,0
+1825,0
+1826,2
+1827,1
+1828,0
+1829,2
+1830,0
+1831,3
+1832,2
+1833,2
+1834,2
+1835,0
+1836,2
+1837,0
+1838,0
+1839,0
+1840,0
+1841,0
+1842,0
+1843,0
+1844,3
+1845,2
+1846,1
+1847,1
+1848,0
+1849,1
+1850,2
+1851,3
+1852,3
+1853,0
+1854,0
+1855,2
+1856,0
+1857,0
+1858,3
+1859,1
+1860,0
+1861,1
+1862,2
+1863,0
+1864,1
+1865,0
+1866,0
+1867,1
+1868,0
+1869,0
+1870,0
+1871,2
+1872,2
+1873,1
+1874,0
+1875,3
+1876,0
+1877,3
+1878,0
+1879,2
+1880,0
+1881,1
+1882,2
+1883,0
+1884,3
+1885,0
+1886,2
+1887,0
+1888,0
+1889,1
+1890,0
+1891,2
+1892,2
+1893,0
+1894,0
+1895,1
+1896,0
+1897,0
+1898,2
+1899,0
+1900,0
+1901,3
+1902,2
+1903,2
+1904,2
+1905,0
+1906,0
+1907,1
+1908,0
+1909,3
+1910,0
+1911,2
+1912,0
+1913,1
+1914,0
+1915,2
+1916,0
+1917,0
+1918,0
+1919,0
+1920,1
+1921,3
+1922,0
+1923,3
+1924,3
+1925,1
+1926,0
+1927,0
+1928,0
+1929,2
+1930,2
+1931,0
+1932,0
+1933,0
+1934,1
+1935,1
+1936,0
+1937,3
+1938,1
+1939,3
+1940,1
+1941,0
+1942,2
+1943,2
+1944,0
+1945,0
+1946,1
+1947,1
+1948,1
+1949,0
+1950,0
+1951,0
+1952,0
+1953,0
+1954,0
+1955,0
+1956,1
+1957,2
+1958,3
+1959,3
+1960,0
+1961,1
+1962,2
+1963,2
+1964,3
+1965,0
+1966,2
+1967,2
+1968,3
+1969,0
+1970,1
+1971,0
+1972,0
+1973,0
+1974,3
+1975,2
+1976,0
+1977,3
+1978,1
+1979,0
+1980,2
+1981,1
+1982,0
+1983,0
+1984,1
+1985,0
+1986,2
+1987,0
+1988,3
+1989,0
+1990,0
+1991,3
+1992,0
+1993,2
+1994,0
+1995,0
+1996,3
+1997,2
+1998,2
+1999,0
+2000,0
+2001,0
+2002,0
+2003,0
+2004,1
+2005,0
+2006,0
+2007,2
+2008,0
+2009,3
+2010,0
+2011,1
+2012,1
+2013,0
+2014,1
+2015,0
+2016,3
+2017,0
+2018,0
+2019,2
+2020,2
+2021,2
+2022,0
+2023,3
+2024,1
+2025,0
+2026,0
+2027,0
+2028,0
+2029,3
+2030,2
+2031,0
+2032,2
+2033,0
+2034,3
+2035,0
+2036,0
+2037,2
+2038,0
+2039,0
+2040,2
+2041,0
+2042,0
+2043,0
+2044,2
+2045,0
+2046,3
+2047,0
+2048,0
+2049,2
+2050,0
+2051,0
+2052,3
+2053,0
+2054,0
+2055,2
+2056,0
+2057,1
+2058,1
+2059,0
+2060,0
+2061,3
+2062,2
+2063,0
+2064,0
+2065,0
+2066,2
+2067,0
+2068,0
+2069,0
+2070,2
+2071,3
+2072,0
+2073,1
+2074,0
+2075,0
+2076,0
+2077,3
+2078,0
+2079,1
+2080,0
+2081,1
+2082,3
+2083,0
+2084,0
+2085,3
+2086,3
+2087,0
+2088,0
+2089,3
+2090,1
+2091,3
+2092,2
+2093,2
+2094,2
+2095,1
+2096,0
+2097,3
+2098,0
+2099,1
+2100,0
+2101,0
+2102,1
+2103,1
+2104,2
+2105,0
+2106,0
+2107,2
+2108,0
+2109,2
+2110,2
+2111,0
+2112,1
+2113,0
+2114,0
+2115,1
+2116,2
+2117,1
+2118,0
+2119,2
+2120,2
+2121,0
+2122,0
+2123,0
+2124,0
+2125,0
+2126,0
+2127,0
+2128,0
+2129,3
+2130,3
+2131,1
+2132,0
+2133,1
+2134,2
+2135,0
+2136,1
+2137,0
+2138,0
+2139,2
+2140,3
+2141,3
+2142,0
+2143,0
+2144,0
+2145,3
+2146,0
+2147,0
+2148,3
+2149,3
+2150,2
+2151,1
+2152,1
+2153,0
+2154,2
+2155,0
+2156,2
+2157,2
+2158,2
+2159,1
+2160,0
+2161,2
+2162,0
+2163,3
+2164,3
+2165,3
+2166,1
+2167,3
+2168,0
+2169,1
+2170,3
+2171,3
+2172,2
+2173,0
+2174,0
+2175,0
+2176,3
+2177,2
+2178,0
+2179,0
+2180,0
+2181,0
+2182,3
+2183,1
+2184,0
+2185,1
+2186,0
+2187,1
+2188,3
+2189,1
+2190,0
+2191,1
+2192,3
+2193,3
+2194,1
+2195,1
+2196,3
+2197,3
+2198,2
+2199,2
+2200,1
+2201,0
+2202,1
+2203,3
+2204,0
+2205,3
+2206,1
+2207,0
+2208,0
+2209,3
+2210,0
+2211,3
+2212,0
+2213,3
+2214,1
+2215,0
+2216,2
+2217,0
+2218,0
+2219,2
+2220,0
+2221,3
+2222,2
+2223,0
+2224,0
+2225,2
+2226,0
+2227,0
+2228,1
+2229,0
+2230,2
+2231,0
+2232,0
+2233,3
+2234,0
+2235,0
+2236,0
+2237,0
+2238,2
+2239,0
+2240,1
+2241,1
+2242,0
+2243,0
+2244,0
+2245,2
+2246,0
+2247,2
+2248,3
+2249,0
+2250,2
+2251,0
+2252,0
+2253,0
+2254,0
+2255,3
+2256,1
+2257,0
+2258,3
+2259,0
+2260,1
+2261,3
+2262,3
+2263,2
+2264,1
+2265,2
+2266,2
+2267,2
+2268,0
+2269,2
+2270,3
+2271,0
+2272,3
+2273,3
+2274,1
+2275,0
+2276,3
+2277,0
+2278,0
+2279,2
+2280,3
+2281,0
+2282,0
+2283,1
+2284,0
+2285,2
+2286,3
+2287,2
+2288,3
+2289,2
+2290,0
+2291,0
+2292,0
+2293,3
+2294,3
+2295,0
+2296,2
+2297,0
+2298,3
+2299,0
+2300,0
+2301,3
+2302,0
+2303,0
+2304,0
+2305,3
+2306,1
+2307,0
+2308,0
+2309,1
+2310,2
+2311,0
+2312,0
+2313,1
+2314,2
+2315,2
+2316,0
+2317,2
+2318,3
+2319,0
+2320,2
+2321,0
+2322,0
+2323,0
+2324,3
+2325,1
+2326,3
+2327,0
+2328,0
+2329,3
+2330,2
+2331,0
+2332,1
+2333,0
+2334,3
+2335,1
+2336,0
+2337,3
+2338,0
+2339,1
+2340,0
+2341,3
+2342,0
+2343,0
+2344,0
+2345,1
+2346,1
+2347,3
+2348,0
+2349,0
+2350,0
+2351,0
+2352,0
+2353,2
+2354,3
+2355,3
+2356,3
+2357,1
+2358,0
+2359,0
+2360,2
+2361,0
+2362,3
+2363,2
+2364,2
+2365,3
+2366,3
+2367,3
+2368,0
+2369,0
+2370,3
+2371,1
+2372,0
+2373,0
+2374,1
+2375,1
+2376,3
+2377,0
+2378,1
+2379,1
+2380,2
+2381,2
+2382,2
+2383,0
+2384,1
+2385,3
+2386,0
+2387,1
+2388,3
+2389,3
+2390,0
+2391,3
+2392,0
+2393,2
+2394,3
+2395,3
+2396,3
+2397,0
+2398,3
+2399,3
+2400,0
+2401,3
+2402,0
+2403,0
+2404,1
+2405,3
+2406,3
+2407,0
+2408,1
+2409,0
+2410,3
+2411,2
+2412,1
+2413,3
+2414,0
+2415,0
+2416,3
+2417,0
+2418,2
+2419,0
+2420,0
+2421,1
+2422,3
+2423,2
+2424,1
+2425,0
+2426,3
+2427,2
+2428,0
+2429,2
+2430,3
+2431,1
+2432,2
+2433,0
+2434,2
+2435,1
+2436,3
+2437,3
+2438,2
+2439,0
+2440,0
+2441,0
+2442,2
+2443,3
+2444,1
+2445,0
+2446,3
+2447,2
+2448,0
+2449,0
+2450,3
+2451,3
+2452,0
+2453,2
+2454,3
+2455,0
+2456,0
+2457,0
+2458,1
+2459,2
+2460,0
+2461,0
+2462,2
+2463,3
+2464,0
+2465,0
+2466,2
+2467,3
+2468,3
+2469,3
+2470,0
+2471,0
+2472,0
+2473,2
+2474,3
+2475,0
+2476,0
+2477,0
+2478,3
+2479,3
+2480,1
+2481,0
+2482,3
+2483,0
+2484,3
+2485,1
+2486,3
+2487,0
+2488,3
+2489,1
+2490,2
+2491,0
+2492,2
+2493,1
+2494,0
+2495,0
+2496,1
+2497,2
+2498,1
+2499,0
+2500,2
+2501,3
+2502,3
+2503,1
+2504,2
+2505,0
+2506,0
+2507,0
+2508,2
+2509,3
+2510,0
+2511,0
+2512,0
+2513,3
+2514,1
+2515,0
+2516,3
+2517,0
+2518,1
+2519,1
+2520,0
+2521,0
+2522,2
+2523,1
+2524,0
+2525,0
+2526,3
+2527,0
+2528,0
+2529,0
+2530,0
+2531,0
+2532,2
+2533,0
+2534,0
+2535,1
+2536,2
+2537,0
+2538,0
+2539,3
+2540,0
+2541,2
+2542,3
+2543,2
+2544,2
+2545,1
+2546,3
+2547,0
+2548,1
+2549,0
+2550,3
+2551,3
+2552,2
+2553,0
+2554,2
+2555,0
+2556,0
+2557,2
+2558,0
+2559,0
+2560,0
+2561,3
+2562,2
+2563,2
+2564,0
+2565,3
+2566,2
+2567,3
+2568,0
+2569,2
+2570,2
+2571,1
+2572,0
+2573,2
+2574,0
+2575,1
+2576,1
+2577,0
+2578,2
+2579,0
+2580,1
+2581,1
+2582,3
+2583,3
+2584,3
+2585,1
+2586,0
+2587,2
+2588,3
+2589,3
+2590,2
+2591,2
+2592,2
+2593,0
+2594,1
+2595,0
+2596,1
+2597,0
+2598,1
+2599,0
+2600,3
+2601,3
+2602,3
+2603,0
+2604,2
+2605,1
+2606,2
+2607,0
+2608,2
+2609,3
+2610,0
+2611,3
+2612,0
+2613,0
+2614,0
+2615,0
+2616,0
+2617,3
+2618,0
+2619,2
+2620,1
+2621,3
+2622,2
+2623,1
+2624,1
+2625,2
+2626,0
+2627,0
+2628,1
+2629,3
+2630,0
+2631,0
+2632,0
+2633,1
+2634,2
+2635,1
+2636,0
+2637,3
+2638,3
+2639,1
+2640,3
+2641,0
+2642,2
+2643,2
+2644,3
+2645,0
+2646,0
+2647,0
+2648,1
+2649,0
+2650,2
+2651,0
+2652,0
+2653,1
+2654,0
+2655,0
+2656,2
+2657,2
+2658,0
+2659,0
+2660,2
+2661,1
+2662,0
+2663,3
+2664,2
+2665,3
+2666,0
+2667,2
+2668,2
+2669,0
+2670,3
+2671,1
+2672,3
+2673,0
+2674,0
+2675,0
+2676,0
+2677,1
+2678,3
+2679,0
+2680,3
+2681,2
+2682,2
+2683,0
+2684,3
+2685,1
+2686,0
+2687,2
+2688,0
+2689,0
+2690,1
+2691,0
+2692,2
+2693,2
+2694,2
+2695,1
+2696,3
+2697,2
+2698,0
+2699,3
+2700,2
+2701,3
+2702,0
+2703,1
+2704,0
+2705,2
+2706,3
+2707,1
+2708,0
+2709,2
+2710,1
+2711,0
+2712,0
+2713,2
+2714,0
+2715,3
+2716,1
+2717,0
+2718,1
+2719,3
+2720,3
+2721,0
+2722,0
+2723,0
+2724,3
+2725,1
+2726,0
+2727,0
+2728,3
+2729,2
+2730,0
+2731,0
+2732,3
+2733,2
+2734,0
+2735,0
+2736,2
+2737,1
+2738,0
+2739,0
+2740,0
+2741,0
+2742,0
+2743,1
+2744,1
+2745,0
+2746,3
+2747,1
+2748,3
+2749,0
+2750,3
+2751,3
+2752,0
+2753,0
+2754,2
+2755,2
+2756,0
+2757,2
+2758,2
+2759,1
+2760,3
+2761,0
+2762,0
+2763,0
+2764,0
+2765,0
+2766,1
+2767,3
+2768,0
+2769,0
+2770,3
+2771,0
+2772,3
+2773,0
+2774,0
+2775,0
+2776,0
+2777,1
+2778,3
+2779,3
+2780,0
+2781,2
+2782,0
+2783,2
+2784,2
+2785,0
+2786,2
+2787,0
+2788,3
+2789,0
+2790,0
+2791,0
+2792,0
+2793,1
+2794,0
+2795,0
+2796,2
+2797,0
+2798,2
+2799,1
+2800,3
+2801,0
+2802,0
+2803,0
+2804,3
+2805,3
+2806,0
+2807,3
+2808,3
+2809,0
+2810,1
+2811,0
+2812,0
+2813,1
+2814,0
+2815,3
+2816,0
+2817,0
+2818,2
+2819,3
+2820,2
+2821,2
+2822,2
+2823,2
+2824,0
+2825,0
+2826,0
+2827,0
+2828,3
+2829,2
+2830,0
+2831,0
+2832,3
+2833,0
+2834,2
+2835,0
+2836,0
+2837,3
+2838,2
+2839,2
+2840,2
+2841,3
+2842,1
+2843,1
+2844,0
+2845,2
+2846,2
+2847,3
+2848,0
+2849,0
+2850,3
+2851,0
+2852,0
+2853,3
+2854,3
+2855,0
+2856,0
+2857,0
+2858,1
+2859,0
+2860,2
+2861,0
+2862,0
+2863,0
+2864,1
+2865,1
+2866,0
+2867,3
+2868,0
+2869,3
+2870,3
+2871,1
+2872,0
+2873,2
+2874,2
+2875,0
+2876,0
+2877,3
+2878,2
+2879,3
+2880,0
+2881,3
+2882,3
+2883,2
+2884,3
+2885,3
+2886,3
+2887,1
+2888,1
+2889,1
+2890,0
+2891,3
+2892,0
+2893,3
+2894,0
+2895,3
+2896,3
+2897,1
+2898,3
+2899,0
+2900,3
+2901,3
+2902,3
+2903,2
+2904,3
+2905,2
+2906,2
+2907,0
+2908,3
+2909,3
+2910,1
+2911,1
+2912,0
+2913,2
+2914,3
+2915,2
+2916,3
+2917,3
+2918,3
+2919,0
+2920,0
+2921,0
+2922,3
+2923,1
+2924,0
+2925,0
+2926,0
+2927,0
+2928,2
+2929,3
+2930,2
+2931,1
+2932,0
+2933,2
+2934,0
+2935,0
+2936,0
+2937,2
+2938,0
+2939,0
+2940,2
+2941,3
+2942,0
+2943,0
+2944,1
+2945,0
+2946,0
+2947,0
+2948,2
+2949,0
+2950,0
+2951,2
+2952,0
+2953,2
+2954,1
+2955,0
+2956,2
+2957,3
+2958,0
+2959,0
+2960,0
+2961,0
+2962,3
+2963,3
+2964,0
+2965,2
+2966,2
+2967,1
+2968,1
+2969,0
+2970,0
+2971,1
+2972,0
+2973,0
+2974,2
+2975,2
+2976,3
+2977,3
+2978,1
+2979,0
+2980,2
+2981,0
+2982,3
+2983,1
+2984,2
+2985,0
+2986,2
+2987,3
+2988,0
+2989,2
+2990,0
+2991,0
+2992,0
+2993,0
+2994,0
+2995,3
+2996,0
+2997,0
+2998,3
+2999,0
+3000,0
+3001,0
+3002,3
+3003,2
+3004,0
+3005,3
+3006,1
+3007,0
+3008,3
+3009,1
+3010,2
+3011,1
+3012,0
+3013,3
+3014,1
+3015,3
+3016,0
+3017,0
+3018,0
+3019,3
+3020,2
+3021,0
+3022,1
+3023,3
+3024,0
+3025,3
+3026,0
+3027,1
+3028,0
+3029,3
+3030,3
+3031,0
+3032,3
+3033,2
+3034,0
+3035,3
+3036,3
+3037,0
+3038,0
+3039,0
+3040,3
+3041,1
+3042,0
+3043,0
+3044,1
+3045,0
+3046,0
+3047,0
+3048,0
+3049,0
+3050,0
+3051,0
+3052,0
+3053,1
+3054,0
+3055,2
+3056,0
+3057,2
+3058,0
+3059,3
+3060,0
+3061,0
+3062,3
+3063,0
+3064,3
+3065,3
+3066,0
+3067,3
+3068,1
+3069,0
+3070,0
+3071,3
+3072,3
+3073,3
+3074,3
+3075,0
+3076,0
+3077,0
+3078,0
+3079,0
+3080,3
+3081,3
+3082,0
+3083,0
+3084,1
+3085,0
+3086,3
+3087,0
+3088,3
+3089,2
+3090,0
+3091,2
+3092,1
+3093,0
+3094,0
+3095,1
+3096,0
+3097,3
+3098,3
+3099,2
+3100,2
+3101,0
+3102,0
+3103,0
+3104,0
+3105,1
+3106,0
+3107,0
+3108,0
+3109,0
+3110,3
+3111,0
+3112,2
+3113,1
+3114,0
+3115,0
+3116,0
+3117,0
+3118,0
+3119,0
+3120,1
+3121,2
+3122,0
+3123,0
+3124,0
+3125,2
+3126,0
+3127,2
+3128,2
+3129,0
+3130,0
+3131,3
+3132,1
+3133,0
+3134,0
+3135,3
+3136,3
+3137,3
+3138,1
+3139,0
+3140,0
+3141,1
+3142,2
+3143,0
+3144,3
+3145,0
+3146,3
+3147,0
+3148,0
+3149,0
+3150,1
+3151,0
+3152,0
+3153,0
+3154,0
+3155,3
+3156,3
+3157,3
+3158,1
+3159,2
+3160,2
+3161,2
+3162,1
+3163,0
+3164,3
+3165,3
+3166,3
+3167,1
+3168,0
+3169,0
+3170,2
+3171,1
+3172,3
+3173,3
+3174,2
+3175,0
+3176,0
+3177,1
+3178,3
+3179,1
+3180,2
+3181,1
+3182,2
+3183,2
+3184,0
+3185,3
+3186,3
+3187,1
+3188,0
+3189,0
+3190,0
+3191,0
+3192,0
+3193,3
+3194,1
+3195,2
+3196,0
+3197,0
+3198,0
+3199,2
+3200,0
+3201,1
+3202,3
+3203,0
+3204,2
+3205,0
+3206,3
+3207,0
+3208,1
+3209,3
+3210,0
+3211,2
+3212,2
+3213,3
+3214,3
+3215,0
+3216,0
+3217,2
+3218,0
+3219,0
+3220,1
+3221,0
+3222,3
+3223,2
+3224,0
+3225,0
+3226,0
+3227,3
+3228,0
+3229,2
+3230,0
+3231,3
+3232,0
+3233,1
+3234,3
+3235,0
+3236,2
+3237,3
+3238,1
+3239,3
+3240,2
+3241,2
+3242,3
+3243,0
+3244,0
+3245,1
+3246,2
+3247,0
+3248,1
+3249,3
+3250,3
+3251,0
+3252,0
+3253,3
+3254,0
+3255,3
+3256,2
+3257,3
+3258,2
+3259,0
+3260,3
+3261,1
+3262,0
+3263,3
+3264,0
+3265,0
+3266,2
+3267,3
+3268,3
+3269,1
+3270,0
+3271,1
+3272,0
+3273,0
+3274,0
+3275,0
+3276,0
+3277,0
+3278,0
+3279,0
+3280,2
+3281,1
+3282,3
+3283,0
+3284,0
+3285,1
+3286,3
+3287,0
+3288,3
+3289,0
+3290,0
+3291,0
+3292,1
+3293,3
+3294,1
+3295,1
+3296,0
+3297,0
+3298,1
+3299,0
+3300,1
+3301,0
+3302,0
+3303,0
+3304,0
+3305,0
+3306,0
+3307,0
+3308,0
+3309,3
+3310,0
+3311,0
+3312,1
+3313,1
+3314,2
+3315,2
+3316,0
+3317,0
+3318,3
+3319,1
+3320,2
+3321,0
+3322,3
+3323,0
+3324,2
+3325,0
+3326,0
+3327,0
+3328,3
+3329,2
+3330,2
+3331,0
+3332,3
+3333,0
+3334,2
+3335,3
+3336,0
+3337,0
+3338,1
+3339,2
+3340,3
+3341,0
+3342,0
+3343,0
+3344,2
+3345,1
+3346,2
+3347,0
+3348,0
+3349,2
+3350,2
+3351,0
+3352,0
+3353,3
+3354,0
+3355,1
+3356,3
+3357,0
+3358,0
+3359,3
+3360,0
+3361,0
+3362,0
+3363,3
+3364,0
+3365,0
+3366,2
+3367,1
+3368,3
+3369,1
+3370,1
+3371,0
+3372,3
+3373,3
+3374,2
+3375,3
+3376,0
+3377,1
+3378,3
+3379,1
+3380,0
+3381,0
+3382,3
+3383,2
+3384,0
+3385,3
+3386,0
+3387,2
+3388,1
+3389,0
+3390,0
+3391,0
+3392,3
+3393,0
+3394,2
+3395,0
+3396,0
+3397,0
+3398,3
+3399,3
+3400,3
+3401,2
+3402,2
+3403,1
+3404,0
+3405,3
+3406,2
+3407,0
+3408,0
+3409,0
+3410,2
+3411,1
+3412,3
+3413,0
+3414,1
+3415,0
+3416,3
+3417,0
+3418,0
+3419,3
+3420,3
+3421,3
+3422,0
+3423,0
+3424,1
+3425,0
+3426,0
+3427,3
+3428,2
+3429,2
+3430,0
+3431,0
+3432,0
+3433,0
+3434,3
+3435,2
+3436,1
+3437,1
+3438,0
+3439,0
+3440,3
+3441,0
+3442,0
+3443,2
+3444,0
+3445,0
+3446,3
+3447,1
+3448,1
+3449,3
+3450,0
+3451,3
+3452,3
+3453,0
+3454,0
+3455,3
+3456,2
+3457,0
+3458,3
+3459,0
+3460,1
+3461,0
+3462,0
+3463,1
+3464,0
+3465,0
+3466,1
+3467,0
+3468,2
+3469,3
+3470,3
+3471,2
+3472,3
+3473,0
+3474,2
+3475,0
+3476,0
+3477,3
+3478,2
+3479,0
+3480,2
+3481,3
+3482,3
+3483,0
+3484,2
+3485,1
+3486,1
+3487,0
+3488,0
+3489,0
+3490,0
+3491,2
+3492,0
+3493,3
+3494,1
+3495,0
+3496,0
+3497,0
+3498,2
+3499,1
+3500,0
+3501,1
+3502,2
+3503,0
+3504,2
+3505,0
+3506,0
+3507,2
+3508,2
+3509,0
+3510,3
+3511,2
+3512,2
+3513,2
+3514,0
+3515,0
+3516,0
+3517,0
+3518,0
+3519,3
+3520,2
+3521,2
+3522,3
+3523,0
+3524,2
+3525,2
+3526,0
+3527,0
+3528,1
+3529,0
+3530,2
+3531,3
+3532,0
+3533,0
+3534,2
+3535,1
+3536,2
+3537,3
+3538,0
+3539,3
+3540,2
+3541,0
+3542,0
+3543,2
+3544,0
+3545,1
+3546,1
+3547,2
+3548,1
+3549,0
+3550,2
+3551,3
+3552,2
+3553,3
+3554,0
+3555,2
+3556,0
+3557,2
+3558,3
+3559,0
+3560,2
+3561,0
+3562,2
+3563,2
+3564,3
+3565,0
+3566,0
+3567,1
+3568,1
+3569,3
+3570,2
+3571,2
+3572,0
+3573,0
+3574,0
+3575,0
+3576,0
+3577,0
+3578,3
+3579,0
+3580,1
+3581,2
+3582,0
+3583,0
+3584,2
+3585,3
+3586,1
+3587,3
+3588,0
+3589,3
+3590,3
+3591,0
+3592,2
+3593,3
+3594,2
+3595,0
+3596,0
+3597,0
+3598,0
+3599,0
+3600,3
+3601,3
+3602,3
+3603,2
+3604,0
+3605,0
+3606,2
+3607,0
+3608,0
+3609,0
+3610,3
+3611,0
+3612,3
+3613,2
+3614,1
+3615,1
+3616,0
+3617,0
+3618,0
+3619,2
+3620,2
+3621,1
+3622,3
+3623,1
+3624,3
+3625,3
+3626,3
+3627,3
+3628,3
+3629,0
+3630,0
+3631,3
+3632,0
+3633,1
+3634,0
+3635,0
+3636,3
+3637,2
+3638,3
+3639,0
+3640,2
+3641,3
+3642,0
+3643,0
+3644,2
+3645,2
+3646,0
+3647,0
+3648,3
+3649,3
+3650,2
+3651,0
+3652,2
+3653,0
+3654,0
+3655,0
+3656,0
+3657,3
+3658,0
+3659,2
+3660,1
+3661,0
+3662,1
+3663,0
+3664,0
+3665,3
+3666,1
+3667,0
+3668,2
+3669,2
+3670,2
+3671,1
+3672,0
+3673,0
+3674,1
+3675,2
+3676,0
+3677,1
+3678,2
+3679,0
+3680,0
+3681,1
+3682,0
+3683,3
+3684,0
+3685,3
+3686,0
+3687,0
+3688,2
+3689,2
+3690,1
+3691,0
+3692,1
+3693,0
+3694,2
+3695,1
+3696,0
+3697,0
+3698,3
+3699,2
+3700,3
+3701,1
+3702,1
+3703,1
+3704,3
+3705,0
+3706,0
+3707,0
+3708,2
+3709,0
+3710,0
+3711,3
+3712,0
+3713,0
+3714,2
+3715,1
+3716,3
+3717,1
+3718,3
+3719,1
+3720,0
+3721,1
+3722,1
+3723,1
+3724,0
+3725,0
+3726,0
+3727,0
+3728,0
+3729,0
+3730,3
+3731,0
+3732,3
+3733,0
+3734,0
+3735,3
+3736,0
+3737,3
+3738,0
+3739,3
+3740,2
+3741,0
+3742,3
+3743,0
+3744,3
+3745,0
+3746,0
+3747,2
+3748,2
+3749,1
+3750,0
+3751,0
+3752,3
+3753,2
+3754,0
+3755,2
+3756,3
+3757,0
+3758,3
+3759,2
+3760,0
+3761,0
+3762,0
+3763,0
+3764,0
+3765,3
+3766,3
+3767,0
+3768,2
+3769,0
+3770,3
+3771,0
+3772,0
+3773,0
+3774,1
+3775,2
+3776,0
+3777,0
+3778,0
+3779,1
+3780,1
+3781,0
+3782,0
+3783,1
+3784,2
+3785,3
+3786,0
+3787,0
+3788,2
+3789,0
+3790,2
+3791,0
+3792,2
+3793,2
+3794,0
+3795,0
+3796,0
+3797,0
+3798,1
+3799,0
+3800,0
+3801,1
+3802,3
+3803,2
+3804,0
+3805,1
+3806,2
+3807,0
+3808,3
+3809,0
+3810,2
+3811,3
+3812,2
+3813,1
+3814,2
+3815,0
+3816,0
+3817,0
+3818,3
+3819,0
+3820,2
+3821,2
+3822,0
+3823,3
+3824,0
+3825,0
+3826,2
+3827,0
+3828,0
+3829,1
+3830,0
+3831,2
+3832,3
+3833,3
+3834,0
+3835,0
+3836,0
+3837,0
+3838,0
+3839,3
+3840,2
+3841,3
+3842,3
+3843,3
+3844,0
+3845,2
+3846,0
+3847,0
+3848,0
+3849,1
+3850,0
+3851,0
+3852,0
+3853,0
+3854,3
+3855,0
+3856,2
+3857,0
+3858,0
+3859,3
+3860,2
+3861,0
+3862,0
+3863,0
+3864,1
+3865,0
+3866,3
+3867,0
+3868,0
+3869,3
+3870,0
+3871,2
+3872,1
+3873,2
+3874,3
+3875,0
+3876,0
+3877,0
+3878,0
+3879,0
+3880,0
+3881,3
+3882,1
+3883,1
+3884,3
+3885,0
+3886,2
+3887,1
+3888,0
+3889,0
+3890,2
+3891,2
+3892,0
+3893,0
+3894,0
+3895,0
+3896,0
+3897,3
+3898,2
+3899,0
+3900,2
+3901,1
+3902,0
+3903,3
+3904,0
+3905,3
+3906,0
+3907,0
+3908,0
+3909,3
+3910,2
+3911,1
+3912,3
+3913,0
+3914,0
+3915,2
+3916,0
+3917,0
+3918,3
+3919,3
+3920,0
+3921,2
+3922,1
+3923,1
+3924,3
+3925,0
+3926,1
+3927,2
+3928,2
+3929,0
+3930,0
+3931,3
+3932,2
+3933,0
+3934,0
+3935,2
+3936,0
+3937,1
+3938,0
+3939,1
+3940,0
+3941,1
+3942,1
+3943,0
+3944,1
+3945,2
+3946,2
+3947,0
+3948,1
+3949,3
+3950,2
+3951,2
+3952,0
+3953,0
+3954,0
+3955,1
+3956,0
+3957,3
+3958,1
+3959,0
+3960,0
+3961,0
+3962,3
+3963,2
+3964,2
+3965,3
+3966,0
+3967,2
+3968,0
+3969,1
+3970,3
+3971,0
+3972,0
+3973,0
+3974,3
+3975,0
+3976,0
+3977,3
+3978,3
+3979,1
+3980,3
+3981,0
+3982,2
+3983,2
+3984,1
+3985,1
+3986,3
+3987,1
+3988,2
+3989,3
+3990,0
+3991,2
+3992,2
+3993,0
+3994,0
+3995,0
+3996,0
+3997,0
+3998,2
+3999,0
+4000,0
+4001,3
+4002,1
+4003,2
+4004,0
+4005,1
+4006,3
+4007,1
+4008,1
+4009,1
+4010,2
+4011,2
+4012,3
+4013,3
+4014,3
+4015,3
+4016,2
+4017,2
+4018,3
+4019,0
+4020,0
+4021,0
+4022,0
+4023,0
+4024,3
+4025,2
+4026,2
+4027,0
+4028,0
+4029,0
+4030,0
+4031,1
+4032,0
+4033,2
+4034,0
+4035,3
+4036,1
+4037,2
+4038,2
+4039,3
+4040,0
+4041,0
+4042,0
+4043,0
+4044,2
+4045,2
+4046,2
+4047,3
+4048,0
+4049,3
+4050,2
+4051,3
+4052,2
+4053,2
+4054,3
+4055,0
+4056,0
+4057,0
+4058,0
+4059,0
+4060,3
+4061,0
+4062,0
+4063,0
+4064,0
+4065,3
+4066,0
+4067,0
+4068,1
+4069,3
+4070,0
+4071,2
+4072,3
+4073,0
+4074,1
+4075,0
+4076,0
+4077,0
+4078,0
+4079,2
+4080,0
+4081,1
+4082,0
+4083,0
+4084,0
+4085,3
+4086,2
+4087,3
+4088,0
+4089,0
+4090,1
+4091,0
+4092,0
+4093,0
+4094,2
+4095,1
+4096,0
+4097,0
+4098,0
+4099,3
+4100,1
+4101,0
+4102,2
+4103,2
+4104,2
+4105,3
+4106,0
+4107,2
+4108,0
+4109,0
+4110,0
+4111,3
+4112,2
+4113,0
+4114,0
+4115,3
+4116,3
+4117,3
+4118,0
+4119,1
+4120,2
+4121,0
+4122,0
+4123,2
+4124,0
+4125,2
+4126,2
+4127,0
+4128,0
+4129,3
+4130,0
+4131,3
+4132,2
+4133,0
+4134,0
+4135,2
+4136,0
+4137,2
+4138,2
+4139,1
+4140,1
+4141,3
+4142,3
+4143,2
+4144,3
+4145,0
+4146,2
+4147,0
+4148,0
+4149,3
+4150,0
+4151,0
+4152,0
+4153,2
+4154,1
+4155,0
+4156,0
+4157,3
+4158,1
+4159,2
+4160,3
+4161,0
+4162,2
+4163,2
+4164,0
+4165,3
+4166,0
+4167,3
+4168,2
+4169,0
+4170,2
+4171,0
+4172,2
+4173,0
+4174,0
+4175,3
+4176,1
+4177,0
+4178,2
+4179,2
+4180,0
+4181,1
+4182,2
+4183,2
+4184,0
+4185,0
+4186,2
+4187,3
+4188,0
+4189,2
+4190,2
+4191,3
+4192,0
+4193,3
+4194,2
+4195,2
+4196,0
+4197,0
+4198,1
+4199,2
+4200,3
+4201,0
+4202,0
+4203,2
+4204,0
+4205,0
+4206,3
+4207,0
+4208,0
+4209,0
+4210,0
+4211,0
+4212,0
+4213,0
+4214,1
+4215,0
+4216,1
+4217,0
+4218,0
+4219,3
+4220,0
+4221,3
+4222,2
+4223,0
+4224,0
+4225,0
+4226,0
+4227,1
+4228,3
+4229,0
+4230,0
+4231,0
+4232,2
+4233,2
+4234,0
+4235,2
+4236,1
+4237,0
+4238,3
+4239,0
+4240,2
+4241,3
+4242,0
+4243,0
+4244,0
+4245,0
+4246,0
+4247,1
+4248,3
+4249,0
+4250,3
+4251,0
+4252,0
+4253,2
+4254,0
+4255,0
+4256,3
+4257,0
+4258,1
+4259,3
+4260,3
+4261,0
+4262,3
+4263,1
+4264,2
+4265,0
+4266,2
+4267,2
+4268,0
+4269,0
+4270,2
+4271,1
+4272,3
+4273,0
+4274,1
+4275,3
+4276,0
+4277,2
+4278,1
+4279,0
+4280,0
+4281,0
+4282,2
+4283,2
+4284,0
+4285,0
+4286,1
+4287,0
+4288,1
+4289,2
+4290,3
+4291,0
+4292,2
+4293,0
+4294,0
+4295,1
+4296,1
+4297,1
+4298,2
+4299,1
+4300,0
+4301,3
+4302,2
+4303,0
+4304,0
+4305,1
+4306,3
+4307,3
+4308,3
+4309,2
+4310,1
+4311,2
+4312,0
+4313,3
+4314,2
+4315,0
+4316,2
+4317,3
+4318,0
+4319,0
+4320,3
+4321,3
+4322,1
+4323,0
+4324,0
+4325,3
+4326,1
+4327,3
+4328,1
+4329,1
+4330,1
+4331,1
+4332,0
+4333,3
+4334,2
+4335,2
+4336,0
+4337,2
+4338,0
+4339,3
+4340,2
+4341,3
+4342,3
+4343,3
+4344,3
+4345,2
+4346,0
+4347,2
+4348,3
+4349,2
+4350,0
+4351,2
+4352,3
+4353,1
+4354,0
+4355,0
+4356,0
+4357,0
+4358,1
+4359,0
+4360,2
+4361,0
+4362,0
+4363,0
+4364,2
+4365,2
+4366,2
+4367,0
+4368,2
+4369,2
+4370,0
+4371,0
+4372,0
+4373,3
+4374,0
+4375,0
+4376,1
+4377,0
+4378,3
+4379,0
+4380,1
+4381,3
+4382,0
+4383,3
+4384,0
+4385,3
+4386,1
+4387,0
+4388,0
+4389,0
+4390,2
+4391,2
+4392,0
+4393,0
+4394,0
+4395,1
+4396,1
+4397,0
+4398,2
+4399,0
+4400,2
+4401,3
+4402,2
+4403,0
+4404,1
+4405,1
+4406,2
+4407,0
+4408,0
+4409,0
+4410,2
+4411,1
+4412,0
+4413,0
+4414,3
+4415,0
+4416,0
+4417,3
+4418,3
+4419,2
+4420,1
+4421,2
+4422,1
+4423,0
+4424,3
+4425,0
+4426,0
+4427,2
+4428,0
+4429,0
+4430,3
+4431,2
+4432,1
+4433,2
+4434,1
+4435,2
+4436,0
+4437,0
+4438,0
+4439,0
+4440,0
+4441,2
+4442,3
+4443,2
+4444,3
+4445,0
+4446,1
+4447,1
+4448,2
+4449,0
+4450,0
+4451,0
+4452,1
+4453,3
+4454,1
+4455,0
+4456,2
+4457,0
+4458,1
+4459,3
+4460,2
+4461,2
+4462,0
+4463,3
+4464,3
+4465,0
+4466,0
+4467,2
+4468,0
+4469,1
+4470,0
+4471,0
+4472,1
+4473,1
+4474,0
+4475,1
+4476,0
+4477,2
+4478,0
+4479,0
+4480,0
+4481,3
+4482,1
+4483,3
+4484,3
+4485,3
+4486,0
+4487,0
+4488,1
+4489,3
+4490,3
+4491,2
+4492,3
+4493,0
+4494,1
+4495,0
+4496,3
+4497,0
+4498,3
+4499,0
+4500,0
+4501,0
+4502,1
+4503,0
+4504,2
+4505,3
+4506,0
+4507,3
+4508,1
+4509,0
+4510,3
+4511,0
+4512,0
+4513,3
+4514,3
+4515,3
+4516,2
+4517,2
+4518,1
+4519,0
+4520,0
+4521,2
+4522,2
+4523,0
+4524,2
+4525,0
+4526,3
+4527,0
+4528,1
+4529,1
+4530,2
+4531,2
+4532,1
+4533,0
+4534,2
+4535,0
+4536,3
+4537,3
+4538,2
+4539,2
+4540,1
+4541,2
+4542,2
+4543,2
+4544,3
+4545,3
+4546,3
+4547,3
+4548,2
+4549,0
+4550,2
+4551,1
+4552,3
+4553,0
+4554,2
+4555,2
+4556,3
+4557,0
+4558,3
+4559,3
+4560,2
+4561,1
+4562,3
+4563,0
+4564,0
+4565,0
+4566,0
+4567,1
+4568,3
+4569,3
+4570,0
+4571,2
+4572,0
+4573,0
+4574,2
+4575,3
+4576,3
+4577,1
+4578,0
+4579,3
+4580,2
+4581,0
+4582,0
+4583,2
+4584,2
+4585,1
+4586,0
+4587,2
+4588,2
+4589,0
+4590,2
+4591,0
+4592,0
+4593,0
+4594,2
+4595,1
+4596,0
+4597,0
+4598,2
+4599,0
+4600,3
+4601,3
+4602,3
+4603,3
+4604,0
+4605,2
+4606,0
+4607,1
+4608,0
+4609,2
+4610,0
+4611,0
+4612,0
+4613,0
+4614,0
+4615,3
+4616,3
+4617,2
+4618,0
+4619,2
+4620,0
+4621,2
+4622,3
+4623,0
+4624,3
+4625,0
+4626,3
+4627,0
+4628,0
+4629,3
+4630,0
+4631,0
+4632,0
+4633,3
+4634,0
+4635,0
+4636,1
+4637,2
+4638,0
+4639,0
+4640,0
+4641,0
+4642,1
+4643,0
+4644,0
+4645,1
+4646,0
+4647,0
+4648,0
+4649,0
+4650,3
+4651,0
+4652,0
+4653,3
+4654,0
+4655,0
+4656,3
+4657,2
+4658,0
+4659,3
+4660,1
+4661,1
+4662,1
+4663,0
+4664,1
+4665,1
+4666,2
+4667,2
+4668,1
+4669,3
+4670,0
+4671,0
+4672,3
+4673,2
+4674,0
+4675,0
+4676,3
+4677,1
+4678,0
+4679,1
+4680,2
+4681,0
+4682,3
+4683,0
+4684,0
+4685,2
+4686,0
+4687,1
+4688,0
+4689,0
+4690,2
+4691,0
+4692,0
+4693,3
+4694,1
+4695,1
+4696,2
+4697,1
+4698,0
+4699,0
+4700,0
+4701,0
+4702,2
+4703,0
+4704,1
+4705,0
+4706,3
+4707,3
+4708,2
+4709,1
+4710,0
+4711,0
+4712,3
+4713,3
+4714,0
+4715,0
+4716,0
+4717,0
+4718,3
+4719,1
+4720,1
+4721,3
+4722,2
+4723,2
+4724,3
+4725,0
+4726,2
+4727,0
+4728,3
+4729,1
+4730,0
+4731,0
+4732,0
+4733,3
+4734,0
+4735,0
+4736,3
+4737,0
+4738,0
+4739,2
+4740,3
+4741,0
+4742,2
+4743,2
+4744,0
+4745,3
+4746,0
+4747,0
+4748,2
+4749,0
+4750,2
+4751,3
+4752,1
+4753,1
+4754,0
+4755,2
+4756,1
+4757,2
+4758,0
+4759,1
+4760,3
+4761,3
+4762,2
+4763,0
+4764,0
+4765,2
+4766,3
+4767,2
+4768,0
+4769,3
+4770,0
+4771,0
+4772,2
+4773,1
+4774,3
+4775,0
+4776,2
+4777,0
+4778,0
+4779,3
+4780,1
+4781,0
+4782,2
+4783,0
+4784,0
+4785,1
+4786,0
+4787,0
+4788,1
+4789,0
+4790,0
+4791,0
+4792,0
+4793,0
+4794,3
+4795,2
+4796,0
+4797,2
+4798,1
+4799,0
+4800,0
+4801,0
+4802,2
+4803,3
+4804,0
+4805,0
+4806,0
+4807,0
+4808,3
+4809,0
+4810,1
+4811,3
+4812,0
+4813,2
+4814,2
+4815,0
+4816,0
+4817,0
+4818,0
+4819,3
+4820,0
+4821,0
+4822,2
+4823,0
+4824,0
+4825,0
+4826,1
+4827,3
+4828,2
+4829,3
+4830,3
+4831,0
+4832,0
+4833,2
+4834,3
+4835,1
+4836,1
+4837,2
+4838,0
+4839,3
+4840,3
+4841,2
+4842,3
+4843,0
+4844,3
+4845,0
+4846,0
+4847,0
+4848,3
+4849,0
+4850,0
+4851,0
+4852,1
+4853,2
+4854,1
+4855,2
+4856,1
+4857,0
+4858,0
+4859,0
+4860,3
+4861,2
+4862,0
+4863,3
+4864,0
+4865,0
+4866,1
+4867,2
+4868,1
+4869,3
+4870,1
+4871,1
+4872,0
+4873,0
+4874,3
+4875,3
+4876,3
+4877,3
+4878,1
+4879,1
+4880,0
+4881,1
+4882,3
+4883,2
+4884,1
+4885,0
+4886,0
+4887,1
+4888,0
+4889,0
+4890,2
+4891,3
+4892,3
+4893,2
+4894,0
+4895,2
+4896,1
+4897,0
+4898,1
+4899,3
+4900,2
+4901,0
+4902,0
+4903,0
+4904,1
+4905,2
+4906,3
+4907,0
+4908,0
+4909,0
+4910,0
+4911,1
+4912,2
+4913,3
+4914,1
+4915,2
+4916,3
+4917,3
+4918,3
+4919,3
+4920,0
+4921,0
+4922,2
+4923,0
+4924,3
+4925,1
+4926,2
+4927,0
+4928,0
+4929,2
+4930,0
+4931,0
+4932,3
+4933,3
+4934,1
+4935,1
+4936,3
+4937,3
+4938,1
+4939,0
+4940,0
+4941,3
+4942,2
+4943,0
+4944,3
+4945,2
+4946,0
+4947,0
+4948,3
+4949,0
+4950,0
+4951,3
+4952,0
+4953,0
+4954,0
+4955,3
+4956,3
+4957,1
+4958,0
+4959,1
+4960,1
+4961,0
+4962,0
+4963,0
+4964,2
+4965,0
+4966,0
+4967,0
+4968,1
+4969,0
+4970,0
+4971,0
+4972,1
+4973,2
+4974,0
+4975,0
+4976,0
+4977,0
+4978,3
+4979,2
+4980,0
+4981,0
+4982,3
+4983,0
+4984,0
+4985,3
+4986,2
+4987,0
+4988,0
+4989,2
+4990,0
+4991,0
+4992,0
+4993,0
+4994,0
+4995,0
+4996,3
+4997,0
+4998,2
+4999,3
+5000,0
+5001,0
+5002,0
+5003,1
+5004,0
+5005,0
+5006,0
+5007,0
+5008,0
+5009,0
+5010,2
+5011,1
+5012,0
+5013,2
+5014,3
+5015,2
+5016,0
+5017,0
+5018,0
+5019,0
+5020,3
+5021,3
+5022,0
+5023,0
+5024,2
+5025,3
+5026,0
+5027,3
+5028,3
+5029,3
+5030,0
+5031,0
+5032,3
+5033,0
+5034,0
+5035,1
+5036,0
+5037,1
+5038,3
+5039,0
+5040,0
+5041,3
+5042,2
+5043,3
+5044,1
+5045,2
+5046,0
+5047,0
+5048,0
+5049,0
+5050,0
+5051,2
+5052,0
+5053,1
+5054,0
+5055,0
+5056,0
+5057,3
+5058,1
+5059,2
+5060,2
+5061,2
+5062,2
+5063,1
+5064,1
+5065,2
+5066,3
+5067,0
+5068,2
+5069,0
+5070,3
+5071,0
+5072,0
+5073,0
+5074,0
+5075,1
+5076,1
+5077,0
+5078,2
+5079,2
+5080,0
+5081,3
+5082,0
+5083,0
+5084,0
+5085,2
+5086,0
+5087,0
+5088,0
+5089,3
+5090,0
+5091,0
+5092,0
+5093,2
+5094,0
+5095,0
+5096,1
+5097,0
+5098,0
+5099,1
+5100,3
+5101,3
+5102,0
+5103,0
+5104,0
+5105,3
+5106,0
+5107,2
+5108,3
+5109,0
+5110,0
+5111,3
+5112,2
+5113,1
+5114,3
+5115,2
+5116,1
+5117,0
+5118,0
+5119,2
+5120,2
+5121,2
+5122,1
+5123,0
+5124,0
+5125,0
+5126,0
+5127,2
+5128,0
+5129,0
+5130,0
+5131,1
+5132,0
+5133,1
+5134,0
+5135,0
+5136,1
+5137,0
+5138,0
+5139,0
+5140,3
+5141,0
+5142,2
+5143,2
+5144,2
+5145,1
+5146,3
+5147,1
+5148,0
+5149,0
+5150,0
+5151,2
+5152,2
+5153,0
+5154,0
+5155,0
+5156,0
+5157,2
+5158,3
+5159,0
+5160,1
+5161,2
+5162,2
+5163,0
+5164,0
+5165,0
+5166,0
+5167,0
+5168,0
+5169,0
+5170,0
+5171,0
+5172,3
+5173,0
+5174,0
+5175,1
+5176,0
+5177,3
+5178,2
+5179,1
+5180,3
+5181,0
+5182,2
+5183,1
+5184,1
+5185,0
+5186,0
+5187,0
+5188,3
+5189,2
+5190,0
+5191,0
+5192,0
+5193,1
+5194,0
+5195,0
+5196,2
+5197,2
+5198,0
+5199,3
+5200,3
+5201,0
+5202,0
+5203,3
+5204,3
+5205,1
+5206,2
+5207,3
+5208,0
+5209,1
+5210,3
+5211,0
+5212,2
+5213,0
+5214,0
+5215,0
+5216,3
+5217,3
+5218,2
+5219,2
+5220,0
+5221,2
+5222,1
+5223,0
+5224,1
+5225,3
+5226,0
+5227,0
+5228,2
+5229,0
+5230,3
+5231,0
+5232,2
+5233,3
+5234,1
+5235,1
+5236,0
+5237,0
+5238,2
+5239,0
+5240,0
+5241,0
+5242,2
+5243,3
+5244,0
+5245,3
+5246,3
+5247,2
+5248,0
+5249,0
+5250,3
+5251,0
+5252,3
+5253,3
+5254,2
+5255,0
+5256,2
+5257,0
+5258,0
+5259,0
+5260,3
+5261,2
+5262,0
+5263,0
+5264,1
+5265,3
+5266,0
+5267,0
+5268,0
+5269,1
+5270,3
+5271,2
+5272,3
+5273,0
+5274,3
+5275,2
+5276,0
+5277,0
+5278,3
+5279,2
+5280,3
+5281,0
+5282,1
+5283,0
+5284,3
+5285,0
+5286,0
+5287,0
+5288,1
+5289,2
+5290,1
+5291,1
+5292,0
+5293,0
+5294,2
+5295,2
+5296,0
+5297,0
+5298,0
+5299,3
+5300,0
+5301,0
+5302,0
+5303,0
+5304,0
+5305,2
+5306,1
+5307,3
+5308,0
+5309,0
+5310,0
+5311,2
+5312,0
+5313,0
+5314,0
+5315,3
+5316,2
+5317,1
+5318,3
+5319,3
+5320,2
+5321,0
+5322,0
+5323,0
+5324,3
+5325,2
+5326,0
+5327,0
+5328,1
+5329,1
+5330,0
+5331,0
+5332,0
+5333,2
+5334,3
+5335,2
+5336,0
+5337,0
+5338,1
+5339,2
+5340,2
+5341,0
+5342,0
+5343,3
+5344,0
+5345,1
+5346,1
+5347,0
+5348,1
+5349,0
+5350,0
+5351,1
+5352,0
+5353,3
+5354,3
+5355,3
+5356,3
+5357,2
+5358,3
+5359,0
+5360,0
+5361,3
+5362,1
+5363,1
+5364,0
+5365,3
+5366,2
+5367,0
+5368,0
+5369,3
+5370,3
+5371,2
+5372,2
+5373,0
+5374,3
+5375,0
+5376,3
+5377,2
+5378,0
+5379,0
+5380,0
+5381,0
+5382,0
+5383,0
+5384,0
+5385,0
+5386,0
+5387,0
+5388,2
+5389,3
+5390,0
+5391,1
+5392,3
+5393,1
+5394,0
+5395,1
+5396,3
+5397,0
+5398,2
+5399,0
+5400,3
+5401,3
+5402,2
+5403,1
+5404,0
+5405,0
+5406,0
+5407,0
+5408,3
+5409,2
+5410,3
+5411,1
+5412,3
+5413,3
+5414,0
+5415,2
+5416,2
+5417,3
+5418,3
+5419,0
+5420,2
+5421,1
+5422,1
+5423,3
+5424,0
+5425,1
+5426,3
+5427,0
+5428,0
+5429,0
+5430,1
+5431,2
+5432,0
+5433,1
+5434,0
+5435,3
+5436,0
+5437,0
+5438,1
+5439,3
+5440,1
+5441,3
+5442,3
+5443,3
+5444,1
+5445,0
+5446,2
+5447,0
+5448,0
+5449,1
+5450,0
+5451,2
+5452,3
+5453,1
+5454,0
+5455,0
+5456,0
+5457,0
+5458,0
+5459,0
+5460,2
+5461,0
+5462,1
+5463,0
+5464,0
+5465,0
+5466,0
+5467,0
+5468,1
+5469,0
+5470,0
+5471,0
+5472,0
+5473,0
+5474,0
+5475,1
+5476,3
+5477,2
+5478,0
+5479,0
+5480,0
+5481,2
+5482,2
+5483,1
+5484,0
+5485,0
+5486,1
+5487,0
+5488,0
+5489,3
+5490,0
+5491,0
+5492,2
+5493,2
+5494,1
+5495,0
+5496,0
+5497,0
+5498,0
+5499,3
+5500,2
+5501,0
+5502,0
+5503,0
+5504,3
+5505,3
+5506,3
+5507,0
+5508,3
+5509,3
+5510,3
+5511,2
+5512,3
+5513,0
+5514,3
+5515,3
+5516,3
+5517,3
+5518,2
+5519,0
+5520,0
+5521,3
+5522,0
+5523,3
+5524,3
+5525,3
+5526,3
+5527,3
+5528,1
+5529,0
+5530,2
+5531,0
+5532,0
+5533,3
+5534,0
+5535,1
+5536,2
+5537,3
+5538,0
+5539,0
+5540,2
+5541,2
+5542,0
+5543,1
+5544,2
+5545,0
+5546,0
+5547,3
+5548,3
+5549,0
+5550,3
+5551,0
+5552,1
+5553,0
+5554,0
+5555,0
+5556,1
+5557,0
+5558,0
+5559,0
+5560,0
+5561,1
+5562,0
+5563,3
+5564,2
+5565,1
+5566,3
+5567,2
+5568,0
+5569,2
+5570,0
+5571,0
+5572,0
+5573,2
+5574,0
+5575,2
+5576,1
+5577,0
+5578,3
+5579,0
+5580,0
+5581,0
+5582,0
+5583,3
+5584,1
+5585,3
+5586,1
+5587,0
+5588,0
+5589,1
+5590,3
+5591,3
+5592,2
+5593,2
+5594,2
+5595,2
+5596,1
+5597,0
+5598,0
+5599,1
+5600,0
+5601,1
+5602,2
+5603,3
+5604,3
+5605,2
+5606,3
+5607,3
+5608,2
+5609,0
+5610,2
+5611,3
+5612,1
+5613,2
+5614,3
+5615,0
+5616,0
+5617,0
+5618,1
+5619,1
+5620,3
+5621,0
+5622,3
+5623,0
+5624,0
+5625,0
+5626,3
+5627,3
+5628,3
+5629,2
+5630,2
+5631,2
+5632,0
+5633,0
+5634,2
+5635,0
+5636,0
+5637,0
+5638,2
+5639,0
+5640,0
+5641,2
+5642,0
+5643,0
+5644,0
+5645,3
+5646,2
+5647,2
+5648,1
+5649,3
+5650,2
+5651,1
+5652,0
+5653,0
+5654,0
+5655,1
+5656,3
+5657,0
+5658,3
+5659,0
+5660,0
+5661,0
+5662,3
+5663,2
+5664,3
+5665,0
+5666,2
+5667,1
+5668,2
+5669,0
+5670,2
+5671,0
+5672,0
+5673,3
+5674,1
+5675,2
+5676,3
+5677,3
+5678,1
+5679,3
+5680,0
+5681,1
+5682,0
+5683,0
+5684,0
+5685,0
+5686,1
+5687,3
+5688,0
+5689,1
+5690,0
+5691,0
+5692,3
+5693,2
+5694,0
+5695,0
+5696,0
+5697,2
+5698,3
+5699,0
+5700,2
+5701,0
+5702,2
+5703,3
+5704,0
+5705,0
+5706,0
+5707,0
+5708,0
+5709,0
+5710,3
+5711,2
+5712,0
+5713,0
+5714,0
+5715,0
+5716,2
+5717,0
+5718,2
+5719,0
+5720,0
+5721,0
+5722,2
+5723,1
+5724,3
+5725,2
+5726,0
+5727,3
+5728,3
+5729,0
+5730,0
+5731,0
+5732,0
+5733,0
+5734,1
+5735,0
+5736,3
+5737,3
+5738,0
+5739,0
+5740,0
+5741,0
+5742,3
+5743,0
+5744,1
+5745,0
+5746,1
+5747,3
+5748,1
+5749,0
+5750,0
+5751,1
+5752,0
+5753,0
+5754,3
+5755,0
+5756,0
+5757,3
+5758,0
+5759,0
+5760,0
+5761,2
+5762,3
+5763,1
+5764,1
+5765,0
+5766,0
+5767,2
+5768,3
+5769,0
+5770,2
+5771,0
+5772,2
+5773,1
+5774,0
+5775,0
+5776,1
+5777,0
+5778,0
+5779,3
+5780,2
+5781,0
+5782,3
+5783,2
+5784,3
+5785,0
+5786,1
+5787,2
+5788,3
+5789,0
+5790,0
+5791,2
+5792,0
+5793,2
+5794,2
+5795,1
+5796,0
+5797,3
+5798,2
+5799,0
+5800,0
+5801,2
+5802,3
+5803,3
+5804,1
+5805,3
+5806,3
+5807,3
+5808,1
+5809,1
+5810,0
+5811,0
+5812,0
+5813,0
+5814,1
+5815,0
+5816,1
+5817,3
+5818,3
+5819,3
+5820,0
+5821,1
+5822,0
+5823,1
+5824,3
+5825,0
+5826,1
+5827,0
+5828,0
+5829,0
+5830,0
+5831,3
+5832,0
+5833,2
+5834,0
+5835,2
+5836,3
+5837,2
+5838,2
+5839,0
+5840,2
+5841,2
+5842,1
+5843,0
+5844,1
+5845,2
+5846,0
+5847,2
+5848,1
+5849,0
+5850,1
+5851,1
+5852,2
+5853,2
+5854,0
+5855,3
+5856,0
+5857,2
+5858,0
+5859,1
+5860,3
+5861,3
+5862,3
+5863,3
+5864,1
+5865,2
+5866,0
+5867,2
+5868,0
+5869,0
+5870,2
+5871,1
+5872,1
+5873,0
+5874,0
+5875,0
+5876,2
+5877,2
+5878,2
+5879,0
+5880,1
+5881,1
+5882,1
+5883,0
+5884,2
+5885,0
+5886,3
+5887,0
+5888,0
+5889,0
+5890,2
+5891,1
+5892,0
+5893,0
+5894,3
+5895,1
+5896,0
+5897,0
+5898,2
+5899,0
+5900,0
+5901,3
+5902,1
+5903,2
+5904,0
+5905,3
+5906,0
+5907,3
+5908,0
+5909,3
+5910,0
+5911,3
+5912,3
+5913,2
+5914,0
+5915,0
+5916,0
+5917,3
+5918,2
+5919,0
+5920,1
+5921,3
+5922,0
+5923,0
+5924,3
+5925,0
+5926,2
+5927,2
+5928,0
+5929,0
+5930,0
+5931,2
+5932,0
+5933,0
+5934,3
+5935,0
+5936,0
+5937,2
+5938,0
+5939,2
+5940,1
+5941,1
+5942,1
+5943,3
+5944,0
+5945,1
+5946,0
+5947,2
+5948,3
+5949,0
+5950,2
+5951,2
+5952,1
+5953,2
+5954,0
+5955,0
+5956,3
+5957,1
+5958,0
+5959,0
+5960,3
+5961,0
+5962,2
+5963,0
+5964,0
+5965,0
+5966,0
+5967,0
+5968,3
+5969,0
+5970,3
+5971,0
+5972,2
+5973,1
+5974,1
+5975,0
+5976,0
+5977,1
+5978,2
+5979,3
+5980,2
+5981,1
+5982,0
+5983,3
+5984,3
+5985,2
+5986,0
+5987,1
+5988,2
+5989,0
+5990,0
+5991,1
+5992,3
+5993,0
+5994,0
+5995,0
+5996,2
+5997,2
+5998,0
+5999,3
+6000,0
+6001,3
+6002,1
+6003,0
+6004,3
+6005,1
+6006,3
+6007,0
+6008,0
+6009,2
+6010,3
+6011,2
+6012,0
+6013,3
+6014,0
+6015,3
+6016,3
+6017,3
+6018,0
+6019,2
+6020,0
+6021,0
+6022,2
+6023,3
+6024,3
+6025,1
+6026,0
+6027,0
+6028,0
+6029,0
+6030,3
+6031,0
+6032,0
+6033,3
+6034,0
+6035,2
+6036,0
+6037,0
+6038,2
+6039,0
+6040,2
+6041,2
+6042,2
+6043,1
+6044,0
+6045,1
+6046,2
+6047,1
+6048,1
+6049,0
+6050,1
+6051,0
+6052,3
+6053,0
+6054,0
+6055,0
+6056,3
+6057,1
+6058,2
+6059,2
+6060,0
+6061,0
+6062,3
+6063,3
+6064,3
+6065,2
+6066,0
+6067,1
+6068,2
+6069,0
+6070,0
+6071,2
+6072,0
+6073,2
+6074,2
+6075,1
+6076,0
+6077,1
+6078,0
+6079,2
+6080,3
+6081,2
+6082,0
+6083,0
+6084,0
+6085,2
+6086,2
+6087,1
+6088,1
+6089,3
+6090,3
+6091,0
+6092,0
+6093,0
+6094,1
+6095,3
+6096,0
+6097,3
+6098,1
+6099,2
+6100,0
+6101,2
+6102,0
+6103,2
+6104,0
+6105,0
+6106,0
+6107,0
+6108,0
+6109,0
+6110,2
+6111,1
+6112,0
+6113,0
+6114,2
+6115,3
+6116,0
+6117,0
+6118,0
+6119,0
+6120,0
+6121,2
+6122,3
+6123,0
+6124,3
+6125,2
+6126,0
+6127,2
+6128,0
+6129,0
+6130,1
+6131,0
+6132,0
+6133,0
+6134,0
+6135,0
+6136,0
+6137,3
+6138,0
+6139,2
+6140,2
+6141,0
+6142,2
+6143,2
+6144,3
+6145,3
+6146,0
+6147,1
+6148,0
+6149,0
+6150,0
+6151,2
+6152,0
+6153,2
+6154,0
+6155,3
+6156,1
+6157,3
+6158,2
+6159,0
+6160,0
+6161,0
+6162,0
+6163,0
+6164,3
+6165,0
+6166,1
+6167,0
+6168,2
+6169,0
+6170,0
+6171,2
+6172,0
+6173,2
+6174,0
+6175,3
+6176,0
+6177,2
+6178,2
+6179,2
+6180,1
+6181,3
+6182,3
+6183,0
+6184,0
+6185,2
+6186,0
+6187,0
+6188,0
+6189,0
+6190,0
+6191,3
+6192,2
+6193,0
+6194,2
+6195,3
+6196,0
+6197,2
+6198,0
+6199,0
+6200,0
+6201,1
+6202,2
+6203,0
+6204,0
+6205,0
+6206,0
+6207,1
+6208,3
+6209,2
+6210,2
+6211,1
+6212,3
+6213,2
+6214,0
+6215,3
+6216,3
+6217,1
+6218,1
+6219,0
+6220,0
+6221,0
+6222,0
+6223,0
+6224,1
+6225,0
+6226,1
+6227,3
+6228,1
+6229,0
+6230,0
+6231,0
+6232,0
+6233,0
+6234,2
+6235,3
+6236,0
+6237,0
+6238,0
+6239,0
+6240,0
+6241,0
+6242,0
+6243,1
+6244,0
+6245,2
+6246,2
+6247,0
+6248,0
+6249,0
+6250,3
+6251,1
+6252,1
+6253,0
+6254,0
+6255,0
+6256,3
+6257,0
+6258,0
+6259,3
+6260,0
+6261,0
+6262,2
+6263,2
+6264,3
+6265,3
+6266,3
+6267,0
+6268,0
+6269,0
+6270,0
+6271,2
+6272,2
+6273,0
+6274,3
+6275,2
+6276,2
+6277,0
+6278,0
+6279,1
+6280,1
+6281,2
+6282,0
+6283,0
+6284,1
+6285,0
+6286,0
+6287,3
+6288,2
+6289,1
+6290,0
+6291,3
+6292,0
+6293,0
+6294,3
+6295,0
+6296,1
+6297,0
+6298,0
+6299,2
+6300,3
+6301,3
+6302,2
+6303,0
+6304,2
+6305,0
+6306,0
+6307,0
+6308,0
+6309,2
+6310,1
+6311,3
+6312,2
+6313,0
+6314,3
+6315,3
+6316,0
+6317,2
+6318,3
+6319,3
+6320,3
+6321,3
+6322,0
+6323,2
+6324,2
+6325,0
+6326,3
+6327,0
+6328,2
+6329,0
+6330,0
+6331,0
+6332,3
+6333,0
+6334,3
+6335,0
+6336,3
+6337,0
+6338,0
+6339,0
+6340,3
+6341,0
+6342,0
+6343,2
+6344,0
+6345,1
+6346,1
+6347,3
+6348,2
+6349,1
+6350,0
+6351,0
+6352,3
+6353,2
+6354,0
+6355,0
+6356,0
+6357,3
+6358,3
+6359,2
+6360,0
+6361,0
+6362,3
+6363,2
+6364,3
+6365,3
+6366,2
+6367,1
+6368,0
+6369,3
+6370,2
+6371,3
+6372,0
+6373,3
+6374,0
+6375,0
+6376,2
+6377,0
+6378,0
+6379,0
+6380,2
+6381,1
+6382,3
+6383,2
+6384,0
+6385,3
+6386,2
+6387,0
+6388,0
+6389,0
+6390,3
+6391,3
+6392,3
+6393,0
+6394,3
+6395,0
+6396,3
+6397,0
+6398,0
+6399,1
+6400,1
+6401,0
+6402,1
+6403,0
+6404,3
+6405,3
+6406,2
+6407,0
+6408,2
+6409,3
+6410,1
+6411,2
+6412,2
+6413,0
+6414,0
+6415,0
+6416,2
+6417,0
+6418,0
+6419,1
+6420,0
+6421,2
+6422,3
+6423,2
+6424,0
+6425,2
+6426,1
+6427,0
+6428,0
+6429,0
+6430,2
+6431,0
+6432,2
+6433,1
+6434,2
+6435,1
+6436,1
+6437,2
+6438,3
+6439,1
+6440,3
+6441,2
+6442,2
+6443,0
+6444,1
+6445,0
+6446,3
+6447,0
+6448,0
+6449,2
+6450,3
+6451,0
+6452,3
+6453,0
+6454,0
+6455,0
+6456,0
+6457,0
+6458,3
+6459,2
+6460,0
+6461,3
+6462,2
+6463,0
+6464,2
+6465,0
+6466,0
+6467,1
+6468,1
+6469,1
+6470,0
+6471,0
+6472,0
+6473,2
+6474,0
+6475,1
+6476,2
+6477,3
+6478,0
+6479,2
+6480,3
+6481,0
+6482,2
+6483,2
+6484,2
+6485,3
+6486,0
+6487,1
+6488,0
+6489,0
+6490,0
+6491,0
+6492,0
+6493,2
+6494,3
+6495,0
+6496,2
+6497,0
+6498,2
+6499,3
+6500,3
+6501,1
+6502,0
+6503,3
+6504,0
+6505,0
+6506,3
+6507,0
+6508,3
+6509,3
+6510,0
+6511,2
+6512,3
+6513,3
+6514,1
+6515,1
+6516,2
+6517,1
+6518,2
+6519,0
+6520,2
+6521,3
+6522,0
+6523,0
+6524,1
+6525,0
+6526,3
+6527,3
+6528,0
+6529,1
+6530,1
+6531,0
+6532,0
+6533,0
+6534,0
+6535,0
+6536,3
+6537,0
+6538,2
+6539,2
+6540,0
+6541,0
+6542,0
+6543,0
+6544,0
+6545,1
+6546,3
+6547,0
+6548,0
+6549,1
+6550,1
+6551,0
+6552,0
+6553,2
+6554,2
+6555,0
+6556,2
+6557,2
+6558,1
+6559,3
+6560,2
+6561,1
+6562,1
+6563,2
+6564,0
+6565,0
+6566,3
+6567,3
+6568,0
+6569,2
+6570,1
+6571,2
+6572,0
+6573,0
+6574,0
+6575,3
+6576,0
+6577,3
+6578,0
+6579,0
+6580,1
+6581,0
+6582,3
+6583,0
+6584,1
+6585,0
+6586,0
+6587,0
+6588,3
+6589,0
+6590,0
+6591,0
+6592,0
+6593,3
+6594,0
+6595,0
+6596,0
+6597,2
+6598,2
+6599,3
+6600,3
+6601,0
+6602,0
+6603,0
+6604,3
+6605,3
+6606,3
+6607,2
+6608,1
+6609,0
+6610,0
+6611,1
+6612,2
+6613,3
+6614,2
+6615,0
+6616,2
+6617,3
+6618,2
+6619,0
+6620,0
+6621,0
+6622,3
+6623,0
+6624,0
+6625,1
+6626,0
+6627,3
+6628,0
+6629,0
+6630,0
+6631,3
+6632,2
+6633,2
+6634,0
+6635,1
+6636,0
+6637,2
+6638,2
+6639,0
+6640,3
+6641,1
+6642,0
+6643,3
+6644,2
+6645,0
+6646,0
+6647,0
+6648,3
+6649,3
+6650,0
+6651,0
+6652,0
+6653,3
+6654,0
+6655,0
+6656,0
+6657,0
+6658,2
+6659,1
+6660,3
+6661,3
+6662,2
+6663,0
+6664,0
+6665,0
+6666,0
+6667,0
+6668,0
+6669,3
+6670,0
+6671,3
+6672,0
+6673,0
+6674,0
+6675,1
+6676,2
+6677,0
+6678,2
+6679,2
+6680,0
+6681,0
+6682,0
+6683,0
+6684,3
+6685,2
+6686,2
+6687,1
+6688,2
+6689,0
+6690,0
+6691,2
+6692,3
+6693,1
+6694,3
+6695,0
+6696,2
+6697,0
+6698,3
+6699,0
+6700,2
+6701,0
+6702,3
+6703,1
+6704,0
+6705,2
+6706,1
+6707,2
+6708,1
+6709,3
+6710,0
+6711,2
+6712,0
+6713,2
+6714,0
+6715,0
+6716,3
+6717,3
+6718,2
+6719,2
+6720,2
+6721,0
+6722,0
+6723,0
+6724,0
+6725,0
+6726,0
+6727,1
+6728,1
+6729,0
+6730,0
+6731,1
+6732,2
+6733,0
+6734,0
+6735,2
+6736,2
+6737,0
+6738,0
+6739,0
+6740,0
+6741,1
+6742,1
+6743,1
+6744,0
+6745,3
+6746,3
+6747,0
+6748,1
+6749,0
+6750,0
+6751,3
+6752,0
+6753,0
+6754,3
+6755,0
+6756,3
+6757,2
+6758,1
+6759,3
+6760,0
+6761,3
+6762,2
+6763,0
+6764,3
+6765,0
+6766,3
+6767,3
+6768,0
+6769,3
+6770,2
+6771,2
+6772,2
+6773,2
+6774,0
+6775,3
+6776,0
+6777,0
+6778,1
+6779,2
+6780,3
+6781,3
+6782,2
+6783,1
+6784,2
+6785,0
+6786,3
+6787,3
+6788,1
+6789,0
+6790,2
+6791,0
+6792,2
+6793,2
+6794,0
+6795,0
+6796,0
+6797,0
+6798,0
+6799,0
+6800,0
+6801,0
+6802,0
+6803,0
+6804,0
+6805,0
+6806,0
+6807,3
+6808,0
+6809,1
+6810,0
+6811,1
+6812,0
+6813,2
+6814,3
+6815,1
+6816,2
+6817,1
+6818,3
+6819,0
+6820,1
+6821,1
+6822,3
+6823,0
+6824,0
+6825,2
+6826,2
+6827,3
+6828,0
+6829,0
+6830,3
+6831,0
+6832,0
+6833,2
+6834,1
+6835,0
+6836,3
+6837,2
+6838,0
+6839,3
+6840,0
+6841,0
+6842,3
+6843,1
+6844,0
+6845,3
+6846,0
+6847,0
+6848,0
+6849,3
+6850,2
+6851,0
+6852,2
+6853,3
+6854,3
+6855,0
+6856,0
+6857,3
+6858,3
+6859,0
+6860,0
+6861,3
+6862,3
+6863,0
+6864,0
+6865,1
+6866,2
+6867,3
+6868,2
+6869,1
+6870,1
+6871,3
+6872,2
+6873,0
+6874,1
+6875,0
+6876,0
+6877,2
+6878,0
+6879,1
+6880,3
+6881,3
+6882,3
+6883,1
+6884,2
+6885,0
+6886,0
+6887,0
+6888,0
+6889,1
+6890,3
+6891,0
+6892,1
+6893,3
+6894,3
+6895,3
+6896,1
+6897,1
+6898,0
+6899,1
+6900,2
+6901,2
+6902,0
+6903,1
+6904,0
+6905,2
+6906,2
+6907,0
+6908,0
+6909,2
+6910,0
+6911,0
+6912,0
+6913,1
+6914,3
+6915,1
+6916,3
+6917,1
+6918,3
+6919,2
+6920,0
+6921,1
+6922,0
+6923,1
+6924,0
+6925,2
+6926,2
+6927,0
+6928,2
+6929,1
+6930,0
+6931,1
+6932,0
+6933,3
+6934,3
+6935,3
+6936,3
+6937,0
+6938,0
+6939,0
+6940,2
+6941,0
+6942,1
+6943,0
+6944,0
+6945,0
+6946,2
+6947,3
+6948,2
+6949,1
+6950,3
+6951,2
+6952,2
+6953,2
+6954,0
+6955,1
+6956,0
+6957,2
+6958,0
+6959,0
+6960,0
+6961,3
+6962,2
+6963,0
+6964,3
+6965,1
+6966,2
+6967,0
+6968,0
+6969,3
+6970,3
+6971,0
+6972,0
+6973,0
+6974,0
+6975,0
+6976,0
+6977,0
+6978,3
+6979,0
+6980,0
+6981,0
+6982,0
+6983,2
+6984,3
+6985,3
+6986,3
+6987,0
+6988,0
+6989,1
+6990,0
+6991,2
+6992,2
+6993,3
+6994,2
+6995,0
+6996,1
+6997,1
+6998,2
+6999,1
+7000,2
+7001,2
+7002,0
+7003,3
+7004,0
+7005,1
+7006,0
+7007,0
+7008,0
+7009,0
+7010,2
+7011,1
+7012,0
+7013,0
+7014,0
+7015,0
+7016,2
+7017,0
+7018,0
+7019,0
+7020,2
+7021,0
+7022,0
+7023,2
+7024,0
+7025,1
+7026,0
+7027,0
+7028,2
+7029,1
+7030,0
+7031,2
+7032,3
+7033,3
+7034,0
+7035,3
+7036,3
+7037,2
+7038,0
+7039,0
+7040,0
+7041,2
+7042,0
+7043,0
+7044,3
+7045,0
+7046,0
+7047,3
+7048,1
+7049,2
+7050,1
+7051,1
+7052,1
+7053,0
+7054,0
+7055,0
+7056,0
+7057,0
+7058,1
+7059,0
+7060,0
+7061,2
+7062,2
+7063,0
+7064,0
+7065,2
+7066,0
+7067,2
+7068,2
+7069,0
+7070,0
+7071,2
+7072,2
+7073,2
+7074,2
+7075,0
+7076,0
+7077,0
+7078,3
+7079,3
+7080,2
+7081,2
+7082,1
+7083,0
+7084,2
+7085,0
+7086,1
+7087,2
+7088,2
+7089,1
+7090,0
+7091,2
+7092,0
+7093,3
+7094,2
+7095,3
+7096,0
+7097,0
+7098,0
+7099,2
+7100,1
+7101,3
+7102,0
+7103,2
+7104,2
+7105,0
+7106,1
+7107,2
+7108,3
+7109,3
+7110,0
+7111,1
+7112,2
+7113,0
+7114,3
+7115,0
+7116,0
+7117,3
+7118,0
+7119,0
+7120,0
+7121,3
+7122,0
+7123,0
+7124,3
+7125,2
+7126,2
+7127,1
+7128,0
+7129,0
+7130,0
+7131,2
+7132,2
+7133,0
+7134,0
+7135,1
+7136,1
+7137,0
+7138,0
+7139,2
+7140,1
+7141,1
+7142,0
+7143,3
+7144,0
+7145,3
+7146,0
+7147,2
+7148,0
+7149,0
+7150,3
+7151,3
+7152,3
+7153,0
+7154,2
+7155,0
+7156,2
+7157,3
+7158,3
+7159,0
+7160,1
+7161,1
+7162,1
+7163,2
+7164,3
+7165,0
+7166,1
+7167,0
+7168,0
+7169,0
+7170,2
+7171,0
+7172,0
+7173,3
+7174,3
+7175,3
+7176,2
+7177,2
+7178,0
+7179,3
+7180,0
+7181,2
+7182,1
+7183,3
+7184,0
+7185,0
+7186,0
+7187,3
+7188,0
+7189,3
+7190,0
+7191,3
+7192,0
+7193,2
+7194,3
+7195,0
+7196,2
+7197,0
+7198,0
+7199,0
+7200,1
+7201,0
+7202,3
+7203,0
+7204,0
+7205,0
+7206,2
+7207,0
+7208,0
+7209,2
+7210,1
+7211,3
+7212,3
+7213,3
+7214,0
+7215,0
+7216,0
+7217,1
+7218,0
+7219,1
+7220,1
+7221,0
+7222,1
+7223,2
+7224,0
+7225,0
+7226,3
+7227,3
+7228,2
+7229,0
+7230,2
+7231,2
+7232,2
+7233,0
+7234,0
+7235,0
+7236,1
+7237,0
+7238,1
+7239,3
+7240,1
+7241,3
+7242,3
+7243,2
+7244,2
+7245,3
+7246,2
+7247,2
+7248,0
+7249,1
+7250,0
+7251,2
+7252,1
+7253,2
+7254,2
+7255,2
+7256,2
+7257,3
+7258,0
+7259,0
+7260,0
+7261,0
+7262,2
+7263,1
+7264,0
+7265,0
+7266,1
+7267,0
+7268,0
+7269,3
+7270,1
+7271,2
+7272,0
+7273,3
+7274,2
+7275,1
+7276,3
+7277,0
+7278,0
+7279,2
+7280,1
+7281,3
+7282,1
+7283,0
+7284,3
+7285,0
+7286,1
+7287,3
+7288,0
+7289,1
+7290,3
+7291,0
+7292,1
+7293,0
+7294,2
+7295,2
+7296,2
+7297,0
+7298,0
+7299,1
+7300,2
+7301,1
+7302,2
+7303,0
+7304,1
+7305,0
+7306,3
+7307,0
+7308,1
+7309,0
+7310,0
+7311,2
+7312,3
+7313,1
+7314,3
+7315,0
+7316,1
+7317,1
+7318,1
+7319,0
+7320,0
+7321,2
+7322,0
+7323,3
+7324,0
+7325,0
+7326,0
+7327,2
+7328,3
+7329,0
+7330,0
+7331,0
+7332,3
+7333,3
+7334,0
+7335,1
+7336,0
+7337,3
+7338,3
+7339,2
+7340,2
+7341,1
+7342,0
+7343,1
+7344,3
+7345,3
+7346,0
+7347,2
+7348,3
+7349,1
+7350,0
+7351,3
+7352,2
+7353,0
+7354,2
+7355,0
+7356,1
+7357,1
+7358,0
+7359,3
+7360,0
+7361,0
+7362,1
+7363,3
+7364,0
+7365,1
+7366,2
+7367,0
+7368,0
+7369,2
+7370,3
+7371,1
+7372,0
+7373,3
+7374,0
+7375,1
+7376,2
+7377,0
+7378,2
+7379,0
+7380,0
+7381,2
+7382,0
+7383,1
+7384,2
+7385,2
+7386,2
+7387,0
+7388,0
+7389,2
+7390,0
+7391,0
+7392,1
+7393,0
+7394,3
+7395,2
+7396,1
+7397,2
+7398,0
+7399,3
+7400,2
+7401,2
+7402,0
+7403,1
+7404,0
+7405,0
+7406,1
+7407,0
+7408,0
+7409,2
+7410,2
+7411,3
+7412,0
+7413,0
+7414,0
+7415,3
+7416,3
+7417,0
+7418,2
+7419,1
+7420,0
+7421,0
+7422,3
+7423,3
+7424,1
+7425,0
+7426,0
+7427,0
+7428,3
+7429,0
+7430,3
+7431,2
+7432,3
+7433,2
+7434,0
+7435,1
+7436,0
+7437,0
+7438,0
+7439,2
+7440,0
+7441,2
+7442,3
+7443,3
+7444,1
+7445,0
+7446,0
+7447,0
+7448,0
+7449,0
+7450,1
+7451,2
+7452,3
+7453,0
+7454,0
+7455,0
+7456,3
+7457,0
+7458,2
+7459,0
+7460,0
+7461,0
+7462,0
+7463,0
+7464,3
+7465,3
+7466,2
+7467,0
+7468,0
+7469,3
+7470,3
+7471,3
+7472,2
+7473,1
+7474,0
+7475,0
+7476,1
+7477,2
+7478,0
+7479,0
+7480,0
+7481,0
+7482,3
+7483,0
+7484,2
+7485,3
+7486,2
+7487,2
+7488,0
+7489,0
+7490,0
+7491,0
+7492,2
+7493,0
+7494,3
+7495,0
+7496,0
+7497,3
+7498,0
+7499,3
+7500,0
+7501,0
+7502,0
+7503,3
+7504,1
+7505,0
+7506,0
+7507,0
+7508,0
+7509,2
+7510,3
+7511,0
+7512,3
+7513,3
+7514,1
+7515,2
+7516,1
+7517,2
+7518,0
+7519,3
+7520,1
+7521,3
+7522,0
+7523,3
+7524,0
+7525,1
+7526,0
+7527,3
+7528,0
+7529,0
+7530,2
+7531,2
+7532,0
+7533,2
+7534,0
+7535,2
+7536,3
+7537,2
+7538,0
+7539,0
+7540,0
+7541,2
+7542,0
+7543,0
+7544,0
+7545,2
+7546,0
+7547,0
+7548,3
+7549,0
+7550,2
+7551,0
+7552,0
+7553,2
+7554,3
+7555,0
+7556,0
+7557,0
+7558,3
+7559,1
+7560,0
+7561,2
+7562,0
+7563,3
+7564,3
+7565,3
+7566,2
+7567,0
+7568,0
+7569,0
+7570,0
+7571,3
+7572,0
+7573,2
+7574,2
+7575,1
+7576,3
+7577,0
+7578,1
+7579,0
+7580,0
+7581,0
+7582,2
+7583,1
+7584,0
+7585,0
+7586,0
+7587,1
+7588,0
+7589,0
+7590,0
+7591,0
+7592,2
+7593,0
+7594,3
+7595,0
+7596,2
+7597,1
+7598,1
+7599,0
+7600,3
+7601,3
+7602,0
+7603,0
+7604,1
+7605,0
+7606,3
+7607,2
+7608,0
+7609,0
+7610,3
+7611,0
+7612,0
+7613,0
+7614,0
+7615,3
+7616,2
+7617,0
+7618,0
+7619,1
+7620,0
+7621,1
+7622,0
+7623,3
+7624,0
+7625,1
+7626,3
+7627,0
+7628,3
+7629,0
+7630,0
+7631,0
+7632,1
+7633,3
+7634,0
+7635,1
+7636,0
+7637,1
+7638,2
+7639,3
+7640,2
+7641,2
+7642,0
+7643,2
+7644,0
+7645,2
+7646,3
+7647,1
+7648,2
+7649,0
+7650,1
+7651,0
+7652,2
+7653,1
+7654,2
+7655,0
+7656,0
+7657,3
+7658,0
+7659,0
+7660,2
+7661,0
+7662,0
+7663,3
+7664,2
+7665,0
+7666,2
+7667,0
+7668,0
+7669,3
+7670,2
+7671,0
+7672,0
+7673,2
+7674,2
+7675,2
+7676,0
+7677,0
+7678,1
+7679,3
+7680,0
+7681,1
+7682,3
+7683,0
+7684,2
+7685,0
+7686,0
+7687,2
+7688,0
+7689,1
+7690,0
+7691,1
+7692,0
+7693,2
+7694,3
+7695,3
+7696,0
+7697,0
+7698,0
+7699,2
+7700,2
+7701,2
+7702,3
+7703,0
+7704,0
+7705,2
+7706,0
+7707,3
+7708,3
+7709,0
+7710,2
+7711,0
+7712,0
+7713,2
+7714,3
+7715,1
+7716,3
+7717,0
+7718,3
+7719,3
+7720,0
+7721,0
+7722,0
+7723,1
+7724,0
+7725,2
+7726,0
+7727,0
+7728,0
+7729,1
+7730,0
+7731,3
+7732,3
+7733,0
+7734,2
+7735,1
+7736,2
+7737,1
+7738,1
+7739,0
+7740,3
+7741,3
+7742,0
+7743,0
+7744,3
+7745,0
+7746,0
+7747,3
+7748,1
+7749,3
+7750,0
+7751,3
+7752,0
+7753,2
+7754,0
+7755,0
+7756,1
+7757,1
+7758,1
+7759,1
+7760,3
+7761,0
+7762,2
+7763,0
+7764,0
+7765,0
+7766,3
+7767,2
+7768,3
+7769,3
+7770,0
+7771,3
+7772,0
+7773,0
+7774,3
+7775,2
+7776,1
+7777,3
+7778,1
+7779,3
+7780,3
+7781,0
+7782,0
+7783,1
+7784,2
+7785,1
+7786,2
+7787,3
+7788,1
+7789,0
+7790,3
+7791,0
+7792,2
+7793,3
+7794,0
+7795,3
+7796,2
+7797,2
+7798,0
+7799,0
+7800,0
+7801,3
+7802,3
+7803,3
+7804,0
+7805,3
+7806,1
+7807,0
+7808,3
+7809,0
+7810,3
+7811,0
+7812,2
+7813,1
+7814,0
+7815,2
+7816,0
+7817,1
+7818,2
+7819,3
+7820,0
+7821,0
+7822,0
+7823,3
+7824,0
+7825,3
+7826,0
+7827,3
+7828,3
+7829,1
+7830,0
+7831,0
+7832,0
+7833,1
+7834,0
+7835,0
+7836,3
+7837,0
+7838,0
+7839,1
+7840,1
+7841,0
+7842,2
+7843,0
+7844,0
+7845,0
+7846,3
+7847,0
+7848,0
+7849,0
+7850,2
+7851,0
+7852,0
+7853,1
+7854,0
+7855,3
+7856,1
+7857,0
+7858,0
+7859,3
+7860,0
+7861,0
+7862,0
+7863,0
+7864,3
+7865,0
+7866,1
+7867,0
+7868,3
+7869,3
+7870,0
+7871,0
+7872,0
+7873,2
+7874,3
+7875,3
+7876,2
+7877,0
+7878,2
+7879,0
+7880,2
+7881,1
+7882,0
+7883,0
+7884,2
+7885,0
+7886,0
+7887,2
+7888,2
+7889,1
+7890,0
+7891,3
+7892,1
+7893,2
+7894,0
+7895,0
+7896,0
+7897,1
+7898,2
+7899,3
+7900,0
+7901,0
+7902,1
+7903,1
+7904,0
+7905,1
+7906,2
+7907,0
+7908,0
+7909,3
+7910,1
+7911,2
+7912,2
+7913,2
+7914,0
+7915,3
+7916,3
+7917,0
+7918,0
+7919,0
+7920,1
+7921,0
+7922,3
+7923,0
+7924,1
+7925,0
+7926,1
+7927,2
+7928,1
+7929,0
+7930,0
+7931,1
+7932,3
+7933,2
+7934,1
+7935,0
+7936,1
+7937,0
+7938,0
+7939,0
+7940,3
+7941,0
+7942,0
+7943,1
+7944,2
+7945,0
+7946,2
+7947,0
+7948,0
+7949,2
+7950,0
+7951,0
+7952,0
+7953,1
+7954,0
+7955,3
+7956,3
+7957,3
+7958,3
+7959,2
+7960,3
+7961,0
+7962,1
+7963,3
+7964,0
+7965,0
+7966,0
+7967,0
+7968,1
+7969,0
+7970,2
+7971,2
+7972,2
+7973,3
+7974,0
+7975,3
+7976,0
+7977,2
+7978,1
+7979,1
+7980,0
+7981,0
+7982,2
+7983,3
+7984,3
+7985,0
+7986,0
+7987,2
+7988,2
+7989,0
+7990,3
+7991,2
+7992,0
+7993,0
+7994,0
+7995,1
+7996,1
+7997,2
+7998,1
+7999,0
+8000,0
+8001,0
+8002,1
+8003,3
+8004,0
+8005,3
+8006,2
+8007,2
+8008,1
+8009,1
+8010,2
+8011,3
+8012,0
+8013,3
+8014,3
+8015,0
+8016,3
+8017,3
+8018,0
+8019,0
+8020,3
+8021,0
+8022,0
+8023,3
+8024,0
+8025,0
+8026,2
+8027,1
+8028,3
+8029,0
+8030,2
+8031,2
+8032,2
+8033,2
+8034,0
+8035,0
+8036,3
+8037,2
+8038,0
+8039,3
+8040,3
+8041,0
+8042,3
+8043,0
+8044,2
+8045,3
+8046,0
+8047,0
+8048,0
+8049,2
+8050,0
+8051,3
+8052,2
+8053,0
+8054,0
+8055,1
+8056,2
+8057,3
+8058,0
+8059,1
+8060,1
+8061,1
+8062,0
+8063,0
+8064,3
+8065,2
+8066,0
+8067,0
+8068,1
+8069,0
+8070,3
+8071,0
+8072,1
+8073,1
+8074,2
+8075,2
+8076,0
+8077,0
+8078,0
+8079,0
+8080,0
+8081,0
+8082,1
+8083,3
+8084,3
+8085,0
+8086,3
+8087,0
+8088,0
+8089,0
+8090,0
+8091,0
+8092,0
+8093,0
+8094,0
+8095,0
+8096,2
+8097,2
+8098,0
+8099,3
+8100,3
+8101,2
+8102,2
+8103,0
+8104,0
+8105,3
+8106,1
+8107,0
+8108,3
+8109,2
+8110,1
+8111,0
+8112,0
+8113,3
+8114,2
+8115,1
+8116,1
+8117,0
+8118,2
+8119,0
+8120,0
+8121,0
+8122,2
+8123,2
+8124,0
+8125,3
+8126,0
+8127,1
+8128,0
+8129,0
+8130,1
+8131,0
+8132,3
+8133,1
+8134,1
+8135,1
+8136,2
+8137,2
+8138,1
+8139,1
+8140,0
+8141,2
+8142,2
+8143,0
+8144,0
+8145,1
+8146,1
+8147,2
+8148,3
+8149,3
+8150,3
+8151,3
+8152,1
+8153,0
+8154,2
+8155,2
+8156,0
+8157,0
+8158,0
+8159,2
+8160,0
+8161,2
+8162,2
+8163,2
+8164,3
+8165,3
+8166,3
+8167,3
+8168,0
+8169,3
+8170,0
+8171,1
+8172,1
+8173,0
+8174,3
+8175,1
+8176,0
+8177,3
+8178,0
+8179,3
+8180,1
+8181,0
+8182,1
+8183,3
+8184,3
+8185,2
+8186,2
+8187,2
+8188,3
+8189,2
+8190,3
+8191,0
+8192,0
+8193,0
+8194,1
+8195,1
+8196,1
+8197,0
+8198,2
+8199,3
+8200,3
+8201,0
+8202,3
+8203,3
+8204,1
+8205,0
+8206,2
+8207,0
+8208,3
+8209,0
+8210,0
+8211,1
+8212,3
+8213,0
+8214,0
+8215,0
+8216,0
+8217,2
+8218,1
+8219,0
+8220,0
+8221,3
+8222,2
+8223,0
+8224,0
+8225,0
+8226,1
+8227,0
+8228,0
+8229,0
+8230,0
+8231,0
+8232,3
+8233,0
+8234,2
+8235,3
+8236,3
+8237,0
+8238,2
+8239,0
+8240,0
+8241,0
+8242,0
+8243,0
+8244,0
+8245,0
+8246,3
+8247,0
+8248,2
+8249,3
+8250,0
+8251,0
+8252,1
+8253,2
+8254,0
+8255,3
+8256,0
+8257,0
+8258,0
+8259,3
+8260,3
+8261,3
+8262,1
+8263,0
+8264,0
+8265,3
+8266,3
+8267,0
+8268,2
+8269,3
+8270,2
+8271,0
+8272,0
+8273,3
+8274,0
+8275,3
+8276,3
+8277,0
+8278,2
+8279,0
+8280,2
+8281,0
+8282,0
+8283,3
+8284,2
+8285,0
+8286,0
+8287,2
+8288,2
+8289,0
+8290,0
+8291,0
+8292,0
+8293,1
+8294,0
+8295,0
+8296,1
+8297,1
+8298,0
+8299,1
+8300,3
+8301,0
+8302,0
+8303,1
+8304,0
+8305,0
+8306,2
+8307,2
+8308,3
+8309,0
+8310,3
+8311,3
+8312,0
+8313,0
+8314,0
+8315,3
+8316,0
+8317,2
+8318,3
+8319,0
+8320,0
+8321,0
+8322,0
+8323,0
+8324,2
+8325,2
+8326,0
+8327,3
+8328,2
+8329,0
+8330,2
+8331,3
+8332,3
+8333,1
+8334,0
+8335,0
+8336,3
+8337,2
+8338,0
+8339,3
+8340,0
+8341,1
+8342,2
+8343,0
+8344,1
+8345,0
+8346,0
+8347,0
+8348,3
+8349,2
+8350,3
+8351,3
+8352,3
+8353,2
+8354,0
+8355,0
+8356,2
+8357,3
+8358,0
+8359,3
+8360,0
+8361,3
+8362,3
+8363,2
+8364,3
+8365,0
+8366,2
+8367,2
+8368,2
+8369,1
+8370,3
+8371,0
+8372,3
+8373,1
+8374,3
+8375,3
+8376,0
+8377,2
+8378,2
+8379,0
+8380,2
+8381,3
+8382,0
+8383,0
+8384,3
+8385,0
+8386,2
+8387,3
+8388,1
+8389,2
+8390,2
+8391,1
+8392,3
+8393,0
+8394,0
+8395,2
+8396,3
+8397,0
+8398,0
+8399,2
+8400,0
+8401,1
+8402,3
+8403,3
+8404,3
+8405,0
+8406,2
+8407,0
+8408,0
+8409,0
+8410,0
+8411,3
+8412,2
+8413,1
+8414,3
+8415,2
+8416,0
+8417,0
+8418,3
+8419,0
+8420,3
+8421,2
+8422,2
+8423,2
+8424,3
+8425,0
+8426,0
+8427,0
+8428,0
+8429,2
+8430,3
+8431,1
+8432,2
+8433,0
+8434,0
+8435,3
+8436,1
+8437,0
+8438,0
+8439,3
+8440,0
+8441,0
+8442,2
+8443,2
+8444,1
+8445,2
+8446,1
+8447,0
+8448,2
+8449,0
+8450,0
+8451,3
+8452,0
+8453,2
+8454,1
+8455,0
+8456,1
+8457,0
+8458,0
+8459,0
+8460,0
+8461,2
+8462,0
+8463,3
+8464,1
+8465,0
+8466,2
+8467,0
+8468,3
+8469,2
+8470,0
+8471,1
+8472,0
+8473,1
+8474,3
+8475,0
+8476,0
+8477,3
+8478,2
+8479,2
+8480,0
+8481,0
+8482,3
+8483,2
+8484,2
+8485,3
+8486,2
+8487,2
+8488,1
+8489,0
+8490,2
+8491,1
+8492,2
+8493,2
+8494,0
+8495,0
+8496,0
+8497,2
+8498,0
+8499,0
+8500,3
+8501,2
+8502,2
+8503,2
+8504,1
+8505,2
+8506,0
+8507,0
+8508,1
+8509,3
+8510,0
+8511,0
+8512,3
+8513,0
+8514,0
+8515,0
+8516,3
+8517,0
+8518,3
+8519,3
+8520,3
+8521,0
+8522,0
+8523,1
+8524,2
+8525,1
+8526,0
+8527,2
+8528,1
+8529,0
+8530,0
+8531,2
+8532,1
+8533,3
+8534,3
+8535,2
+8536,2
+8537,0
+8538,2
+8539,2
+8540,0
+8541,2
+8542,3
+8543,2
+8544,0
+8545,0
+8546,0
+8547,2
+8548,0
+8549,3
+8550,0
+8551,0
+8552,3
+8553,2
+8554,0
+8555,1
+8556,2
+8557,0
+8558,0
+8559,3
+8560,3
+8561,1
+8562,0
+8563,0
+8564,2
+8565,0
+8566,0
+8567,0
+8568,3
+8569,3
+8570,3
+8571,2
+8572,3
+8573,0
+8574,1
+8575,0
+8576,2
+8577,0
+8578,0
+8579,1
+8580,3
+8581,2
+8582,3
+8583,3
+8584,0
+8585,3
+8586,0
+8587,0
+8588,0
+8589,2
+8590,2
+8591,2
+8592,1
+8593,3
+8594,2
+8595,1
+8596,0
+8597,0
+8598,2
+8599,3
+8600,0
+8601,3
+8602,0
+8603,3
+8604,3
+8605,1
+8606,0
+8607,0
+8608,1
+8609,2
+8610,1
+8611,0
+8612,0
+8613,0
+8614,0
+8615,3
+8616,2
+8617,0
+8618,0
+8619,1
+8620,0
+8621,3
+8622,0
+8623,2
+8624,0
+8625,3
+8626,0
+8627,0
+8628,3
+8629,0
+8630,0
+8631,0
+8632,0
+8633,1
+8634,3
+8635,2
+8636,0
+8637,3
+8638,0
+8639,0
+8640,0
+8641,0
+8642,3
+8643,2
+8644,3
+8645,1
+8646,1
+8647,0
+8648,1
+8649,0
+8650,2
+8651,3
+8652,1
+8653,0
+8654,0
+8655,0
+8656,2
+8657,3
+8658,2
+8659,3
+8660,0
+8661,3
+8662,2
+8663,0
+8664,0
+8665,1
+8666,0
+8667,1
+8668,0
+8669,0
+8670,2
+8671,0
+8672,3
+8673,0
+8674,0
+8675,0
+8676,0
+8677,1
+8678,3
+8679,1
+8680,0
+8681,0
+8682,0
+8683,3
+8684,0
+8685,0
+8686,2
+8687,0
+8688,0
+8689,0
+8690,0
+8691,0
+8692,2
+8693,0
+8694,0
+8695,1
+8696,0
+8697,2
+8698,0
+8699,2
+8700,0
+8701,0
+8702,2
+8703,1
+8704,2
+8705,0
+8706,0
+8707,0
+8708,0
+8709,0
+8710,0
+8711,0
+8712,2
+8713,0
+8714,1
+8715,0
+8716,0
+8717,3
+8718,0
+8719,0
+8720,3
+8721,2
+8722,2
+8723,0
+8724,3
+8725,0
+8726,0
+8727,0
+8728,0
+8729,2
+8730,1
+8731,0
+8732,0
+8733,0
+8734,0
+8735,0
+8736,0
+8737,0
+8738,0
+8739,3
+8740,0
+8741,0
+8742,0
+8743,0
+8744,3
+8745,0
+8746,1
+8747,0
+8748,1
+8749,0
+8750,2
+8751,2
+8752,0
+8753,0
+8754,0
+8755,0
+8756,3
+8757,3
+8758,3
+8759,1
+8760,0
+8761,0
+8762,2
+8763,1
+8764,3
+8765,0
+8766,0
+8767,2
+8768,3
+8769,3
+8770,0
+8771,0
+8772,3
+8773,3
+8774,3
+8775,0
+8776,3
+8777,2
+8778,1
+8779,3
+8780,2
+8781,0
+8782,0
+8783,0
+8784,2
+8785,0
+8786,0
+8787,1
+8788,3
+8789,0
+8790,3
+8791,3
+8792,2
+8793,0
+8794,0
+8795,3
+8796,0
+8797,0
+8798,0
+8799,2
+8800,2
+8801,3
+8802,3
+8803,0
+8804,0
+8805,3
+8806,0
+8807,0
+8808,0
+8809,0
+8810,1
+8811,0
+8812,3
+8813,2
+8814,2
+8815,0
+8816,0
+8817,0
+8818,3
+8819,2
+8820,2
+8821,0
+8822,0
+8823,0
+8824,0
+8825,3
+8826,3
+8827,2
+8828,3
+8829,2
+8830,0
+8831,2
+8832,2
+8833,0
+8834,1
+8835,0
+8836,2
+8837,0
+8838,2
+8839,0
+8840,0
+8841,3
+8842,0
+8843,3
+8844,2
+8845,0
+8846,3
+8847,3
+8848,3
+8849,3
+8850,2
+8851,0
+8852,2
+8853,3
+8854,3
+8855,0
+8856,0
+8857,0
+8858,0
+8859,0
+8860,3
+8861,3
+8862,3
+8863,2
+8864,0
+8865,0
+8866,3
+8867,1
+8868,3
+8869,0
+8870,0
+8871,0
+8872,2
+8873,0
+8874,0
+8875,3
+8876,1
+8877,3
+8878,1
+8879,0
+8880,2
+8881,0
+8882,2
+8883,3
+8884,0
+8885,1
+8886,0
+8887,0
+8888,0
+8889,0
+8890,3
+8891,0
+8892,0
+8893,0
+8894,1
+8895,1
+8896,2
+8897,0
+8898,3
+8899,1
+8900,3
+8901,0
+8902,2
+8903,1
+8904,2
+8905,0
+8906,0
+8907,0
+8908,0
+8909,0
+8910,3
+8911,0
+8912,2
+8913,3
+8914,2
+8915,3
+8916,2
+8917,0
+8918,2
+8919,0
+8920,0
+8921,1
+8922,3
+8923,2
+8924,0
+8925,3
+8926,0
+8927,3
+8928,1
+8929,1
+8930,1
+8931,0
+8932,0
+8933,2
+8934,3
+8935,2
+8936,1
+8937,2
+8938,3
+8939,2
+8940,1
+8941,2
+8942,3
+8943,2
+8944,2
+8945,0
+8946,1
+8947,1
+8948,2
+8949,3
+8950,0
+8951,0
+8952,3
+8953,2
+8954,1
+8955,0
+8956,3
+8957,0
+8958,3
+8959,0
+8960,0
+8961,2
+8962,3
+8963,0
+8964,2
+8965,1
+8966,0
+8967,0
+8968,1
+8969,2
+8970,2
+8971,2
+8972,3
+8973,3
+8974,3
+8975,0
+8976,1
+8977,0
+8978,3
+8979,0
+8980,0
+8981,3
+8982,1
+8983,0
+8984,1
+8985,0
+8986,0
+8987,0
+8988,2
+8989,0
+8990,3
+8991,0
+8992,0
+8993,3
+8994,0
+8995,0
+8996,3
+8997,1
+8998,0
+8999,0
+9000,2
+9001,1
+9002,3
+9003,0
+9004,0
+9005,0
+9006,1
+9007,2
+9008,0
+9009,0
+9010,3
+9011,3
+9012,0
+9013,0
+9014,0
+9015,3
+9016,3
+9017,0
+9018,2
+9019,3
+9020,0
+9021,2
+9022,2
+9023,2
+9024,2
+9025,3
+9026,2
+9027,1
+9028,2
+9029,2
+9030,0
+9031,1
+9032,0
+9033,0
+9034,3
+9035,0
+9036,3
+9037,2
+9038,1
+9039,0
+9040,0
+9041,0
+9042,0
+9043,0
+9044,0
+9045,2
+9046,0
+9047,1
+9048,0
+9049,3
+9050,2
+9051,2
+9052,0
+9053,0
+9054,1
+9055,3
+9056,0
+9057,2
+9058,3
+9059,2
+9060,0
+9061,2
+9062,1
+9063,3
+9064,0
+9065,0
+9066,0
+9067,3
+9068,0
+9069,0
+9070,0
+9071,0
+9072,0
+9073,1
+9074,0
+9075,1
+9076,0
+9077,3
+9078,0
+9079,0
+9080,3
+9081,0
+9082,0
+9083,0
+9084,1
+9085,0
+9086,0
+9087,1
+9088,1
+9089,2
+9090,3
+9091,0
+9092,0
+9093,0
+9094,3
+9095,0
+9096,3
+9097,0
+9098,1
+9099,2
+9100,0
+9101,3
+9102,2
+9103,0
+9104,0
+9105,1
+9106,0
+9107,0
+9108,0
+9109,2
+9110,0
+9111,0
+9112,0
+9113,3
+9114,3
+9115,3
+9116,0
+9117,1
+9118,0
+9119,1
+9120,0
+9121,2
+9122,1
+9123,1
+9124,3
+9125,1
+9126,2
+9127,1
+9128,3
+9129,1
+9130,0
+9131,0
+9132,0
+9133,3
+9134,0
+9135,1
+9136,0
+9137,2
+9138,3
+9139,0
+9140,3
+9141,2
+9142,0
+9143,3
+9144,0
+9145,0
+9146,2
+9147,2
+9148,2
+9149,0
+9150,1
+9151,0
+9152,0
+9153,3
+9154,3
+9155,2
+9156,2
+9157,3
+9158,2
+9159,3
+9160,0
+9161,3
+9162,3
+9163,3
+9164,1
+9165,1
+9166,0
+9167,0
+9168,2
+9169,0
+9170,0
+9171,1
+9172,2
+9173,3
+9174,1
+9175,0
+9176,2
+9177,0
+9178,1
+9179,0
+9180,0
+9181,1
+9182,3
+9183,2
+9184,0
+9185,1
+9186,3
+9187,3
+9188,0
+9189,3
+9190,0
+9191,0
+9192,0
+9193,0
+9194,0
+9195,0
+9196,2
+9197,1
+9198,1
+9199,2
+9200,3
+9201,0
+9202,0
+9203,3
+9204,1
+9205,0
+9206,3
+9207,3
+9208,0
+9209,0
+9210,0
+9211,0
+9212,3
+9213,0
+9214,2
+9215,2
+9216,0
+9217,0
+9218,0
+9219,2
+9220,2
+9221,0
+9222,1
+9223,2
+9224,0
+9225,0
+9226,0
+9227,0
+9228,0
+9229,1
+9230,3
+9231,0
+9232,0
+9233,2
+9234,0
+9235,1
+9236,2
+9237,1
+9238,3
+9239,0
+9240,3
+9241,2
+9242,3
+9243,1
+9244,3
+9245,1
+9246,0
+9247,3
+9248,3
+9249,1
+9250,0
+9251,0
+9252,2
+9253,3
+9254,0
+9255,2
+9256,1
+9257,0
+9258,1
+9259,2
+9260,2
+9261,0
+9262,0
+9263,2
+9264,1
+9265,0
+9266,3
+9267,3
+9268,0
+9269,0
+9270,3
+9271,1
+9272,0
+9273,1
+9274,2
+9275,0
+9276,3
+9277,0
+9278,1
+9279,0
+9280,0
+9281,1
+9282,1
+9283,1
+9284,0
+9285,0
+9286,2
+9287,0
+9288,2
+9289,2
+9290,2
+9291,1
+9292,3
+9293,0
+9294,3
+9295,2
+9296,0
+9297,3
+9298,0
+9299,2
+9300,2
+9301,0
+9302,0
+9303,3
+9304,1
+9305,0
+9306,1
+9307,2
+9308,3
+9309,3
+9310,1
+9311,3
+9312,3
+9313,2
+9314,3
+9315,0
+9316,2
+9317,3
+9318,0
+9319,0
+9320,1
+9321,2
+9322,2
+9323,2
+9324,0
+9325,0
+9326,3
+9327,2
+9328,0
+9329,0
+9330,2
+9331,2
+9332,3
+9333,3
+9334,0
+9335,2
+9336,3
+9337,2
+9338,0
+9339,0
+9340,3
+9341,0
+9342,0
+9343,2
+9344,0
+9345,3
+9346,0
+9347,0
+9348,3
+9349,3
+9350,2
+9351,3
+9352,2
+9353,0
+9354,2
+9355,1
+9356,2
+9357,0
+9358,0
+9359,3
+9360,3
+9361,0
+9362,0
+9363,1
+9364,3
+9365,0
+9366,0
+9367,0
+9368,0
+9369,1
+9370,2
+9371,2
+9372,3
+9373,3
+9374,3
+9375,1
+9376,0
+9377,2
+9378,2
+9379,0
+9380,3
+9381,1
+9382,0
+9383,0
+9384,0
+9385,0
+9386,3
+9387,2
+9388,3
+9389,3
+9390,0
+9391,0
+9392,0
+9393,3
+9394,2
+9395,0
+9396,0
+9397,1
+9398,1
+9399,0
+9400,2
+9401,0
+9402,3
+9403,2
+9404,0
+9405,0
+9406,0
+9407,3
+9408,0
+9409,3
+9410,3
+9411,1
+9412,1
+9413,0
+9414,0
+9415,0
+9416,2
+9417,2
+9418,0
+9419,2
+9420,0
+9421,0
+9422,2
+9423,2
+9424,3
+9425,0
+9426,0
+9427,2
+9428,0
+9429,0
+9430,0
+9431,2
+9432,2
+9433,0
+9434,3
+9435,0
+9436,0
+9437,2
+9438,0
+9439,3
+9440,0
+9441,0
+9442,0
+9443,0
+9444,0
+9445,1
+9446,0
+9447,1
+9448,1
+9449,0
+9450,0
+9451,0
+9452,0
+9453,1
+9454,0
+9455,0
+9456,0
+9457,3
+9458,2
+9459,0
+9460,0
+9461,0
+9462,0
+9463,0
+9464,3
+9465,0
+9466,2
+9467,1
+9468,2
+9469,2
+9470,2
+9471,3
+9472,0
+9473,3
+9474,2
+9475,0
+9476,0
+9477,0
+9478,1
+9479,2
+9480,0
+9481,3
+9482,3
+9483,2
+9484,1
+9485,3
+9486,3
+9487,3
+9488,2
+9489,0
+9490,3
+9491,1
+9492,0
+9493,0
+9494,1
+9495,0
+9496,1
+9497,2
+9498,2
+9499,0
+9500,0
+9501,1
+9502,2
+9503,0
+9504,0
+9505,0
+9506,0
+9507,1
+9508,0
+9509,2
+9510,0
+9511,3
+9512,2
+9513,2
+9514,3
+9515,2
+9516,2
+9517,0
+9518,0
+9519,1
+9520,3
+9521,0
+9522,1
+9523,1
+9524,0
+9525,0
+9526,2
+9527,0
+9528,0
+9529,0
+9530,3
+9531,0
+9532,2
+9533,2
+9534,1
+9535,0
+9536,3
+9537,3
+9538,0
+9539,0
+9540,0
+9541,3
+9542,0
+9543,1
+9544,2
+9545,3
+9546,0
+9547,1
+9548,3
+9549,3
+9550,2
+9551,2
+9552,0
+9553,0
+9554,1
+9555,3
+9556,3
+9557,0
+9558,1
+9559,3
+9560,3
+9561,1
+9562,2
+9563,3
+9564,2
+9565,0
+9566,2
+9567,3
+9568,0
+9569,0
+9570,1
+9571,2
+9572,1
+9573,0
+9574,0
+9575,0
+9576,0
+9577,0
+9578,2
+9579,1
+9580,0
+9581,1
+9582,0
+9583,3
+9584,3
+9585,2
+9586,0
+9587,0
+9588,0
+9589,3
+9590,0
+9591,3
+9592,2
+9593,1
+9594,3
+9595,3
+9596,0
+9597,3
+9598,0
+9599,1
+9600,0
+9601,0
+9602,1
+9603,1
+9604,0
+9605,2
+9606,0
+9607,3
+9608,3
+9609,2
+9610,2
+9611,0
+9612,0
+9613,0
+9614,1
+9615,0
+9616,2
+9617,0
+9618,0
+9619,1
+9620,2
+9621,0
+9622,0
+9623,0
+9624,2
+9625,2
+9626,1
+9627,0
+9628,3
+9629,3
+9630,1
+9631,1
+9632,0
+9633,3
+9634,0
+9635,0
+9636,0
+9637,0
+9638,2
+9639,0
+9640,3
+9641,0
+9642,2
+9643,0
+9644,0
+9645,0
+9646,1
+9647,3
+9648,2
+9649,0
+9650,1
+9651,3
+9652,2
+9653,3
+9654,1
+9655,3
+9656,0
+9657,2
+9658,2
+9659,0
+9660,0
+9661,0
+9662,0
+9663,0
+9664,0
+9665,1
+9666,2
+9667,3
+9668,3
+9669,0
+9670,2
+9671,2
+9672,0
+9673,0
+9674,3
+9675,0
+9676,2
+9677,0
+9678,3
+9679,0
+9680,1
+9681,0
+9682,3
+9683,2
+9684,2
+9685,2
+9686,2
+9687,0
+9688,0
+9689,0
+9690,3
+9691,1
+9692,3
+9693,0
+9694,0
+9695,0
+9696,3
+9697,0
+9698,3
+9699,2
+9700,2
+9701,0
+9702,0
+9703,2
+9704,1
+9705,3
+9706,2
+9707,0
+9708,3
+9709,0
+9710,1
+9711,3
+9712,3
+9713,3
+9714,3
+9715,0
+9716,0
+9717,2
+9718,0
+9719,3
+9720,2
+9721,0
+9722,3
+9723,3
+9724,0
+9725,0
+9726,0
+9727,0
+9728,3
+9729,0
+9730,1
+9731,0
+9732,3
+9733,0
+9734,0
+9735,1
+9736,1
+9737,3
+9738,0
+9739,2
+9740,3
+9741,3
+9742,1
+9743,2
+9744,2
+9745,0
+9746,0
+9747,3
+9748,1
+9749,0
+9750,2
+9751,0
+9752,0
+9753,0
+9754,1
+9755,2
+9756,3
+9757,3
+9758,3
+9759,0
+9760,0
+9761,3
+9762,0
+9763,3
+9764,0
+9765,1
+9766,3
+9767,2
+9768,2
+9769,0
+9770,3
+9771,1
+9772,2
+9773,2
+9774,0
+9775,0
+9776,3
+9777,3
+9778,1
+9779,0
+9780,1
+9781,0
+9782,0
+9783,0
+9784,0
+9785,0
+9786,0
+9787,0
+9788,0
+9789,0
+9790,1
+9791,0
+9792,3
+9793,3
+9794,1
+9795,2
+9796,0
+9797,0
+9798,2
+9799,0
+9800,0
+9801,1
+9802,0
+9803,3
+9804,0
+9805,3
+9806,0
+9807,0
+9808,0
+9809,0
+9810,3
+9811,3
+9812,1
+9813,2
+9814,2
+9815,3
+9816,0
+9817,1
+9818,2
+9819,2
+9820,1
+9821,0
+9822,0
+9823,2
+9824,0
+9825,0
+9826,2
+9827,2
+9828,0
+9829,0
+9830,0
+9831,0
+9832,0
+9833,0
+9834,3
+9835,0
+9836,0
+9837,2
+9838,0
+9839,3
+9840,0
+9841,1
+9842,1
+9843,3
+9844,2
+9845,3
+9846,0
+9847,0
+9848,0
+9849,2
+9850,0
+9851,1
+9852,0
+9853,3
+9854,3
+9855,0
+9856,0
+9857,0
+9858,0
+9859,3
+9860,2
+9861,1
+9862,0
+9863,2
+9864,2
+9865,0
+9866,0
+9867,0
+9868,0
+9869,0
+9870,0
+9871,2
+9872,0
+9873,2
+9874,0
+9875,0
+9876,0
+9877,0
+9878,1
+9879,2
+9880,1
+9881,2
+9882,3
+9883,3
+9884,1
+9885,1
+9886,0
+9887,2
+9888,2
+9889,3
+9890,3
+9891,0
+9892,0
+9893,2
+9894,3
+9895,0
+9896,1
+9897,0
+9898,3
+9899,0
+9900,0
+9901,0
+9902,0
+9903,3
+9904,0
+9905,2
+9906,0
+9907,2
+9908,2
+9909,0
+9910,0
+9911,0
+9912,0
+9913,2
+9914,0
+9915,3
+9916,0
+9917,3
+9918,1
+9919,0
+9920,2
+9921,3
+9922,1
+9923,3
+9924,2
+9925,3
+9926,3
+9927,0
+9928,0
+9929,3
+9930,1
+9931,0
+9932,2
+9933,3
+9934,0
+9935,1
+9936,0
+9937,0
+9938,0
+9939,0
+9940,3
+9941,1
+9942,0
+9943,3
+9944,3
+9945,3
+9946,0
+9947,0
+9948,0
+9949,1
+9950,1
+9951,1
+9952,3
+9953,3
+9954,1
+9955,1
+9956,2
+9957,1
+9958,2
+9959,0
+9960,0
+9961,0
+9962,0
+9963,2
+9964,2
+9965,0
+9966,2
+9967,0
+9968,0
+9969,3
+9970,0
+9971,1
+9972,1
+9973,3
+9974,0
+9975,0
+9976,1
+9977,1
+9978,3
+9979,0
+9980,3
+9981,0
+9982,0
+9983,0
+9984,2
+9985,3
+9986,3
+9987,2
+9988,1
+9989,2
+9990,1
+9991,1
+9992,1
+9993,3
+9994,2
+9995,3
+9996,0
+9997,0
+9998,0
+9999,0
+10000,0
+10001,0
+10002,0
+10003,0
+10004,0
+10005,2
+10006,3
+10007,0
+10008,0
+10009,2
+10010,3
+10011,3
+10012,1
+10013,0
+10014,0
+10015,2
+10016,3
+10017,0
+10018,3
+10019,2
+10020,3
+10021,0
+10022,3
+10023,1
+10024,1
+10025,0
+10026,1
+10027,0
+10028,2
+10029,0
+10030,0
+10031,3
+10032,3
+10033,2
+10034,3
+10035,2
+10036,1
+10037,0
+10038,0
+10039,0
+10040,0
+10041,2
+10042,2
+10043,3
+10044,2
+10045,3
+10046,3
+10047,1
+10048,0
+10049,2
+10050,0
+10051,1
+10052,0
+10053,3
+10054,0
+10055,1
+10056,0
+10057,3
+10058,2
+10059,0
+10060,1
+10061,2
+10062,3
+10063,3
+10064,1
+10065,2
+10066,1
+10067,2
+10068,1
+10069,0
+10070,1
+10071,0
+10072,0
+10073,0
+10074,3
+10075,0
+10076,0
+10077,3
+10078,3
+10079,3
+10080,2
+10081,1
+10082,2
+10083,0
+10084,1
+10085,3
+10086,0
+10087,1
+10088,1
+10089,2
+10090,1
+10091,2
+10092,0
+10093,2
+10094,2
+10095,0
+10096,2
+10097,3
+10098,2
+10099,3
+10100,3
+10101,3
+10102,1
+10103,0
+10104,3
+10105,0
+10106,0
+10107,1
+10108,0
+10109,3
+10110,2
+10111,0
+10112,0
+10113,2
+10114,0
+10115,2
+10116,2
+10117,2
+10118,0
+10119,2
+10120,2
+10121,1
+10122,0
+10123,0
+10124,3
+10125,3
+10126,3
+10127,3
+10128,0
+10129,0
+10130,0
+10131,3
+10132,2
+10133,0
+10134,0
+10135,1
+10136,0
+10137,0
+10138,0
+10139,0
+10140,0
+10141,0
+10142,1
+10143,0
+10144,0
+10145,2
+10146,0
+10147,0
+10148,2
+10149,0
+10150,2
+10151,0
+10152,3
+10153,2
+10154,0
+10155,0
+10156,0
+10157,3
+10158,0
+10159,3
+10160,0
+10161,3
+10162,1
+10163,0
+10164,2
+10165,0
+10166,0
+10167,0
+10168,0
+10169,0
+10170,0
+10171,0
+10172,3
+10173,3
+10174,3
+10175,2
+10176,3
+10177,1
+10178,1
+10179,1
+10180,3
+10181,0
+10182,0
+10183,0
+10184,0
+10185,2
+10186,2
+10187,3
+10188,0
+10189,3
+10190,0
+10191,0
+10192,2
+10193,3
+10194,2
+10195,0
+10196,2
+10197,3
+10198,0
+10199,2
+10200,0
+10201,2
+10202,1
+10203,2
+10204,0
+10205,1
+10206,0
+10207,0
+10208,2
+10209,0
+10210,3
+10211,0
+10212,0
+10213,0
+10214,0
+10215,0
+10216,3
+10217,0
+10218,0
+10219,1
+10220,3
+10221,3
+10222,3
+10223,0
+10224,3
+10225,0
+10226,0
+10227,0
+10228,2
+10229,2
+10230,0
+10231,0
+10232,0
+10233,1
+10234,0
+10235,3
+10236,3
+10237,0
+10238,1
+10239,3
+10240,2
+10241,2
+10242,0
+10243,2
+10244,0
+10245,3
+10246,1
+10247,0
+10248,0
+10249,2
+10250,3
+10251,2
+10252,0
+10253,3
+10254,3
+10255,2
+10256,0
+10257,3
+10258,0
+10259,0
+10260,0
+10261,0
+10262,0
+10263,0
+10264,0
+10265,2
+10266,0
+10267,0
+10268,2
+10269,0
+10270,0
+10271,0
+10272,0
+10273,0
+10274,1
+10275,1
+10276,0
+10277,3
+10278,0
+10279,0
+10280,2
+10281,3
+10282,1
+10283,1
+10284,0
+10285,2
+10286,0
+10287,3
+10288,0
+10289,3
+10290,2
+10291,0
+10292,2
+10293,3
+10294,3
+10295,2
+10296,2
+10297,0
+10298,0
+10299,0
+10300,3
+10301,3
+10302,2
+10303,0
+10304,0
+10305,2
+10306,0
+10307,3
+10308,0
+10309,3
+10310,3
+10311,0
+10312,1
+10313,0
+10314,1
+10315,0
+10316,0
+10317,2
+10318,0
+10319,1
+10320,1
+10321,0
+10322,0
+10323,0
+10324,0
+10325,2
+10326,3
+10327,3
+10328,3
+10329,3
+10330,0
+10331,0
+10332,1
+10333,1
+10334,1
+10335,0
+10336,0
+10337,2
+10338,0
+10339,0
+10340,3
+10341,2
+10342,0
+10343,2
+10344,2
+10345,0
+10346,0
+10347,2
+10348,2
+10349,0
+10350,0
+10351,0
+10352,0
+10353,0
+10354,0
+10355,2
+10356,0
+10357,0
+10358,0
+10359,0
+10360,0
+10361,1
+10362,0
+10363,2
+10364,2
+10365,1
+10366,0
+10367,0
+10368,2
+10369,0
+10370,2
+10371,0
+10372,0
+10373,3
+10374,0
+10375,2
+10376,0
+10377,3
+10378,0
+10379,3
+10380,0
+10381,2
+10382,2
+10383,0
+10384,1
+10385,0
+10386,0
+10387,3
+10388,0
+10389,1
+10390,3
+10391,0
+10392,0
+10393,0
+10394,2
+10395,0
+10396,2
+10397,0
+10398,0
+10399,0
+10400,2
+10401,0
+10402,3
+10403,0
+10404,3
+10405,0
+10406,2
+10407,3
+10408,0
+10409,0
+10410,0
+10411,1
+10412,3
+10413,0
+10414,1
+10415,0
+10416,0
+10417,2
+10418,2
+10419,1
+10420,0
+10421,1
+10422,0
+10423,0
+10424,1
+10425,2
+10426,2
+10427,0
+10428,3
+10429,0
+10430,0
+10431,0
+10432,1
+10433,0
+10434,3
+10435,0
+10436,3
+10437,3
+10438,1
+10439,1
+10440,0
+10441,0
+10442,0
+10443,0
+10444,3
+10445,2
+10446,3
+10447,2
+10448,1
+10449,3
+10450,3
+10451,0
+10452,3
+10453,0
+10454,2
+10455,0
+10456,0
+10457,3
+10458,0
+10459,3
+10460,1
+10461,0
+10462,3
+10463,0
+10464,2
+10465,1
+10466,0
+10467,3
+10468,1
+10469,0
+10470,3
+10471,0
+10472,1
+10473,0
+10474,1
+10475,0
+10476,1
+10477,0
+10478,1
+10479,1
+10480,0
+10481,0
+10482,3
+10483,1
+10484,0
+10485,1
+10486,1
+10487,0
+10488,0
+10489,0
+10490,2
+10491,3
+10492,0
+10493,0
+10494,0
+10495,0
+10496,1
+10497,0
+10498,0
+10499,1
+10500,2
+10501,2
+10502,0
+10503,0
+10504,3
+10505,3
+10506,0
+10507,1
+10508,3
+10509,0
+10510,2
+10511,3
+10512,0
+10513,2
+10514,0
+10515,2
+10516,3
+10517,0
+10518,2
+10519,1
+10520,2
+10521,0
+10522,0
+10523,2
+10524,0
+10525,0
+10526,3
+10527,2
+10528,1
+10529,1
+10530,0
+10531,2
+10532,1
+10533,3
+10534,3
+10535,1
+10536,2
+10537,0
+10538,1
+10539,1
+10540,0
+10541,2
+10542,0
+10543,1
+10544,2
+10545,3
+10546,0
+10547,2
+10548,0
+10549,1
+10550,0
+10551,3
+10552,0
+10553,0
+10554,0
+10555,2
+10556,0
+10557,3
+10558,2
+10559,0
+10560,2
+10561,0
+10562,3
+10563,1
+10564,0
+10565,0
+10566,0
+10567,3
+10568,0
+10569,0
+10570,2
+10571,0
+10572,0
+10573,0
+10574,0
+10575,0
+10576,2
+10577,0
+10578,2
+10579,0
+10580,0
+10581,2
+10582,0
+10583,2
+10584,0
+10585,3
+10586,0
+10587,0
+10588,2
+10589,2
+10590,0
+10591,3
+10592,2
+10593,0
+10594,0
+10595,0
+10596,0
+10597,0
+10598,2
+10599,2
+10600,2
+10601,1
+10602,1
+10603,2
+10604,3
+10605,3
+10606,0
+10607,3
+10608,1
+10609,0
+10610,3
+10611,0
+10612,0
+10613,3
+10614,3
+10615,2
+10616,1
+10617,1
+10618,3
+10619,3
+10620,1
+10621,0
+10622,2
+10623,0
+10624,2
+10625,2
+10626,3
+10627,1
+10628,0
+10629,0
+10630,3
+10631,0
+10632,0
+10633,3
+10634,1
+10635,3
+10636,0
+10637,0
+10638,3
+10639,1
+10640,0
+10641,0
+10642,3
+10643,3
+10644,1
+10645,0
+10646,1
+10647,1
+10648,3
+10649,2
+10650,1
+10651,2
+10652,0
+10653,2
+10654,2
+10655,1
+10656,2
+10657,1
+10658,3
+10659,1
+10660,1
+10661,1
+10662,0
+10663,1
+10664,2
+10665,0
+10666,3
+10667,0
+10668,2
+10669,0
+10670,2
+10671,0
+10672,2
+10673,1
+10674,0
+10675,1
+10676,2
+10677,0
+10678,3
+10679,2
+10680,3
+10681,1
+10682,0
+10683,0
+10684,0
+10685,3
+10686,3
+10687,2
+10688,2
+10689,0
+10690,0
+10691,1
+10692,0
+10693,3
+10694,0
+10695,2
+10696,2
+10697,0
+10698,0
+10699,0
+10700,2
+10701,3
+10702,0
+10703,2
+10704,2
+10705,1
+10706,0
+10707,3
+10708,3
+10709,0
+10710,0
+10711,2
+10712,0
+10713,0
+10714,2
+10715,1
+10716,2
+10717,0
+10718,3
+10719,3
+10720,0
+10721,0
+10722,0
+10723,2
+10724,1
+10725,3
+10726,0
+10727,2
+10728,0
+10729,2
+10730,0
+10731,2
+10732,0
+10733,3
+10734,0
+10735,1
+10736,3
+10737,2
+10738,0
+10739,0
+10740,0
+10741,0
+10742,3
+10743,3
+10744,0
diff --git a/new_model_tester.py b/new_model_tester.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac76d07f73f9772290853fb343c106b146e1ec83
--- /dev/null
+++ b/new_model_tester.py
@@ -0,0 +1,67 @@
+from features_extractor import FeatureExtractor
+
+import pandas as pd
+import numpy as np
+import xgboost as xgb
+import pickle
+import time
+
+from sklearn.model_selection import cross_validate, cross_val_predict, train_test_split, GridSearchCV
+from sklearn.metrics import accuracy_score, f1_score, confusion_matrix
+from sklearn.neighbors import KNeighborsClassifier
+from sklearn.svm import SVC
+from sklearn.ensemble import VotingClassifier, RandomForestClassifier
+
+from matplotlib import pyplot
+from copy import copy, deepcopy
+
+
+simple_categorical_variables = ['salutations', 'designation']
+complex_categorical_variables = ['mail_type', 'tld', 'org']
+numerical_variables = ['ccs', 'bcced', 'images', 'urls', 'chars_in_subject', 'chars_in_body']
+
+## Build the features extractor
+fe = FeatureExtractor(['train.csv', 'train_legacy.csv'], test_size=0.2)
+
+base_model = xgb.XGBClassifier(n_estimators=100, max_depth=12, gamma=0, reg_lambda=0.1, reg_alpha=0,
+                                learning_rate=0.1, subsample=0.8, colsample_bytree=0.5,
+                                min_child_weight=0.2, scale_pos_weight=1,
+                                objective='multi_softprob', verbosity=1)
+
+X_train, Y_train, X_test, Y_test, X_true = fe.extract_features('test.csv',
+                                                                simple_categorical_variables=simple_categorical_variables,
+                                                                complex_categorical_variables=complex_categorical_variables,
+                                                                numerical_variables=numerical_variables,
+                                                                time_variable=None)
+
+param_grid = {'n_estimators':[300, 400, 500], 'max_depth':[12], 'learning_rate':[0.01, 0.02, 0.05],
+              'gamma':[0], 'reg_lambda':[0, 0.1, 0.2], 'reg_alpha':[0]}
+grid = GridSearchCV(estimator=base_model, param_grid=param_grid, scoring='f1_macro', n_jobs=8, cv=2, verbose=1)
+grid.fit(X_train, Y_train)
+
+best_params = grid.best_params_
+print('Best params: {}'.format(best_params))
+
+base_model = base_model.set_params(params=best_params)
+scores = cross_validate(base_model, X_train, Y_train, cv=8,
+                        verbose=1, return_estimator=True, return_train_score=True,
+                        n_jobs=8, scoring='f1_macro')
+
+print("Train : ", np.mean(scores['train_score']), "Valid : ",np.mean(scores['test_score']))
+print(scores['test_score'])
+
+best_model = scores['estimator'][np.argmax(scores['test_score'])]
+test_pred = best_model.predict(X_test)
+print("Best Test : ", f1_score(Y_test, test_pred, average=None))
+print(confusion_matrix(Y_test, test_pred))
+
+voting_model = VotingClassifier(estimators=scores['estimator'], voting='soft')
+voting_model.fit(X_train, Y_train)
+y_test_pred_median = voting_model.predict(X_test)
+
+y_test_pred_median = np.argmax(y_test_pred_median, axis=1)
+test_median_score = f1_score(Y_test, y_test_pred_median, average=None)
+print("Median Test : ", test_median_score)
+print(confusion_matrix(Y_test, y_test_pred_median))
+
+
diff --git a/saved_stacks/0.1_knn_classifier_rd_0.9802165556813452.dat b/saved_stacks/0.1_knn_classifier_rd_0.9802165556813452.dat
new file mode 100644
index 0000000000000000000000000000000000000000..34c346dc26d6605cc50d4e0fa26e0d086325fecf
Binary files /dev/null and b/saved_stacks/0.1_knn_classifier_rd_0.9802165556813452.dat differ
diff --git a/saved_stacks/0.1_knn_classifier_tuned_0.9788529160892514.dat b/saved_stacks/0.1_knn_classifier_tuned_0.9788529160892514.dat
new file mode 100644
index 0000000000000000000000000000000000000000..786d53e75bd4589279984da9a3a700cc8a9000e6
Binary files /dev/null and b/saved_stacks/0.1_knn_classifier_tuned_0.9788529160892514.dat differ
diff --git a/saved_stacks/0.1_xgb_multi_softprob_rd_0.9806327380947029.dat b/saved_stacks/0.1_xgb_multi_softprob_rd_0.9806327380947029.dat
new file mode 100644
index 0000000000000000000000000000000000000000..2ed76748c69aa48aab4d381a2014993b664347b9
Binary files /dev/null and b/saved_stacks/0.1_xgb_multi_softprob_rd_0.9806327380947029.dat differ
diff --git a/saved_stacks/0.1_xgb_multi_softprob_tuned_0.9803752131450765.dat b/saved_stacks/0.1_xgb_multi_softprob_tuned_0.9803752131450765.dat
new file mode 100644
index 0000000000000000000000000000000000000000..36d90015dac38b4552e180cc635ad6f1ace746af
Binary files /dev/null and b/saved_stacks/0.1_xgb_multi_softprob_tuned_0.9803752131450765.dat differ
diff --git a/skeleton_code.py b/skeleton_code.py
deleted file mode 100644
index bdd7cb30deadfb94dedcdd72e6ddcad5b2bd1aa7..0000000000000000000000000000000000000000
--- a/skeleton_code.py
+++ /dev/null
@@ -1,153 +0,0 @@
-"""
-This script can be used as skelton code to read the challenge train and test
-csvs, to train a trivial model, and write data to the submission file.
-"""
-import pandas as pd
-import numpy as np
-import xgboost as xgb
-
-from datetime import datetime
-
-from sklearn.preprocessing import OneHotEncoder, MinMaxScaler, StandardScaler
-from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
-from sklearn.neighbors import KNeighborsClassifier
-from sklearn.model_selection import cross_validate, train_test_split
-from sklearn.metrics import accuracy_score, f1_score
-
-from matplotlib import pyplot
-
-
-def timestampToMonthDayHour():
-    return
-
-
-## Read csvs
-train_df = pd.read_csv('train.csv', index_col=0)
-train_df2 = pd.read_csv('train_legacy.csv', index_col=0)
-train_df = pd.concat((train_df,train_df2), axis=0)
-true_test_df = pd.read_csv('test.csv', index_col=0)
-train_df, test_df = train_test_split(train_df, test_size=0.20, random_state=42)
-
-## Handle missing values
-train_df.fillna('NA', inplace=True)
-test_df.fillna('NA', inplace=True)
-true_test_df.fillna('NA', inplace=True)
-
-## Filtering column "mail_type"
-print(train_df)
-
-train_y = np.ravel(train_df[['label']])
-test_y = np.ravel(test_df[['label']])
-
-sample_per_class = np.sum(OneHotEncoder(sparse=False).fit_transform(train_df[['label']].to_numpy()), axis=0)
-print(sample_per_class/np.sum(sample_per_class))
-
-categorical_variables = ['salutations', 'designation']
-simple_numerical_variables = ['ccs', 'bcced', 'images', 'urls', 'chars_in_subject', 'chars_in_body']
-
-train_x_categorical = train_df[categorical_variables].to_numpy()
-test_x_categorical = test_df[categorical_variables].to_numpy()
-true_x_categorical = true_test_df[categorical_variables].to_numpy()
-
-train_x_numerical = train_df[simple_numerical_variables].to_numpy()
-test_x_numerical = test_df[simple_numerical_variables].to_numpy()
-true_x_numerical = true_test_df[simple_numerical_variables].to_numpy()
-
-x_train_list = []
-x_test_list = []
-x_true_list = []
-features_labels = []
-
-## Do one hot encoding of categorical features
-feat_enc_categorical = OneHotEncoder(handle_unknown='ignore', sparse=False)
-
-train_x_categorical = feat_enc_categorical.fit_transform(train_x_categorical)
-test_x_categorical = feat_enc_categorical.transform(test_x_categorical)
-true_x_categorical = feat_enc_categorical.transform(true_x_categorical)
-
-x_train_list.append(train_x_categorical)
-x_test_list.append(test_x_categorical)
-x_true_list.append(true_x_categorical)
-features_labels += [categorical_variables[0]]*2 + [categorical_variables[1]]*2
-
-## Do standard normalisation for simple numerical features*
-feat_enc_numerical = StandardScaler()
-
-train_x_numerical = feat_enc_numerical.fit_transform(train_x_numerical)
-test_x_numerical = feat_enc_numerical.transform(test_x_numerical)
-true_x_numerical = feat_enc_numerical.transform(true_x_numerical)
-
-x_train_list.append(train_x_numerical)
-x_test_list.append(test_x_numerical)
-x_true_list.append(true_x_numerical)
-features_labels += simple_numerical_variables
-
-## Do one hot encoding and LDA for domain name and corportation (org and tld) independently
-complex_categorical_variables = ['mail_type', 'tld', 'org']
-
-for variable in complex_categorical_variables:
-    train_x_var = train_df[[variable]].to_numpy()
-    test_x_var = test_df[[variable]].to_numpy()
-    true_x_var = true_test_df[[variable]].to_numpy()
-
-    feat_enc = OneHotEncoder(handle_unknown='ignore', sparse=False)
-    train_x_var = feat_enc.fit_transform(train_x_var)
-    test_x_var = feat_enc.transform(test_x_var)
-    true_x_var = feat_enc.transform(true_x_var)
-
-    lda = LDA()
-    train_x_var = lda.fit_transform(train_x_var, train_y)
-    test_x_var = lda.transform(test_x_var)
-    true_x_var = lda.transform(true_x_var)
-
-    x_train_list.append(train_x_var)
-    x_test_list.append(test_x_var)
-    x_true_list.append(true_x_var)
-    features_labels += [variable]*test_x_var.shape[1]
-
-
-## Concatenate all the features
-print([x.shape for x in x_train_list])
-X_train = np.concatenate(x_train_list, axis=1)
-Y_train = train_y
-X_test = np.concatenate(x_test_list, axis=1)
-X_true = np.concatenate(x_true_list, axis=1)
-print(X_train.shape, Y_train.shape, X_test.shape, X_true.shape)
-
-# ## Train a simple KNN classifier using featurized data
-# neigh = KNeighborsClassifier(n_neighbors=5)
-# neigh.fit(X_train, Y_train)
-# pred_y = neigh.predict(X_test)
-# pred_df = pd.DataFrame(pred_y, columns=['label'])
-# pred_df.to_csv("knn_sample_submission.csv", index=True, index_label='Id')
-
-## Train on xgb classifier
-
-model = xgb.XGBClassifier(n_estimators=250, max_depth=12,
-                          learning_rate=0.1, subsample=0.8, colsample_bytree=0.5,
-                          min_child_weight=0.2, scale_pos_weight=1,
-                          objective='multi:softmax', verbosity=1)
-
-scores = cross_validate(model, X_train, Y_train, cv=8,
-                        verbose=1, return_estimator=True, return_train_score=True,
-                        n_jobs=8, scoring='f1_macro')
-
-
-print("Train : ", np.mean(scores['train_score']), "Valid : ",np.mean(scores['test_score']))
-print(scores['test_score'])
-best_model_index = np.argmax(scores['test_score'])
-best_model = scores['estimator'][best_model_index]
-
-test_pred = best_model.predict(X_test)
-print("Test : ", f1_score(test_y, test_pred, average='macro'))
-
-pred_y = best_model.predict(X_true)
-pred_df = pd.DataFrame(pred_y, columns=['label'])
-pred_df.to_csv("xgb_sample_submission.csv", index=True, index_label='Id')
-
-print(len(best_model.feature_importances_), len(features_labels), features_labels)
-print(best_model.feature_importances_)
-# pyplot.bar(features_labels, best_model.feature_importances_)
-# pyplot.show()
-# pyplot.bar(range(len(features_labels)), best_model.feature_importances_)
-# pyplot.show()
diff --git a/stacked_prediction.py b/stacked_prediction.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3d08c5f017ff6d2aa77a237e7b7f6ff5be39709
--- /dev/null
+++ b/stacked_prediction.py
@@ -0,0 +1,114 @@
+"""
+This script can be used as skelton code to read the challenge train and test
+csvs, to train a trivial model, and write data to the submission file.
+"""
+from features_extractor import FeatureExtractor
+
+import pandas as pd
+import numpy as np
+import xgboost as xgb
+import pickle
+import time
+
+from sklearn.model_selection import cross_validate, cross_val_predict, train_test_split
+from sklearn.metrics import accuracy_score, f1_score, confusion_matrix
+from sklearn.neighbors import KNeighborsClassifier
+from sklearn.svm import SVC
+from sklearn.ensemble import VotingClassifier, RandomForestClassifier
+
+from matplotlib import pyplot
+from copy import copy, deepcopy
+
+
+simple_categorical_variables = ['salutations', 'designation', 'bcced']
+complex_categorical_variables = ['mail_type', 'tld', 'org']
+numerical_variables = ['ccs', 'images', 'urls', 'chars_in_subject', 'chars_in_body']
+numerical_variables_to_clusterise = []
+
+## Build the features extractor
+test_size = 0.2
+fe = FeatureExtractor(['train.csv', 'train_legacy.csv'], test_size=test_size)
+
+# We will stack models in this list
+stack = []
+stack_datas = []
+
+# We build our models
+model_types = [
+    'xgb_multi_softprob_tuned', 
+    'xgb_multi_softprob_rd',
+    'knn_classifier_tuned',
+    'knn_classifier_rd',
+    # 'svc_classifier'
+]
+models = [
+    xgb.XGBClassifier(n_estimators=500, max_depth=12, gamma=0, reg_lambda=0.1, reg_alpha=0,
+                            learning_rate=0.02, subsample=0.8, colsample_bytree=0.5,
+                            min_child_weight=0.2, scale_pos_weight=1,
+                            objective='multi_softprob', verbosity=1),
+    xgb.XGBClassifier(n_estimators=500, max_depth=12, gamma=0, reg_lambda=0, reg_alpha=0,
+                            learning_rate=0.02, subsample=0.8, colsample_bytree=0.5,
+                            min_child_weight=0.2, scale_pos_weight=1,
+                            objective='multi_softprob', verbosity=1),
+    KNeighborsClassifier(),
+    KNeighborsClassifier(n_neighbors=8, p=1, weights='distance'),
+    SVC(C=100, degree=1, probability=True),
+    RandomForestClassifier(),
+]
+
+nb_folds = 8
+features_labels = []
+
+for model_type, base_model in zip(model_types, models):
+
+    X_train, Y_train, X_test, Y_test, X_true = fe.extract_features('test.csv',
+                                                                simple_categorical_variables=simple_categorical_variables,
+                                                                complex_categorical_variables=complex_categorical_variables,
+                                                                numerical_variables=numerical_variables,
+                                                                numerical_variables_to_clusterise=numerical_variables_to_clusterise,
+                                                                time_variable=None)
+    
+    scores = cross_validate(base_model, X_train, Y_train, cv=nb_folds,
+                            verbose=1, return_estimator=True, return_train_score=True,
+                            n_jobs=8, scoring='f1_macro')
+
+    stack += deepcopy(scores['estimator'])
+
+    print("Train : ", np.mean(scores['train_score']), "Valid : ",np.mean(scores['test_score']))
+    print(scores['test_score'])
+
+    best_model = scores['estimator'][np.argmax(scores['test_score'])]
+    test_pred = best_model.predict(X_test)
+    print("Best Test : ", f1_score(Y_test, test_pred, average=None))
+    print(confusion_matrix(Y_test, test_pred))
+
+    # Take the median predicitons of every fold
+    y_train_pred_list = []
+    y_test_pred_list = []
+    y_true_pred_list = []
+    for model in scores['estimator']:
+            y_train_pred_list += [model.predict_proba(X_train)[:, np.newaxis]]
+            y_test_pred_list += [model.predict_proba(X_test)[:, np.newaxis]]
+            y_true_pred_list += [model.predict_proba(X_true)[:, np.newaxis]]
+    y_train_pred_median = np.median(np.concatenate(y_train_pred_list, axis=1), axis=1)
+    y_test_pred_median = np.median(np.concatenate(y_test_pred_list, axis=1), axis=1)
+    y_true_pred_median = np.median(np.concatenate(y_true_pred_list, axis=1), axis=1)
+
+    stack_datas = {'Y_train_pred': copy(y_train_pred_median),
+                   'Y_test_pred': copy(y_test_pred_median),
+                   'Y_true_pred': copy(y_true_pred_median),
+                   'feature_label': model_type,
+                   'test_size': test_size
+    }
+
+    y_test_pred_median = np.argmax(y_test_pred_median, axis=1)
+    test_median_score = f1_score(Y_test, y_test_pred_median, average=None)
+    print("Median Test : ", test_median_score)
+    print(confusion_matrix(Y_test, y_test_pred_median))
+
+    if model_type == 'xgb_multi_softprob':
+        y_true_pred_median = np.argmax(y_true_pred_median, axis=1)
+        pred_df = pd.DataFrame(y_true_pred_median, columns=['label'])
+        pred_df.to_csv("xgb_sample_submission.csv", index=True, index_label='Id')
+
+    pickle.dump(stack_datas, open("saved_stacks/{}_{}_{}.dat".format(test_size, model_type, np.mean(test_median_score)), "wb"))
\ No newline at end of file
diff --git a/stacked_sample_submission.csv b/stacked_sample_submission.csv
new file mode 100644
index 0000000000000000000000000000000000000000..0e9cf7ecfeabc424cf1ccf764d020de4de9ce74c
--- /dev/null
+++ b/stacked_sample_submission.csv
@@ -0,0 +1,10746 @@
+Id,label
+0,2
+1,0
+2,0
+3,3
+4,0
+5,0
+6,0
+7,2
+8,2
+9,0
+10,2
+11,0
+12,0
+13,0
+14,3
+15,2
+16,1
+17,0
+18,1
+19,1
+20,0
+21,0
+22,1
+23,0
+24,3
+25,3
+26,1
+27,0
+28,1
+29,2
+30,0
+31,1
+32,0
+33,3
+34,0
+35,0
+36,3
+37,2
+38,3
+39,0
+40,0
+41,1
+42,0
+43,0
+44,1
+45,0
+46,3
+47,3
+48,3
+49,3
+50,2
+51,0
+52,3
+53,2
+54,0
+55,0
+56,3
+57,2
+58,1
+59,3
+60,0
+61,3
+62,2
+63,3
+64,3
+65,0
+66,3
+67,0
+68,0
+69,0
+70,1
+71,0
+72,2
+73,2
+74,3
+75,2
+76,0
+77,2
+78,2
+79,2
+80,1
+81,0
+82,0
+83,0
+84,2
+85,0
+86,2
+87,0
+88,2
+89,2
+90,3
+91,3
+92,3
+93,3
+94,0
+95,0
+96,0
+97,0
+98,2
+99,0
+100,2
+101,2
+102,2
+103,0
+104,3
+105,0
+106,2
+107,0
+108,0
+109,0
+110,1
+111,0
+112,0
+113,3
+114,1
+115,3
+116,2
+117,2
+118,3
+119,0
+120,3
+121,2
+122,0
+123,0
+124,3
+125,1
+126,3
+127,0
+128,1
+129,1
+130,0
+131,1
+132,2
+133,0
+134,1
+135,1
+136,3
+137,0
+138,0
+139,0
+140,0
+141,2
+142,0
+143,2
+144,2
+145,1
+146,2
+147,0
+148,0
+149,3
+150,2
+151,3
+152,3
+153,0
+154,2
+155,3
+156,3
+157,2
+158,0
+159,1
+160,1
+161,1
+162,2
+163,3
+164,0
+165,0
+166,0
+167,0
+168,0
+169,0
+170,0
+171,0
+172,0
+173,3
+174,0
+175,0
+176,0
+177,3
+178,3
+179,0
+180,3
+181,0
+182,3
+183,0
+184,0
+185,2
+186,0
+187,3
+188,0
+189,3
+190,2
+191,1
+192,0
+193,0
+194,3
+195,1
+196,3
+197,0
+198,3
+199,3
+200,1
+201,0
+202,0
+203,3
+204,0
+205,3
+206,2
+207,3
+208,2
+209,0
+210,0
+211,3
+212,3
+213,3
+214,3
+215,3
+216,3
+217,2
+218,3
+219,2
+220,0
+221,0
+222,2
+223,0
+224,3
+225,2
+226,1
+227,3
+228,0
+229,0
+230,3
+231,0
+232,0
+233,2
+234,2
+235,1
+236,0
+237,3
+238,0
+239,0
+240,0
+241,0
+242,2
+243,0
+244,0
+245,0
+246,2
+247,0
+248,0
+249,0
+250,0
+251,0
+252,0
+253,0
+254,0
+255,0
+256,3
+257,0
+258,0
+259,2
+260,0
+261,0
+262,2
+263,2
+264,0
+265,0
+266,2
+267,3
+268,2
+269,2
+270,0
+271,0
+272,3
+273,0
+274,0
+275,0
+276,3
+277,0
+278,3
+279,0
+280,1
+281,1
+282,0
+283,0
+284,2
+285,3
+286,3
+287,0
+288,0
+289,2
+290,2
+291,0
+292,3
+293,0
+294,2
+295,0
+296,2
+297,3
+298,0
+299,1
+300,1
+301,0
+302,3
+303,1
+304,0
+305,2
+306,0
+307,0
+308,0
+309,0
+310,0
+311,2
+312,2
+313,2
+314,1
+315,0
+316,1
+317,2
+318,0
+319,0
+320,3
+321,3
+322,3
+323,0
+324,3
+325,2
+326,2
+327,2
+328,3
+329,2
+330,0
+331,0
+332,3
+333,1
+334,0
+335,0
+336,2
+337,1
+338,1
+339,3
+340,0
+341,0
+342,1
+343,0
+344,0
+345,0
+346,3
+347,0
+348,3
+349,3
+350,0
+351,3
+352,1
+353,1
+354,1
+355,3
+356,2
+357,2
+358,0
+359,0
+360,0
+361,3
+362,0
+363,1
+364,3
+365,0
+366,3
+367,1
+368,0
+369,3
+370,3
+371,0
+372,2
+373,0
+374,1
+375,3
+376,0
+377,3
+378,0
+379,3
+380,0
+381,0
+382,1
+383,0
+384,3
+385,1
+386,2
+387,1
+388,1
+389,0
+390,2
+391,3
+392,2
+393,3
+394,0
+395,2
+396,0
+397,0
+398,0
+399,3
+400,0
+401,2
+402,1
+403,1
+404,0
+405,3
+406,0
+407,0
+408,0
+409,1
+410,2
+411,0
+412,3
+413,0
+414,3
+415,3
+416,3
+417,0
+418,3
+419,0
+420,0
+421,2
+422,2
+423,1
+424,3
+425,0
+426,1
+427,2
+428,2
+429,3
+430,3
+431,2
+432,2
+433,1
+434,1
+435,2
+436,0
+437,2
+438,3
+439,0
+440,3
+441,2
+442,2
+443,2
+444,0
+445,2
+446,2
+447,3
+448,0
+449,0
+450,1
+451,2
+452,3
+453,0
+454,1
+455,1
+456,0
+457,0
+458,1
+459,0
+460,0
+461,0
+462,3
+463,0
+464,3
+465,2
+466,0
+467,3
+468,0
+469,0
+470,2
+471,2
+472,0
+473,0
+474,1
+475,1
+476,0
+477,3
+478,2
+479,2
+480,0
+481,0
+482,3
+483,2
+484,3
+485,3
+486,0
+487,0
+488,3
+489,1
+490,0
+491,0
+492,3
+493,3
+494,0
+495,3
+496,0
+497,2
+498,2
+499,0
+500,3
+501,0
+502,3
+503,2
+504,3
+505,0
+506,0
+507,2
+508,0
+509,0
+510,0
+511,0
+512,3
+513,0
+514,3
+515,0
+516,0
+517,3
+518,3
+519,0
+520,0
+521,0
+522,0
+523,3
+524,2
+525,0
+526,3
+527,0
+528,0
+529,0
+530,0
+531,1
+532,0
+533,0
+534,0
+535,3
+536,2
+537,3
+538,1
+539,0
+540,1
+541,3
+542,3
+543,3
+544,0
+545,2
+546,0
+547,3
+548,0
+549,3
+550,0
+551,0
+552,3
+553,0
+554,0
+555,0
+556,1
+557,0
+558,1
+559,0
+560,0
+561,2
+562,3
+563,0
+564,0
+565,0
+566,2
+567,2
+568,0
+569,3
+570,1
+571,0
+572,3
+573,0
+574,0
+575,0
+576,0
+577,3
+578,3
+579,0
+580,0
+581,0
+582,0
+583,0
+584,0
+585,3
+586,0
+587,0
+588,0
+589,1
+590,2
+591,0
+592,0
+593,2
+594,0
+595,3
+596,0
+597,1
+598,0
+599,3
+600,3
+601,0
+602,0
+603,0
+604,2
+605,0
+606,1
+607,1
+608,1
+609,1
+610,2
+611,0
+612,2
+613,0
+614,1
+615,2
+616,2
+617,0
+618,2
+619,0
+620,0
+621,2
+622,2
+623,1
+624,0
+625,0
+626,2
+627,0
+628,3
+629,3
+630,3
+631,2
+632,0
+633,1
+634,0
+635,2
+636,0
+637,3
+638,3
+639,0
+640,0
+641,2
+642,0
+643,0
+644,3
+645,3
+646,0
+647,2
+648,1
+649,1
+650,0
+651,3
+652,1
+653,0
+654,2
+655,0
+656,0
+657,2
+658,0
+659,0
+660,0
+661,0
+662,3
+663,3
+664,1
+665,3
+666,3
+667,1
+668,2
+669,0
+670,2
+671,2
+672,3
+673,3
+674,0
+675,0
+676,3
+677,0
+678,3
+679,0
+680,2
+681,0
+682,1
+683,1
+684,3
+685,1
+686,3
+687,0
+688,1
+689,3
+690,1
+691,0
+692,0
+693,0
+694,2
+695,3
+696,0
+697,0
+698,1
+699,0
+700,0
+701,0
+702,2
+703,0
+704,0
+705,1
+706,0
+707,2
+708,2
+709,0
+710,3
+711,1
+712,0
+713,0
+714,3
+715,1
+716,0
+717,0
+718,0
+719,2
+720,3
+721,1
+722,2
+723,2
+724,2
+725,0
+726,0
+727,0
+728,3
+729,0
+730,0
+731,3
+732,2
+733,2
+734,1
+735,2
+736,0
+737,0
+738,0
+739,3
+740,0
+741,0
+742,0
+743,1
+744,0
+745,0
+746,1
+747,3
+748,3
+749,2
+750,3
+751,3
+752,0
+753,0
+754,3
+755,3
+756,3
+757,2
+758,2
+759,1
+760,3
+761,3
+762,3
+763,1
+764,3
+765,3
+766,3
+767,0
+768,0
+769,3
+770,2
+771,0
+772,0
+773,1
+774,0
+775,0
+776,0
+777,0
+778,0
+779,0
+780,3
+781,0
+782,0
+783,1
+784,3
+785,0
+786,0
+787,2
+788,0
+789,0
+790,1
+791,3
+792,2
+793,1
+794,3
+795,2
+796,2
+797,1
+798,3
+799,0
+800,0
+801,2
+802,2
+803,2
+804,3
+805,3
+806,0
+807,2
+808,2
+809,2
+810,2
+811,1
+812,1
+813,0
+814,2
+815,2
+816,3
+817,3
+818,3
+819,1
+820,1
+821,2
+822,1
+823,0
+824,0
+825,0
+826,0
+827,3
+828,1
+829,1
+830,3
+831,2
+832,1
+833,0
+834,0
+835,0
+836,3
+837,0
+838,3
+839,3
+840,1
+841,0
+842,2
+843,0
+844,0
+845,0
+846,1
+847,0
+848,3
+849,0
+850,0
+851,0
+852,0
+853,2
+854,0
+855,2
+856,0
+857,3
+858,1
+859,0
+860,0
+861,1
+862,3
+863,1
+864,1
+865,0
+866,2
+867,1
+868,3
+869,1
+870,2
+871,3
+872,3
+873,0
+874,0
+875,1
+876,3
+877,3
+878,3
+879,1
+880,3
+881,0
+882,3
+883,1
+884,1
+885,2
+886,0
+887,0
+888,0
+889,0
+890,0
+891,2
+892,0
+893,0
+894,0
+895,0
+896,2
+897,2
+898,2
+899,0
+900,0
+901,1
+902,0
+903,3
+904,2
+905,2
+906,2
+907,2
+908,0
+909,3
+910,0
+911,2
+912,1
+913,1
+914,2
+915,0
+916,2
+917,0
+918,3
+919,0
+920,0
+921,2
+922,0
+923,3
+924,0
+925,1
+926,0
+927,0
+928,3
+929,0
+930,2
+931,3
+932,1
+933,0
+934,3
+935,0
+936,3
+937,2
+938,3
+939,2
+940,0
+941,3
+942,0
+943,0
+944,0
+945,3
+946,3
+947,0
+948,2
+949,0
+950,0
+951,0
+952,1
+953,1
+954,0
+955,0
+956,3
+957,3
+958,2
+959,0
+960,1
+961,3
+962,0
+963,3
+964,0
+965,0
+966,0
+967,0
+968,2
+969,2
+970,2
+971,0
+972,0
+973,2
+974,1
+975,0
+976,1
+977,2
+978,2
+979,2
+980,3
+981,3
+982,3
+983,0
+984,3
+985,1
+986,0
+987,0
+988,0
+989,2
+990,1
+991,0
+992,0
+993,0
+994,3
+995,2
+996,3
+997,2
+998,0
+999,1
+1000,0
+1001,0
+1002,0
+1003,2
+1004,0
+1005,2
+1006,2
+1007,0
+1008,2
+1009,2
+1010,3
+1011,3
+1012,3
+1013,0
+1014,1
+1015,0
+1016,2
+1017,1
+1018,3
+1019,2
+1020,3
+1021,3
+1022,0
+1023,0
+1024,0
+1025,1
+1026,3
+1027,3
+1028,0
+1029,0
+1030,0
+1031,0
+1032,1
+1033,2
+1034,0
+1035,0
+1036,3
+1037,0
+1038,1
+1039,1
+1040,0
+1041,2
+1042,3
+1043,1
+1044,3
+1045,3
+1046,3
+1047,1
+1048,1
+1049,1
+1050,1
+1051,2
+1052,2
+1053,0
+1054,1
+1055,0
+1056,3
+1057,2
+1058,0
+1059,0
+1060,0
+1061,0
+1062,0
+1063,1
+1064,0
+1065,3
+1066,1
+1067,2
+1068,3
+1069,0
+1070,0
+1071,0
+1072,1
+1073,3
+1074,2
+1075,2
+1076,0
+1077,2
+1078,3
+1079,0
+1080,0
+1081,0
+1082,0
+1083,2
+1084,1
+1085,2
+1086,2
+1087,3
+1088,0
+1089,2
+1090,1
+1091,0
+1092,3
+1093,0
+1094,2
+1095,0
+1096,0
+1097,0
+1098,1
+1099,0
+1100,3
+1101,3
+1102,3
+1103,1
+1104,1
+1105,0
+1106,2
+1107,3
+1108,2
+1109,3
+1110,1
+1111,3
+1112,0
+1113,0
+1114,0
+1115,0
+1116,0
+1117,3
+1118,0
+1119,3
+1120,1
+1121,0
+1122,0
+1123,2
+1124,2
+1125,0
+1126,0
+1127,1
+1128,1
+1129,0
+1130,0
+1131,1
+1132,0
+1133,2
+1134,3
+1135,0
+1136,0
+1137,3
+1138,3
+1139,1
+1140,3
+1141,0
+1142,0
+1143,0
+1144,3
+1145,0
+1146,3
+1147,0
+1148,0
+1149,1
+1150,0
+1151,2
+1152,0
+1153,3
+1154,0
+1155,3
+1156,0
+1157,3
+1158,0
+1159,0
+1160,1
+1161,3
+1162,1
+1163,0
+1164,2
+1165,2
+1166,1
+1167,3
+1168,2
+1169,3
+1170,3
+1171,0
+1172,0
+1173,1
+1174,2
+1175,2
+1176,0
+1177,0
+1178,0
+1179,1
+1180,1
+1181,2
+1182,1
+1183,0
+1184,0
+1185,3
+1186,2
+1187,3
+1188,0
+1189,1
+1190,2
+1191,0
+1192,0
+1193,0
+1194,0
+1195,0
+1196,2
+1197,0
+1198,0
+1199,3
+1200,3
+1201,0
+1202,0
+1203,3
+1204,0
+1205,2
+1206,0
+1207,2
+1208,2
+1209,1
+1210,2
+1211,2
+1212,0
+1213,3
+1214,1
+1215,0
+1216,0
+1217,0
+1218,0
+1219,0
+1220,3
+1221,3
+1222,0
+1223,3
+1224,2
+1225,3
+1226,2
+1227,0
+1228,3
+1229,1
+1230,1
+1231,1
+1232,1
+1233,2
+1234,1
+1235,2
+1236,3
+1237,0
+1238,2
+1239,0
+1240,0
+1241,3
+1242,1
+1243,1
+1244,3
+1245,3
+1246,0
+1247,3
+1248,0
+1249,0
+1250,3
+1251,0
+1252,0
+1253,1
+1254,0
+1255,3
+1256,0
+1257,1
+1258,0
+1259,0
+1260,1
+1261,0
+1262,1
+1263,2
+1264,2
+1265,0
+1266,0
+1267,3
+1268,2
+1269,2
+1270,0
+1271,3
+1272,0
+1273,2
+1274,0
+1275,1
+1276,0
+1277,0
+1278,0
+1279,3
+1280,3
+1281,0
+1282,3
+1283,0
+1284,2
+1285,3
+1286,3
+1287,0
+1288,0
+1289,3
+1290,0
+1291,0
+1292,0
+1293,3
+1294,2
+1295,0
+1296,0
+1297,0
+1298,2
+1299,0
+1300,2
+1301,2
+1302,2
+1303,0
+1304,3
+1305,3
+1306,2
+1307,0
+1308,0
+1309,3
+1310,1
+1311,3
+1312,3
+1313,1
+1314,2
+1315,2
+1316,0
+1317,0
+1318,1
+1319,3
+1320,1
+1321,3
+1322,0
+1323,0
+1324,2
+1325,0
+1326,0
+1327,2
+1328,3
+1329,0
+1330,0
+1331,0
+1332,0
+1333,3
+1334,3
+1335,2
+1336,0
+1337,3
+1338,0
+1339,3
+1340,0
+1341,0
+1342,0
+1343,0
+1344,0
+1345,0
+1346,1
+1347,0
+1348,0
+1349,2
+1350,1
+1351,0
+1352,0
+1353,1
+1354,2
+1355,0
+1356,2
+1357,3
+1358,2
+1359,0
+1360,3
+1361,3
+1362,0
+1363,0
+1364,0
+1365,0
+1366,3
+1367,2
+1368,0
+1369,0
+1370,2
+1371,0
+1372,0
+1373,2
+1374,2
+1375,2
+1376,0
+1377,1
+1378,0
+1379,0
+1380,2
+1381,0
+1382,0
+1383,0
+1384,3
+1385,2
+1386,3
+1387,1
+1388,1
+1389,0
+1390,0
+1391,3
+1392,1
+1393,2
+1394,3
+1395,0
+1396,3
+1397,0
+1398,0
+1399,0
+1400,0
+1401,0
+1402,0
+1403,2
+1404,0
+1405,3
+1406,3
+1407,2
+1408,0
+1409,0
+1410,0
+1411,1
+1412,0
+1413,0
+1414,0
+1415,0
+1416,1
+1417,0
+1418,0
+1419,0
+1420,0
+1421,0
+1422,2
+1423,0
+1424,1
+1425,3
+1426,3
+1427,0
+1428,0
+1429,0
+1430,0
+1431,0
+1432,3
+1433,1
+1434,3
+1435,0
+1436,0
+1437,3
+1438,1
+1439,2
+1440,1
+1441,2
+1442,0
+1443,0
+1444,0
+1445,3
+1446,0
+1447,0
+1448,2
+1449,2
+1450,3
+1451,0
+1452,3
+1453,3
+1454,3
+1455,1
+1456,0
+1457,0
+1458,0
+1459,3
+1460,0
+1461,0
+1462,2
+1463,3
+1464,3
+1465,1
+1466,0
+1467,3
+1468,0
+1469,0
+1470,0
+1471,1
+1472,0
+1473,0
+1474,3
+1475,0
+1476,1
+1477,0
+1478,3
+1479,3
+1480,0
+1481,1
+1482,3
+1483,1
+1484,3
+1485,0
+1486,1
+1487,0
+1488,3
+1489,0
+1490,0
+1491,0
+1492,1
+1493,3
+1494,0
+1495,1
+1496,2
+1497,3
+1498,0
+1499,0
+1500,0
+1501,0
+1502,3
+1503,0
+1504,0
+1505,1
+1506,2
+1507,0
+1508,2
+1509,3
+1510,2
+1511,3
+1512,0
+1513,3
+1514,3
+1515,2
+1516,3
+1517,3
+1518,2
+1519,3
+1520,2
+1521,3
+1522,0
+1523,0
+1524,1
+1525,0
+1526,1
+1527,1
+1528,1
+1529,0
+1530,3
+1531,1
+1532,3
+1533,3
+1534,3
+1535,2
+1536,0
+1537,1
+1538,2
+1539,0
+1540,0
+1541,0
+1542,1
+1543,0
+1544,0
+1545,1
+1546,1
+1547,1
+1548,2
+1549,2
+1550,2
+1551,0
+1552,1
+1553,0
+1554,0
+1555,3
+1556,0
+1557,2
+1558,1
+1559,0
+1560,3
+1561,2
+1562,3
+1563,0
+1564,2
+1565,3
+1566,0
+1567,3
+1568,0
+1569,0
+1570,3
+1571,3
+1572,3
+1573,0
+1574,2
+1575,1
+1576,3
+1577,1
+1578,1
+1579,0
+1580,1
+1581,2
+1582,0
+1583,1
+1584,0
+1585,0
+1586,0
+1587,0
+1588,0
+1589,0
+1590,0
+1591,3
+1592,2
+1593,2
+1594,0
+1595,0
+1596,0
+1597,3
+1598,3
+1599,0
+1600,1
+1601,1
+1602,0
+1603,0
+1604,3
+1605,0
+1606,2
+1607,0
+1608,1
+1609,1
+1610,2
+1611,3
+1612,0
+1613,0
+1614,0
+1615,0
+1616,2
+1617,3
+1618,3
+1619,0
+1620,2
+1621,3
+1622,3
+1623,1
+1624,0
+1625,3
+1626,2
+1627,0
+1628,0
+1629,3
+1630,3
+1631,0
+1632,2
+1633,0
+1634,0
+1635,1
+1636,2
+1637,3
+1638,1
+1639,0
+1640,0
+1641,0
+1642,3
+1643,1
+1644,0
+1645,0
+1646,2
+1647,3
+1648,0
+1649,2
+1650,3
+1651,1
+1652,1
+1653,3
+1654,1
+1655,2
+1656,0
+1657,1
+1658,0
+1659,1
+1660,0
+1661,3
+1662,2
+1663,0
+1664,1
+1665,2
+1666,0
+1667,3
+1668,2
+1669,0
+1670,3
+1671,2
+1672,0
+1673,0
+1674,2
+1675,0
+1676,0
+1677,3
+1678,1
+1679,1
+1680,3
+1681,2
+1682,3
+1683,0
+1684,2
+1685,2
+1686,0
+1687,2
+1688,0
+1689,0
+1690,1
+1691,3
+1692,0
+1693,3
+1694,1
+1695,3
+1696,3
+1697,0
+1698,0
+1699,0
+1700,0
+1701,0
+1702,1
+1703,0
+1704,1
+1705,0
+1706,1
+1707,0
+1708,2
+1709,0
+1710,3
+1711,2
+1712,0
+1713,2
+1714,0
+1715,1
+1716,0
+1717,0
+1718,3
+1719,0
+1720,1
+1721,3
+1722,2
+1723,3
+1724,0
+1725,1
+1726,1
+1727,1
+1728,0
+1729,0
+1730,2
+1731,0
+1732,1
+1733,1
+1734,3
+1735,0
+1736,3
+1737,0
+1738,2
+1739,0
+1740,0
+1741,2
+1742,3
+1743,1
+1744,2
+1745,1
+1746,3
+1747,1
+1748,0
+1749,0
+1750,0
+1751,0
+1752,2
+1753,0
+1754,0
+1755,2
+1756,0
+1757,3
+1758,3
+1759,1
+1760,0
+1761,0
+1762,0
+1763,3
+1764,0
+1765,0
+1766,3
+1767,1
+1768,0
+1769,1
+1770,3
+1771,3
+1772,2
+1773,3
+1774,1
+1775,2
+1776,1
+1777,3
+1778,0
+1779,0
+1780,1
+1781,3
+1782,0
+1783,0
+1784,0
+1785,0
+1786,0
+1787,2
+1788,0
+1789,1
+1790,2
+1791,0
+1792,2
+1793,0
+1794,2
+1795,0
+1796,3
+1797,0
+1798,1
+1799,0
+1800,2
+1801,2
+1802,0
+1803,0
+1804,3
+1805,0
+1806,3
+1807,1
+1808,3
+1809,0
+1810,1
+1811,0
+1812,3
+1813,2
+1814,0
+1815,1
+1816,3
+1817,0
+1818,0
+1819,2
+1820,3
+1821,0
+1822,0
+1823,0
+1824,0
+1825,0
+1826,2
+1827,1
+1828,0
+1829,2
+1830,0
+1831,3
+1832,2
+1833,2
+1834,2
+1835,0
+1836,2
+1837,0
+1838,0
+1839,0
+1840,0
+1841,0
+1842,0
+1843,0
+1844,3
+1845,2
+1846,1
+1847,1
+1848,0
+1849,1
+1850,2
+1851,3
+1852,3
+1853,0
+1854,0
+1855,2
+1856,0
+1857,0
+1858,3
+1859,1
+1860,0
+1861,1
+1862,2
+1863,0
+1864,1
+1865,0
+1866,0
+1867,1
+1868,0
+1869,0
+1870,0
+1871,2
+1872,2
+1873,1
+1874,0
+1875,3
+1876,0
+1877,3
+1878,0
+1879,2
+1880,0
+1881,1
+1882,2
+1883,0
+1884,3
+1885,0
+1886,2
+1887,0
+1888,0
+1889,1
+1890,0
+1891,2
+1892,2
+1893,0
+1894,0
+1895,1
+1896,0
+1897,0
+1898,2
+1899,0
+1900,0
+1901,3
+1902,2
+1903,2
+1904,2
+1905,0
+1906,0
+1907,1
+1908,0
+1909,3
+1910,0
+1911,2
+1912,0
+1913,1
+1914,0
+1915,2
+1916,0
+1917,0
+1918,0
+1919,0
+1920,1
+1921,3
+1922,0
+1923,3
+1924,3
+1925,1
+1926,0
+1927,0
+1928,0
+1929,2
+1930,2
+1931,0
+1932,0
+1933,0
+1934,1
+1935,1
+1936,0
+1937,3
+1938,1
+1939,3
+1940,1
+1941,0
+1942,2
+1943,2
+1944,0
+1945,0
+1946,1
+1947,1
+1948,1
+1949,0
+1950,0
+1951,0
+1952,0
+1953,0
+1954,0
+1955,0
+1956,1
+1957,2
+1958,3
+1959,3
+1960,0
+1961,1
+1962,2
+1963,2
+1964,3
+1965,0
+1966,2
+1967,2
+1968,3
+1969,0
+1970,1
+1971,0
+1972,0
+1973,0
+1974,3
+1975,2
+1976,0
+1977,3
+1978,1
+1979,0
+1980,2
+1981,1
+1982,0
+1983,0
+1984,1
+1985,0
+1986,2
+1987,0
+1988,3
+1989,0
+1990,0
+1991,3
+1992,0
+1993,2
+1994,0
+1995,0
+1996,3
+1997,2
+1998,2
+1999,0
+2000,0
+2001,0
+2002,0
+2003,0
+2004,1
+2005,0
+2006,0
+2007,2
+2008,0
+2009,3
+2010,0
+2011,1
+2012,1
+2013,0
+2014,1
+2015,0
+2016,3
+2017,0
+2018,0
+2019,2
+2020,2
+2021,2
+2022,0
+2023,3
+2024,1
+2025,0
+2026,0
+2027,0
+2028,0
+2029,3
+2030,2
+2031,0
+2032,2
+2033,0
+2034,3
+2035,0
+2036,0
+2037,2
+2038,0
+2039,0
+2040,2
+2041,0
+2042,0
+2043,0
+2044,2
+2045,0
+2046,3
+2047,0
+2048,0
+2049,2
+2050,0
+2051,0
+2052,3
+2053,0
+2054,0
+2055,2
+2056,0
+2057,1
+2058,1
+2059,0
+2060,0
+2061,3
+2062,2
+2063,0
+2064,0
+2065,0
+2066,2
+2067,0
+2068,0
+2069,0
+2070,2
+2071,3
+2072,0
+2073,1
+2074,0
+2075,0
+2076,0
+2077,3
+2078,0
+2079,1
+2080,0
+2081,1
+2082,3
+2083,0
+2084,0
+2085,3
+2086,3
+2087,0
+2088,0
+2089,3
+2090,1
+2091,3
+2092,2
+2093,2
+2094,2
+2095,1
+2096,0
+2097,3
+2098,0
+2099,1
+2100,0
+2101,0
+2102,1
+2103,1
+2104,2
+2105,0
+2106,0
+2107,2
+2108,0
+2109,2
+2110,2
+2111,0
+2112,1
+2113,0
+2114,0
+2115,1
+2116,2
+2117,1
+2118,0
+2119,2
+2120,2
+2121,0
+2122,0
+2123,0
+2124,0
+2125,0
+2126,0
+2127,0
+2128,0
+2129,3
+2130,3
+2131,1
+2132,0
+2133,1
+2134,2
+2135,0
+2136,1
+2137,0
+2138,0
+2139,2
+2140,3
+2141,3
+2142,0
+2143,0
+2144,0
+2145,3
+2146,0
+2147,0
+2148,3
+2149,3
+2150,2
+2151,1
+2152,1
+2153,0
+2154,2
+2155,0
+2156,2
+2157,2
+2158,2
+2159,1
+2160,0
+2161,2
+2162,0
+2163,3
+2164,3
+2165,3
+2166,1
+2167,3
+2168,0
+2169,1
+2170,3
+2171,3
+2172,2
+2173,0
+2174,0
+2175,0
+2176,3
+2177,2
+2178,0
+2179,0
+2180,0
+2181,3
+2182,3
+2183,1
+2184,0
+2185,1
+2186,0
+2187,1
+2188,3
+2189,1
+2190,0
+2191,1
+2192,3
+2193,3
+2194,1
+2195,1
+2196,3
+2197,3
+2198,2
+2199,2
+2200,1
+2201,0
+2202,1
+2203,3
+2204,0
+2205,3
+2206,1
+2207,0
+2208,0
+2209,3
+2210,0
+2211,3
+2212,0
+2213,3
+2214,1
+2215,0
+2216,2
+2217,0
+2218,0
+2219,2
+2220,0
+2221,3
+2222,2
+2223,0
+2224,0
+2225,2
+2226,0
+2227,0
+2228,1
+2229,0
+2230,2
+2231,0
+2232,3
+2233,3
+2234,0
+2235,0
+2236,0
+2237,0
+2238,2
+2239,0
+2240,1
+2241,1
+2242,0
+2243,0
+2244,0
+2245,2
+2246,0
+2247,2
+2248,3
+2249,0
+2250,2
+2251,0
+2252,0
+2253,0
+2254,0
+2255,3
+2256,1
+2257,0
+2258,3
+2259,0
+2260,1
+2261,3
+2262,3
+2263,2
+2264,1
+2265,2
+2266,2
+2267,2
+2268,0
+2269,2
+2270,3
+2271,0
+2272,3
+2273,3
+2274,1
+2275,0
+2276,3
+2277,0
+2278,0
+2279,2
+2280,0
+2281,0
+2282,0
+2283,1
+2284,0
+2285,2
+2286,3
+2287,2
+2288,3
+2289,2
+2290,0
+2291,0
+2292,0
+2293,3
+2294,3
+2295,0
+2296,2
+2297,0
+2298,3
+2299,0
+2300,0
+2301,3
+2302,0
+2303,0
+2304,0
+2305,3
+2306,1
+2307,0
+2308,0
+2309,1
+2310,2
+2311,0
+2312,0
+2313,1
+2314,2
+2315,2
+2316,0
+2317,2
+2318,3
+2319,0
+2320,2
+2321,0
+2322,0
+2323,0
+2324,3
+2325,1
+2326,3
+2327,0
+2328,0
+2329,3
+2330,2
+2331,0
+2332,1
+2333,0
+2334,3
+2335,1
+2336,0
+2337,3
+2338,0
+2339,1
+2340,0
+2341,0
+2342,0
+2343,0
+2344,0
+2345,1
+2346,1
+2347,3
+2348,0
+2349,0
+2350,0
+2351,0
+2352,0
+2353,2
+2354,3
+2355,3
+2356,3
+2357,1
+2358,0
+2359,0
+2360,2
+2361,0
+2362,3
+2363,2
+2364,2
+2365,3
+2366,3
+2367,3
+2368,0
+2369,0
+2370,3
+2371,1
+2372,0
+2373,0
+2374,1
+2375,1
+2376,3
+2377,0
+2378,1
+2379,1
+2380,2
+2381,2
+2382,2
+2383,0
+2384,1
+2385,3
+2386,0
+2387,1
+2388,3
+2389,3
+2390,0
+2391,3
+2392,0
+2393,2
+2394,3
+2395,3
+2396,3
+2397,0
+2398,3
+2399,3
+2400,0
+2401,3
+2402,0
+2403,0
+2404,1
+2405,3
+2406,3
+2407,0
+2408,1
+2409,0
+2410,3
+2411,2
+2412,1
+2413,3
+2414,0
+2415,0
+2416,3
+2417,0
+2418,2
+2419,0
+2420,0
+2421,1
+2422,3
+2423,2
+2424,1
+2425,3
+2426,3
+2427,2
+2428,0
+2429,2
+2430,3
+2431,1
+2432,2
+2433,0
+2434,2
+2435,1
+2436,3
+2437,3
+2438,2
+2439,0
+2440,3
+2441,0
+2442,2
+2443,3
+2444,1
+2445,0
+2446,3
+2447,2
+2448,0
+2449,0
+2450,3
+2451,3
+2452,0
+2453,2
+2454,3
+2455,0
+2456,0
+2457,0
+2458,1
+2459,2
+2460,0
+2461,0
+2462,2
+2463,3
+2464,0
+2465,0
+2466,2
+2467,3
+2468,3
+2469,3
+2470,0
+2471,0
+2472,0
+2473,2
+2474,3
+2475,0
+2476,0
+2477,0
+2478,3
+2479,3
+2480,1
+2481,0
+2482,3
+2483,0
+2484,3
+2485,1
+2486,3
+2487,0
+2488,3
+2489,1
+2490,2
+2491,0
+2492,2
+2493,1
+2494,0
+2495,0
+2496,1
+2497,2
+2498,1
+2499,0
+2500,2
+2501,3
+2502,3
+2503,3
+2504,2
+2505,0
+2506,0
+2507,0
+2508,2
+2509,3
+2510,0
+2511,0
+2512,3
+2513,3
+2514,1
+2515,0
+2516,3
+2517,3
+2518,1
+2519,1
+2520,0
+2521,0
+2522,2
+2523,1
+2524,0
+2525,0
+2526,3
+2527,0
+2528,0
+2529,0
+2530,0
+2531,0
+2532,2
+2533,0
+2534,0
+2535,1
+2536,2
+2537,0
+2538,0
+2539,3
+2540,0
+2541,2
+2542,3
+2543,2
+2544,2
+2545,1
+2546,3
+2547,0
+2548,1
+2549,0
+2550,3
+2551,3
+2552,2
+2553,0
+2554,2
+2555,0
+2556,0
+2557,2
+2558,0
+2559,0
+2560,0
+2561,3
+2562,2
+2563,2
+2564,0
+2565,3
+2566,2
+2567,3
+2568,0
+2569,2
+2570,2
+2571,1
+2572,0
+2573,2
+2574,0
+2575,1
+2576,1
+2577,0
+2578,2
+2579,0
+2580,1
+2581,1
+2582,3
+2583,3
+2584,3
+2585,1
+2586,0
+2587,2
+2588,3
+2589,3
+2590,2
+2591,2
+2592,2
+2593,0
+2594,1
+2595,0
+2596,1
+2597,0
+2598,1
+2599,0
+2600,3
+2601,3
+2602,3
+2603,0
+2604,2
+2605,1
+2606,2
+2607,0
+2608,2
+2609,3
+2610,0
+2611,3
+2612,0
+2613,0
+2614,0
+2615,0
+2616,0
+2617,3
+2618,0
+2619,2
+2620,1
+2621,3
+2622,2
+2623,1
+2624,1
+2625,2
+2626,0
+2627,0
+2628,1
+2629,3
+2630,0
+2631,0
+2632,0
+2633,1
+2634,2
+2635,1
+2636,0
+2637,3
+2638,3
+2639,1
+2640,3
+2641,0
+2642,2
+2643,2
+2644,3
+2645,0
+2646,0
+2647,0
+2648,1
+2649,0
+2650,2
+2651,0
+2652,0
+2653,1
+2654,0
+2655,0
+2656,2
+2657,2
+2658,3
+2659,0
+2660,2
+2661,1
+2662,0
+2663,3
+2664,2
+2665,3
+2666,0
+2667,2
+2668,2
+2669,0
+2670,3
+2671,1
+2672,3
+2673,0
+2674,0
+2675,0
+2676,0
+2677,1
+2678,3
+2679,0
+2680,3
+2681,2
+2682,2
+2683,0
+2684,3
+2685,1
+2686,0
+2687,2
+2688,0
+2689,0
+2690,1
+2691,0
+2692,2
+2693,2
+2694,2
+2695,1
+2696,3
+2697,2
+2698,0
+2699,3
+2700,2
+2701,3
+2702,0
+2703,1
+2704,0
+2705,2
+2706,3
+2707,1
+2708,0
+2709,2
+2710,1
+2711,0
+2712,0
+2713,2
+2714,0
+2715,3
+2716,1
+2717,0
+2718,1
+2719,3
+2720,3
+2721,0
+2722,0
+2723,0
+2724,3
+2725,1
+2726,0
+2727,0
+2728,3
+2729,2
+2730,0
+2731,0
+2732,3
+2733,2
+2734,0
+2735,0
+2736,2
+2737,1
+2738,0
+2739,0
+2740,0
+2741,0
+2742,0
+2743,1
+2744,1
+2745,0
+2746,3
+2747,1
+2748,3
+2749,0
+2750,3
+2751,3
+2752,0
+2753,0
+2754,2
+2755,2
+2756,0
+2757,2
+2758,2
+2759,1
+2760,3
+2761,0
+2762,0
+2763,0
+2764,0
+2765,0
+2766,1
+2767,3
+2768,0
+2769,0
+2770,3
+2771,0
+2772,3
+2773,0
+2774,0
+2775,0
+2776,0
+2777,1
+2778,3
+2779,3
+2780,0
+2781,2
+2782,0
+2783,2
+2784,2
+2785,0
+2786,2
+2787,0
+2788,3
+2789,0
+2790,0
+2791,0
+2792,0
+2793,1
+2794,0
+2795,0
+2796,2
+2797,0
+2798,2
+2799,1
+2800,3
+2801,0
+2802,0
+2803,0
+2804,3
+2805,3
+2806,0
+2807,3
+2808,3
+2809,0
+2810,1
+2811,0
+2812,0
+2813,1
+2814,3
+2815,3
+2816,0
+2817,0
+2818,2
+2819,3
+2820,2
+2821,2
+2822,2
+2823,2
+2824,0
+2825,0
+2826,0
+2827,0
+2828,3
+2829,2
+2830,0
+2831,0
+2832,3
+2833,0
+2834,2
+2835,0
+2836,0
+2837,3
+2838,2
+2839,2
+2840,2
+2841,3
+2842,1
+2843,1
+2844,0
+2845,2
+2846,2
+2847,3
+2848,0
+2849,0
+2850,3
+2851,0
+2852,0
+2853,3
+2854,3
+2855,0
+2856,0
+2857,0
+2858,1
+2859,0
+2860,2
+2861,0
+2862,0
+2863,0
+2864,1
+2865,1
+2866,0
+2867,3
+2868,0
+2869,3
+2870,3
+2871,1
+2872,3
+2873,2
+2874,2
+2875,0
+2876,0
+2877,3
+2878,2
+2879,3
+2880,0
+2881,3
+2882,3
+2883,2
+2884,3
+2885,3
+2886,3
+2887,1
+2888,1
+2889,1
+2890,0
+2891,3
+2892,0
+2893,3
+2894,0
+2895,3
+2896,3
+2897,1
+2898,3
+2899,0
+2900,3
+2901,3
+2902,3
+2903,2
+2904,3
+2905,2
+2906,2
+2907,0
+2908,3
+2909,3
+2910,1
+2911,1
+2912,0
+2913,2
+2914,3
+2915,2
+2916,3
+2917,3
+2918,3
+2919,0
+2920,0
+2921,0
+2922,3
+2923,1
+2924,0
+2925,0
+2926,0
+2927,0
+2928,2
+2929,3
+2930,2
+2931,1
+2932,0
+2933,2
+2934,0
+2935,0
+2936,0
+2937,2
+2938,0
+2939,0
+2940,2
+2941,3
+2942,0
+2943,3
+2944,1
+2945,0
+2946,0
+2947,0
+2948,2
+2949,0
+2950,0
+2951,2
+2952,0
+2953,2
+2954,1
+2955,0
+2956,2
+2957,3
+2958,0
+2959,0
+2960,0
+2961,0
+2962,3
+2963,3
+2964,0
+2965,2
+2966,2
+2967,1
+2968,1
+2969,0
+2970,0
+2971,1
+2972,0
+2973,0
+2974,2
+2975,2
+2976,3
+2977,3
+2978,1
+2979,0
+2980,2
+2981,0
+2982,3
+2983,1
+2984,2
+2985,0
+2986,2
+2987,3
+2988,0
+2989,2
+2990,0
+2991,0
+2992,0
+2993,0
+2994,0
+2995,3
+2996,0
+2997,0
+2998,3
+2999,0
+3000,0
+3001,0
+3002,3
+3003,2
+3004,0
+3005,3
+3006,1
+3007,0
+3008,3
+3009,1
+3010,2
+3011,1
+3012,0
+3013,3
+3014,1
+3015,3
+3016,0
+3017,0
+3018,0
+3019,3
+3020,2
+3021,0
+3022,1
+3023,3
+3024,0
+3025,3
+3026,0
+3027,1
+3028,0
+3029,3
+3030,3
+3031,0
+3032,3
+3033,2
+3034,0
+3035,3
+3036,3
+3037,0
+3038,3
+3039,0
+3040,3
+3041,1
+3042,0
+3043,0
+3044,1
+3045,0
+3046,0
+3047,0
+3048,0
+3049,0
+3050,0
+3051,0
+3052,0
+3053,1
+3054,0
+3055,2
+3056,3
+3057,2
+3058,0
+3059,3
+3060,0
+3061,3
+3062,3
+3063,0
+3064,3
+3065,3
+3066,0
+3067,3
+3068,1
+3069,0
+3070,0
+3071,3
+3072,3
+3073,3
+3074,3
+3075,0
+3076,0
+3077,0
+3078,0
+3079,0
+3080,3
+3081,3
+3082,0
+3083,0
+3084,1
+3085,0
+3086,3
+3087,0
+3088,3
+3089,2
+3090,0
+3091,2
+3092,1
+3093,0
+3094,0
+3095,1
+3096,0
+3097,3
+3098,3
+3099,2
+3100,2
+3101,0
+3102,0
+3103,0
+3104,0
+3105,1
+3106,0
+3107,0
+3108,0
+3109,0
+3110,3
+3111,0
+3112,2
+3113,1
+3114,0
+3115,0
+3116,0
+3117,0
+3118,0
+3119,0
+3120,1
+3121,2
+3122,0
+3123,0
+3124,0
+3125,2
+3126,0
+3127,2
+3128,2
+3129,0
+3130,0
+3131,3
+3132,1
+3133,0
+3134,0
+3135,3
+3136,3
+3137,3
+3138,1
+3139,0
+3140,0
+3141,1
+3142,2
+3143,0
+3144,3
+3145,0
+3146,3
+3147,0
+3148,0
+3149,0
+3150,1
+3151,0
+3152,0
+3153,0
+3154,0
+3155,3
+3156,3
+3157,3
+3158,1
+3159,2
+3160,2
+3161,2
+3162,1
+3163,3
+3164,3
+3165,3
+3166,3
+3167,1
+3168,0
+3169,0
+3170,2
+3171,1
+3172,3
+3173,3
+3174,2
+3175,0
+3176,0
+3177,1
+3178,3
+3179,1
+3180,2
+3181,1
+3182,2
+3183,2
+3184,0
+3185,3
+3186,3
+3187,1
+3188,0
+3189,0
+3190,0
+3191,0
+3192,0
+3193,3
+3194,1
+3195,2
+3196,0
+3197,0
+3198,0
+3199,2
+3200,0
+3201,1
+3202,3
+3203,0
+3204,2
+3205,0
+3206,3
+3207,0
+3208,1
+3209,3
+3210,0
+3211,2
+3212,2
+3213,3
+3214,3
+3215,0
+3216,0
+3217,2
+3218,0
+3219,0
+3220,1
+3221,0
+3222,3
+3223,2
+3224,0
+3225,0
+3226,0
+3227,3
+3228,0
+3229,2
+3230,0
+3231,3
+3232,3
+3233,1
+3234,3
+3235,0
+3236,2
+3237,3
+3238,1
+3239,3
+3240,2
+3241,2
+3242,3
+3243,0
+3244,3
+3245,1
+3246,2
+3247,0
+3248,1
+3249,3
+3250,3
+3251,0
+3252,0
+3253,3
+3254,0
+3255,3
+3256,2
+3257,3
+3258,2
+3259,0
+3260,3
+3261,1
+3262,0
+3263,3
+3264,0
+3265,0
+3266,2
+3267,3
+3268,3
+3269,1
+3270,0
+3271,1
+3272,0
+3273,0
+3274,0
+3275,0
+3276,0
+3277,0
+3278,0
+3279,0
+3280,2
+3281,1
+3282,3
+3283,0
+3284,0
+3285,1
+3286,3
+3287,0
+3288,3
+3289,0
+3290,0
+3291,0
+3292,1
+3293,3
+3294,1
+3295,1
+3296,0
+3297,0
+3298,1
+3299,0
+3300,1
+3301,0
+3302,0
+3303,0
+3304,0
+3305,0
+3306,0
+3307,0
+3308,0
+3309,3
+3310,0
+3311,0
+3312,1
+3313,1
+3314,2
+3315,2
+3316,0
+3317,0
+3318,3
+3319,1
+3320,2
+3321,0
+3322,3
+3323,0
+3324,2
+3325,0
+3326,0
+3327,0
+3328,3
+3329,2
+3330,2
+3331,0
+3332,3
+3333,0
+3334,2
+3335,3
+3336,0
+3337,0
+3338,1
+3339,2
+3340,3
+3341,0
+3342,0
+3343,0
+3344,2
+3345,1
+3346,2
+3347,0
+3348,0
+3349,2
+3350,2
+3351,0
+3352,0
+3353,3
+3354,0
+3355,1
+3356,3
+3357,0
+3358,0
+3359,3
+3360,0
+3361,3
+3362,0
+3363,3
+3364,0
+3365,0
+3366,2
+3367,1
+3368,3
+3369,1
+3370,1
+3371,0
+3372,3
+3373,3
+3374,2
+3375,3
+3376,0
+3377,1
+3378,3
+3379,1
+3380,0
+3381,0
+3382,3
+3383,2
+3384,0
+3385,3
+3386,0
+3387,2
+3388,1
+3389,3
+3390,0
+3391,0
+3392,3
+3393,0
+3394,2
+3395,0
+3396,0
+3397,0
+3398,3
+3399,3
+3400,3
+3401,2
+3402,2
+3403,1
+3404,0
+3405,3
+3406,2
+3407,0
+3408,0
+3409,3
+3410,2
+3411,1
+3412,3
+3413,0
+3414,1
+3415,0
+3416,3
+3417,0
+3418,0
+3419,3
+3420,3
+3421,3
+3422,0
+3423,0
+3424,1
+3425,0
+3426,0
+3427,3
+3428,2
+3429,2
+3430,0
+3431,0
+3432,0
+3433,0
+3434,3
+3435,2
+3436,1
+3437,1
+3438,0
+3439,0
+3440,3
+3441,3
+3442,0
+3443,2
+3444,0
+3445,0
+3446,3
+3447,1
+3448,1
+3449,3
+3450,0
+3451,3
+3452,3
+3453,0
+3454,0
+3455,3
+3456,2
+3457,0
+3458,3
+3459,0
+3460,1
+3461,0
+3462,0
+3463,1
+3464,0
+3465,0
+3466,1
+3467,0
+3468,2
+3469,3
+3470,3
+3471,2
+3472,3
+3473,0
+3474,2
+3475,0
+3476,0
+3477,3
+3478,2
+3479,0
+3480,2
+3481,3
+3482,3
+3483,0
+3484,2
+3485,1
+3486,1
+3487,0
+3488,0
+3489,0
+3490,0
+3491,2
+3492,0
+3493,3
+3494,1
+3495,0
+3496,0
+3497,0
+3498,2
+3499,1
+3500,0
+3501,1
+3502,2
+3503,0
+3504,2
+3505,0
+3506,0
+3507,2
+3508,2
+3509,0
+3510,3
+3511,2
+3512,2
+3513,2
+3514,0
+3515,0
+3516,0
+3517,0
+3518,0
+3519,3
+3520,2
+3521,2
+3522,3
+3523,0
+3524,2
+3525,2
+3526,0
+3527,0
+3528,1
+3529,0
+3530,2
+3531,3
+3532,0
+3533,0
+3534,2
+3535,1
+3536,2
+3537,3
+3538,0
+3539,3
+3540,2
+3541,0
+3542,0
+3543,2
+3544,0
+3545,1
+3546,1
+3547,2
+3548,1
+3549,0
+3550,2
+3551,3
+3552,2
+3553,3
+3554,0
+3555,2
+3556,3
+3557,2
+3558,3
+3559,0
+3560,2
+3561,0
+3562,2
+3563,2
+3564,3
+3565,0
+3566,0
+3567,1
+3568,1
+3569,3
+3570,2
+3571,2
+3572,0
+3573,3
+3574,0
+3575,0
+3576,0
+3577,0
+3578,3
+3579,0
+3580,1
+3581,2
+3582,0
+3583,0
+3584,2
+3585,3
+3586,1
+3587,3
+3588,0
+3589,3
+3590,3
+3591,0
+3592,2
+3593,3
+3594,2
+3595,0
+3596,0
+3597,0
+3598,0
+3599,0
+3600,3
+3601,3
+3602,3
+3603,2
+3604,0
+3605,0
+3606,2
+3607,0
+3608,0
+3609,0
+3610,3
+3611,0
+3612,3
+3613,2
+3614,1
+3615,1
+3616,0
+3617,0
+3618,0
+3619,2
+3620,2
+3621,1
+3622,3
+3623,1
+3624,3
+3625,3
+3626,3
+3627,3
+3628,3
+3629,0
+3630,0
+3631,3
+3632,0
+3633,1
+3634,0
+3635,0
+3636,3
+3637,2
+3638,3
+3639,0
+3640,2
+3641,3
+3642,0
+3643,0
+3644,2
+3645,2
+3646,0
+3647,0
+3648,3
+3649,3
+3650,2
+3651,0
+3652,2
+3653,0
+3654,0
+3655,0
+3656,0
+3657,3
+3658,0
+3659,2
+3660,1
+3661,0
+3662,1
+3663,0
+3664,0
+3665,3
+3666,1
+3667,0
+3668,2
+3669,2
+3670,2
+3671,1
+3672,0
+3673,0
+3674,1
+3675,2
+3676,0
+3677,1
+3678,2
+3679,0
+3680,0
+3681,1
+3682,0
+3683,3
+3684,0
+3685,3
+3686,0
+3687,0
+3688,2
+3689,2
+3690,1
+3691,0
+3692,1
+3693,0
+3694,2
+3695,1
+3696,0
+3697,0
+3698,3
+3699,2
+3700,3
+3701,1
+3702,1
+3703,1
+3704,3
+3705,0
+3706,0
+3707,0
+3708,2
+3709,0
+3710,0
+3711,3
+3712,0
+3713,0
+3714,2
+3715,1
+3716,3
+3717,1
+3718,3
+3719,1
+3720,0
+3721,1
+3722,1
+3723,1
+3724,0
+3725,0
+3726,0
+3727,0
+3728,0
+3729,0
+3730,3
+3731,0
+3732,3
+3733,0
+3734,0
+3735,3
+3736,0
+3737,3
+3738,0
+3739,3
+3740,2
+3741,0
+3742,3
+3743,0
+3744,3
+3745,0
+3746,0
+3747,2
+3748,2
+3749,1
+3750,0
+3751,0
+3752,3
+3753,2
+3754,3
+3755,2
+3756,3
+3757,0
+3758,3
+3759,2
+3760,0
+3761,0
+3762,0
+3763,0
+3764,0
+3765,3
+3766,3
+3767,0
+3768,2
+3769,0
+3770,3
+3771,0
+3772,0
+3773,0
+3774,1
+3775,2
+3776,0
+3777,0
+3778,0
+3779,1
+3780,1
+3781,0
+3782,3
+3783,1
+3784,2
+3785,3
+3786,0
+3787,0
+3788,2
+3789,0
+3790,2
+3791,0
+3792,2
+3793,2
+3794,0
+3795,0
+3796,0
+3797,0
+3798,1
+3799,0
+3800,0
+3801,1
+3802,3
+3803,2
+3804,0
+3805,1
+3806,2
+3807,0
+3808,3
+3809,0
+3810,2
+3811,3
+3812,2
+3813,1
+3814,2
+3815,0
+3816,0
+3817,0
+3818,3
+3819,0
+3820,2
+3821,2
+3822,0
+3823,3
+3824,0
+3825,0
+3826,2
+3827,0
+3828,0
+3829,1
+3830,0
+3831,2
+3832,3
+3833,3
+3834,0
+3835,0
+3836,0
+3837,0
+3838,0
+3839,3
+3840,2
+3841,3
+3842,3
+3843,3
+3844,0
+3845,2
+3846,0
+3847,0
+3848,0
+3849,1
+3850,0
+3851,3
+3852,0
+3853,0
+3854,3
+3855,0
+3856,2
+3857,0
+3858,0
+3859,3
+3860,2
+3861,0
+3862,0
+3863,0
+3864,1
+3865,0
+3866,3
+3867,0
+3868,0
+3869,3
+3870,0
+3871,2
+3872,1
+3873,2
+3874,3
+3875,0
+3876,0
+3877,0
+3878,0
+3879,0
+3880,0
+3881,3
+3882,1
+3883,1
+3884,3
+3885,0
+3886,2
+3887,1
+3888,0
+3889,0
+3890,2
+3891,2
+3892,0
+3893,0
+3894,0
+3895,0
+3896,0
+3897,3
+3898,2
+3899,0
+3900,2
+3901,1
+3902,0
+3903,3
+3904,0
+3905,3
+3906,0
+3907,0
+3908,0
+3909,3
+3910,2
+3911,1
+3912,3
+3913,0
+3914,0
+3915,2
+3916,0
+3917,0
+3918,3
+3919,3
+3920,0
+3921,2
+3922,1
+3923,1
+3924,3
+3925,0
+3926,1
+3927,2
+3928,2
+3929,0
+3930,0
+3931,3
+3932,2
+3933,0
+3934,0
+3935,2
+3936,0
+3937,1
+3938,0
+3939,1
+3940,0
+3941,1
+3942,1
+3943,0
+3944,1
+3945,2
+3946,2
+3947,0
+3948,1
+3949,3
+3950,2
+3951,2
+3952,0
+3953,0
+3954,0
+3955,1
+3956,0
+3957,0
+3958,1
+3959,0
+3960,0
+3961,0
+3962,3
+3963,2
+3964,2
+3965,3
+3966,0
+3967,2
+3968,0
+3969,1
+3970,3
+3971,0
+3972,0
+3973,0
+3974,3
+3975,0
+3976,0
+3977,3
+3978,3
+3979,1
+3980,3
+3981,0
+3982,2
+3983,2
+3984,1
+3985,1
+3986,3
+3987,1
+3988,2
+3989,3
+3990,0
+3991,2
+3992,2
+3993,0
+3994,0
+3995,0
+3996,0
+3997,0
+3998,2
+3999,0
+4000,0
+4001,3
+4002,1
+4003,2
+4004,0
+4005,1
+4006,3
+4007,1
+4008,1
+4009,1
+4010,2
+4011,2
+4012,3
+4013,3
+4014,3
+4015,3
+4016,2
+4017,2
+4018,3
+4019,0
+4020,0
+4021,0
+4022,0
+4023,0
+4024,3
+4025,2
+4026,2
+4027,0
+4028,0
+4029,0
+4030,0
+4031,1
+4032,0
+4033,2
+4034,0
+4035,3
+4036,1
+4037,2
+4038,2
+4039,3
+4040,0
+4041,0
+4042,0
+4043,0
+4044,2
+4045,2
+4046,2
+4047,3
+4048,0
+4049,3
+4050,2
+4051,3
+4052,2
+4053,2
+4054,3
+4055,0
+4056,0
+4057,0
+4058,0
+4059,0
+4060,3
+4061,0
+4062,0
+4063,0
+4064,0
+4065,3
+4066,0
+4067,0
+4068,1
+4069,3
+4070,0
+4071,2
+4072,3
+4073,0
+4074,1
+4075,0
+4076,0
+4077,0
+4078,0
+4079,2
+4080,3
+4081,1
+4082,0
+4083,0
+4084,0
+4085,3
+4086,2
+4087,3
+4088,0
+4089,0
+4090,1
+4091,0
+4092,0
+4093,0
+4094,2
+4095,1
+4096,0
+4097,0
+4098,0
+4099,3
+4100,1
+4101,0
+4102,2
+4103,2
+4104,2
+4105,3
+4106,0
+4107,2
+4108,0
+4109,0
+4110,0
+4111,0
+4112,2
+4113,0
+4114,0
+4115,3
+4116,3
+4117,3
+4118,0
+4119,1
+4120,2
+4121,0
+4122,0
+4123,2
+4124,0
+4125,2
+4126,2
+4127,3
+4128,0
+4129,3
+4130,0
+4131,3
+4132,2
+4133,0
+4134,0
+4135,2
+4136,0
+4137,2
+4138,2
+4139,1
+4140,1
+4141,3
+4142,3
+4143,2
+4144,3
+4145,0
+4146,2
+4147,0
+4148,0
+4149,3
+4150,0
+4151,0
+4152,0
+4153,2
+4154,1
+4155,0
+4156,0
+4157,3
+4158,1
+4159,2
+4160,3
+4161,3
+4162,2
+4163,2
+4164,0
+4165,3
+4166,0
+4167,3
+4168,2
+4169,0
+4170,2
+4171,0
+4172,2
+4173,0
+4174,0
+4175,3
+4176,1
+4177,0
+4178,2
+4179,2
+4180,0
+4181,1
+4182,2
+4183,2
+4184,0
+4185,0
+4186,2
+4187,3
+4188,0
+4189,2
+4190,2
+4191,3
+4192,0
+4193,3
+4194,2
+4195,2
+4196,0
+4197,0
+4198,1
+4199,2
+4200,3
+4201,0
+4202,0
+4203,2
+4204,0
+4205,0
+4206,3
+4207,0
+4208,0
+4209,0
+4210,0
+4211,0
+4212,0
+4213,0
+4214,1
+4215,0
+4216,1
+4217,0
+4218,0
+4219,3
+4220,0
+4221,3
+4222,2
+4223,0
+4224,0
+4225,0
+4226,0
+4227,1
+4228,3
+4229,0
+4230,0
+4231,0
+4232,2
+4233,2
+4234,0
+4235,2
+4236,1
+4237,0
+4238,3
+4239,0
+4240,2
+4241,3
+4242,0
+4243,0
+4244,0
+4245,3
+4246,0
+4247,1
+4248,3
+4249,0
+4250,3
+4251,0
+4252,0
+4253,2
+4254,0
+4255,0
+4256,3
+4257,0
+4258,1
+4259,3
+4260,3
+4261,0
+4262,3
+4263,1
+4264,2
+4265,0
+4266,2
+4267,2
+4268,0
+4269,0
+4270,2
+4271,1
+4272,3
+4273,0
+4274,1
+4275,3
+4276,0
+4277,2
+4278,1
+4279,0
+4280,0
+4281,0
+4282,2
+4283,2
+4284,0
+4285,0
+4286,1
+4287,0
+4288,1
+4289,2
+4290,3
+4291,0
+4292,2
+4293,0
+4294,0
+4295,1
+4296,1
+4297,1
+4298,2
+4299,1
+4300,0
+4301,3
+4302,2
+4303,0
+4304,0
+4305,1
+4306,3
+4307,3
+4308,3
+4309,2
+4310,1
+4311,2
+4312,0
+4313,3
+4314,2
+4315,3
+4316,2
+4317,3
+4318,0
+4319,0
+4320,3
+4321,3
+4322,1
+4323,0
+4324,0
+4325,3
+4326,1
+4327,3
+4328,1
+4329,1
+4330,1
+4331,1
+4332,0
+4333,3
+4334,2
+4335,2
+4336,0
+4337,2
+4338,0
+4339,3
+4340,2
+4341,3
+4342,3
+4343,3
+4344,3
+4345,2
+4346,0
+4347,2
+4348,3
+4349,2
+4350,0
+4351,2
+4352,3
+4353,1
+4354,0
+4355,0
+4356,0
+4357,0
+4358,1
+4359,0
+4360,2
+4361,0
+4362,0
+4363,0
+4364,2
+4365,2
+4366,2
+4367,0
+4368,2
+4369,2
+4370,0
+4371,0
+4372,0
+4373,3
+4374,0
+4375,0
+4376,1
+4377,0
+4378,3
+4379,0
+4380,1
+4381,0
+4382,0
+4383,3
+4384,0
+4385,3
+4386,1
+4387,0
+4388,0
+4389,0
+4390,2
+4391,2
+4392,0
+4393,0
+4394,0
+4395,1
+4396,1
+4397,0
+4398,2
+4399,0
+4400,2
+4401,3
+4402,2
+4403,0
+4404,1
+4405,1
+4406,2
+4407,0
+4408,0
+4409,0
+4410,2
+4411,1
+4412,0
+4413,0
+4414,3
+4415,0
+4416,0
+4417,3
+4418,3
+4419,2
+4420,1
+4421,2
+4422,1
+4423,0
+4424,3
+4425,0
+4426,0
+4427,2
+4428,0
+4429,0
+4430,3
+4431,2
+4432,1
+4433,2
+4434,1
+4435,2
+4436,0
+4437,0
+4438,0
+4439,0
+4440,0
+4441,2
+4442,3
+4443,2
+4444,3
+4445,0
+4446,1
+4447,1
+4448,2
+4449,0
+4450,0
+4451,0
+4452,1
+4453,3
+4454,1
+4455,0
+4456,2
+4457,0
+4458,1
+4459,3
+4460,2
+4461,2
+4462,0
+4463,3
+4464,3
+4465,0
+4466,0
+4467,2
+4468,0
+4469,1
+4470,0
+4471,0
+4472,1
+4473,1
+4474,0
+4475,1
+4476,0
+4477,2
+4478,0
+4479,0
+4480,3
+4481,3
+4482,1
+4483,3
+4484,3
+4485,3
+4486,0
+4487,0
+4488,1
+4489,3
+4490,3
+4491,2
+4492,3
+4493,0
+4494,1
+4495,0
+4496,3
+4497,3
+4498,0
+4499,0
+4500,0
+4501,0
+4502,1
+4503,0
+4504,2
+4505,3
+4506,0
+4507,3
+4508,1
+4509,0
+4510,3
+4511,0
+4512,0
+4513,3
+4514,3
+4515,3
+4516,2
+4517,2
+4518,1
+4519,0
+4520,0
+4521,2
+4522,2
+4523,3
+4524,2
+4525,0
+4526,3
+4527,0
+4528,1
+4529,1
+4530,2
+4531,2
+4532,1
+4533,0
+4534,2
+4535,0
+4536,3
+4537,3
+4538,2
+4539,2
+4540,1
+4541,2
+4542,2
+4543,2
+4544,3
+4545,3
+4546,3
+4547,3
+4548,2
+4549,0
+4550,2
+4551,1
+4552,3
+4553,0
+4554,2
+4555,2
+4556,3
+4557,0
+4558,3
+4559,3
+4560,2
+4561,1
+4562,3
+4563,0
+4564,0
+4565,0
+4566,0
+4567,1
+4568,3
+4569,3
+4570,0
+4571,2
+4572,0
+4573,0
+4574,2
+4575,3
+4576,3
+4577,1
+4578,0
+4579,3
+4580,2
+4581,0
+4582,0
+4583,2
+4584,2
+4585,1
+4586,0
+4587,2
+4588,2
+4589,0
+4590,2
+4591,0
+4592,0
+4593,0
+4594,2
+4595,1
+4596,0
+4597,0
+4598,2
+4599,0
+4600,3
+4601,3
+4602,3
+4603,3
+4604,0
+4605,2
+4606,0
+4607,1
+4608,0
+4609,2
+4610,0
+4611,0
+4612,0
+4613,3
+4614,0
+4615,3
+4616,3
+4617,2
+4618,0
+4619,2
+4620,0
+4621,2
+4622,3
+4623,0
+4624,3
+4625,0
+4626,3
+4627,0
+4628,0
+4629,3
+4630,0
+4631,0
+4632,0
+4633,3
+4634,0
+4635,0
+4636,1
+4637,2
+4638,0
+4639,0
+4640,0
+4641,0
+4642,1
+4643,0
+4644,0
+4645,1
+4646,0
+4647,0
+4648,0
+4649,0
+4650,3
+4651,0
+4652,0
+4653,3
+4654,0
+4655,0
+4656,3
+4657,2
+4658,0
+4659,3
+4660,1
+4661,1
+4662,1
+4663,0
+4664,1
+4665,1
+4666,2
+4667,2
+4668,1
+4669,3
+4670,0
+4671,0
+4672,3
+4673,2
+4674,0
+4675,0
+4676,3
+4677,1
+4678,0
+4679,1
+4680,2
+4681,0
+4682,3
+4683,3
+4684,0
+4685,2
+4686,0
+4687,1
+4688,0
+4689,0
+4690,2
+4691,0
+4692,0
+4693,3
+4694,1
+4695,1
+4696,2
+4697,1
+4698,0
+4699,0
+4700,0
+4701,0
+4702,2
+4703,0
+4704,1
+4705,0
+4706,3
+4707,3
+4708,2
+4709,1
+4710,0
+4711,0
+4712,3
+4713,3
+4714,0
+4715,0
+4716,0
+4717,0
+4718,3
+4719,1
+4720,1
+4721,3
+4722,2
+4723,2
+4724,3
+4725,0
+4726,2
+4727,0
+4728,3
+4729,1
+4730,0
+4731,0
+4732,3
+4733,3
+4734,0
+4735,0
+4736,0
+4737,0
+4738,0
+4739,2
+4740,3
+4741,0
+4742,2
+4743,2
+4744,0
+4745,3
+4746,0
+4747,0
+4748,2
+4749,0
+4750,2
+4751,3
+4752,1
+4753,1
+4754,0
+4755,2
+4756,1
+4757,2
+4758,0
+4759,1
+4760,3
+4761,3
+4762,2
+4763,0
+4764,0
+4765,2
+4766,3
+4767,2
+4768,0
+4769,3
+4770,0
+4771,0
+4772,2
+4773,1
+4774,3
+4775,3
+4776,2
+4777,0
+4778,0
+4779,3
+4780,1
+4781,0
+4782,2
+4783,0
+4784,0
+4785,1
+4786,0
+4787,0
+4788,1
+4789,0
+4790,0
+4791,0
+4792,0
+4793,0
+4794,3
+4795,2
+4796,0
+4797,2
+4798,1
+4799,0
+4800,0
+4801,0
+4802,2
+4803,3
+4804,0
+4805,0
+4806,0
+4807,0
+4808,3
+4809,0
+4810,1
+4811,3
+4812,0
+4813,2
+4814,2
+4815,0
+4816,0
+4817,0
+4818,0
+4819,3
+4820,0
+4821,0
+4822,2
+4823,0
+4824,0
+4825,0
+4826,1
+4827,3
+4828,2
+4829,3
+4830,3
+4831,0
+4832,0
+4833,2
+4834,3
+4835,1
+4836,1
+4837,2
+4838,0
+4839,3
+4840,3
+4841,2
+4842,3
+4843,0
+4844,0
+4845,3
+4846,0
+4847,0
+4848,3
+4849,0
+4850,0
+4851,0
+4852,1
+4853,2
+4854,1
+4855,2
+4856,1
+4857,0
+4858,0
+4859,0
+4860,3
+4861,2
+4862,0
+4863,3
+4864,0
+4865,0
+4866,1
+4867,2
+4868,1
+4869,3
+4870,1
+4871,1
+4872,0
+4873,0
+4874,3
+4875,3
+4876,3
+4877,3
+4878,1
+4879,1
+4880,0
+4881,1
+4882,3
+4883,2
+4884,1
+4885,0
+4886,0
+4887,1
+4888,0
+4889,0
+4890,2
+4891,3
+4892,3
+4893,2
+4894,0
+4895,2
+4896,1
+4897,0
+4898,1
+4899,3
+4900,2
+4901,0
+4902,0
+4903,0
+4904,1
+4905,2
+4906,3
+4907,0
+4908,0
+4909,0
+4910,3
+4911,1
+4912,2
+4913,3
+4914,1
+4915,2
+4916,3
+4917,3
+4918,3
+4919,3
+4920,0
+4921,0
+4922,2
+4923,0
+4924,3
+4925,1
+4926,2
+4927,0
+4928,0
+4929,2
+4930,0
+4931,0
+4932,3
+4933,3
+4934,1
+4935,1
+4936,3
+4937,3
+4938,1
+4939,0
+4940,0
+4941,3
+4942,2
+4943,0
+4944,3
+4945,2
+4946,0
+4947,0
+4948,3
+4949,0
+4950,0
+4951,3
+4952,0
+4953,0
+4954,0
+4955,3
+4956,3
+4957,1
+4958,0
+4959,1
+4960,1
+4961,0
+4962,0
+4963,0
+4964,2
+4965,0
+4966,0
+4967,0
+4968,1
+4969,0
+4970,0
+4971,0
+4972,1
+4973,2
+4974,0
+4975,0
+4976,0
+4977,0
+4978,3
+4979,2
+4980,0
+4981,0
+4982,3
+4983,0
+4984,0
+4985,3
+4986,2
+4987,3
+4988,0
+4989,2
+4990,0
+4991,0
+4992,0
+4993,0
+4994,0
+4995,0
+4996,3
+4997,0
+4998,2
+4999,3
+5000,0
+5001,0
+5002,0
+5003,1
+5004,3
+5005,0
+5006,0
+5007,0
+5008,0
+5009,0
+5010,2
+5011,1
+5012,0
+5013,2
+5014,3
+5015,2
+5016,0
+5017,0
+5018,0
+5019,0
+5020,3
+5021,3
+5022,0
+5023,0
+5024,2
+5025,3
+5026,0
+5027,3
+5028,3
+5029,3
+5030,0
+5031,0
+5032,3
+5033,0
+5034,0
+5035,1
+5036,0
+5037,1
+5038,3
+5039,0
+5040,0
+5041,3
+5042,2
+5043,3
+5044,1
+5045,2
+5046,0
+5047,0
+5048,0
+5049,0
+5050,0
+5051,2
+5052,0
+5053,1
+5054,0
+5055,0
+5056,0
+5057,3
+5058,1
+5059,2
+5060,2
+5061,2
+5062,2
+5063,1
+5064,1
+5065,2
+5066,3
+5067,0
+5068,2
+5069,0
+5070,3
+5071,0
+5072,0
+5073,0
+5074,0
+5075,1
+5076,1
+5077,0
+5078,2
+5079,2
+5080,0
+5081,3
+5082,0
+5083,0
+5084,0
+5085,2
+5086,0
+5087,0
+5088,0
+5089,3
+5090,0
+5091,0
+5092,0
+5093,2
+5094,0
+5095,0
+5096,1
+5097,0
+5098,0
+5099,1
+5100,3
+5101,3
+5102,0
+5103,0
+5104,0
+5105,3
+5106,0
+5107,2
+5108,3
+5109,0
+5110,0
+5111,3
+5112,2
+5113,1
+5114,3
+5115,2
+5116,1
+5117,0
+5118,0
+5119,2
+5120,2
+5121,2
+5122,1
+5123,0
+5124,0
+5125,0
+5126,0
+5127,2
+5128,0
+5129,0
+5130,0
+5131,1
+5132,0
+5133,1
+5134,0
+5135,0
+5136,1
+5137,0
+5138,0
+5139,0
+5140,3
+5141,0
+5142,2
+5143,2
+5144,2
+5145,1
+5146,3
+5147,1
+5148,0
+5149,0
+5150,0
+5151,2
+5152,2
+5153,0
+5154,0
+5155,0
+5156,0
+5157,2
+5158,3
+5159,0
+5160,1
+5161,2
+5162,2
+5163,0
+5164,0
+5165,0
+5166,0
+5167,0
+5168,0
+5169,0
+5170,0
+5171,0
+5172,3
+5173,0
+5174,0
+5175,1
+5176,0
+5177,3
+5178,2
+5179,1
+5180,3
+5181,3
+5182,2
+5183,1
+5184,1
+5185,0
+5186,0
+5187,0
+5188,3
+5189,2
+5190,0
+5191,0
+5192,0
+5193,1
+5194,0
+5195,0
+5196,2
+5197,2
+5198,0
+5199,3
+5200,3
+5201,0
+5202,0
+5203,3
+5204,3
+5205,1
+5206,2
+5207,3
+5208,0
+5209,1
+5210,3
+5211,0
+5212,2
+5213,0
+5214,0
+5215,0
+5216,3
+5217,3
+5218,2
+5219,2
+5220,0
+5221,2
+5222,1
+5223,0
+5224,1
+5225,3
+5226,0
+5227,0
+5228,2
+5229,0
+5230,3
+5231,0
+5232,2
+5233,3
+5234,1
+5235,1
+5236,0
+5237,0
+5238,2
+5239,0
+5240,0
+5241,0
+5242,2
+5243,3
+5244,0
+5245,3
+5246,3
+5247,2
+5248,0
+5249,0
+5250,3
+5251,0
+5252,3
+5253,0
+5254,2
+5255,0
+5256,2
+5257,0
+5258,0
+5259,3
+5260,3
+5261,2
+5262,0
+5263,0
+5264,1
+5265,3
+5266,0
+5267,0
+5268,0
+5269,1
+5270,3
+5271,2
+5272,3
+5273,0
+5274,3
+5275,2
+5276,0
+5277,0
+5278,3
+5279,2
+5280,3
+5281,0
+5282,1
+5283,0
+5284,3
+5285,0
+5286,0
+5287,0
+5288,1
+5289,2
+5290,1
+5291,1
+5292,0
+5293,0
+5294,2
+5295,2
+5296,0
+5297,0
+5298,0
+5299,3
+5300,0
+5301,0
+5302,0
+5303,0
+5304,0
+5305,2
+5306,1
+5307,3
+5308,0
+5309,0
+5310,3
+5311,2
+5312,0
+5313,0
+5314,0
+5315,3
+5316,2
+5317,1
+5318,3
+5319,3
+5320,2
+5321,0
+5322,0
+5323,0
+5324,3
+5325,2
+5326,0
+5327,0
+5328,1
+5329,1
+5330,0
+5331,0
+5332,0
+5333,2
+5334,3
+5335,2
+5336,0
+5337,0
+5338,1
+5339,2
+5340,2
+5341,0
+5342,0
+5343,3
+5344,0
+5345,1
+5346,1
+5347,0
+5348,1
+5349,0
+5350,0
+5351,1
+5352,0
+5353,3
+5354,3
+5355,3
+5356,3
+5357,2
+5358,3
+5359,0
+5360,0
+5361,3
+5362,1
+5363,1
+5364,0
+5365,3
+5366,2
+5367,0
+5368,3
+5369,3
+5370,3
+5371,2
+5372,2
+5373,0
+5374,3
+5375,0
+5376,3
+5377,2
+5378,0
+5379,0
+5380,0
+5381,0
+5382,0
+5383,0
+5384,0
+5385,0
+5386,0
+5387,0
+5388,2
+5389,3
+5390,0
+5391,1
+5392,3
+5393,1
+5394,0
+5395,1
+5396,3
+5397,0
+5398,2
+5399,0
+5400,3
+5401,3
+5402,2
+5403,1
+5404,0
+5405,0
+5406,0
+5407,0
+5408,3
+5409,2
+5410,3
+5411,1
+5412,3
+5413,3
+5414,0
+5415,2
+5416,2
+5417,3
+5418,3
+5419,0
+5420,2
+5421,1
+5422,1
+5423,3
+5424,0
+5425,1
+5426,3
+5427,0
+5428,0
+5429,0
+5430,1
+5431,2
+5432,0
+5433,1
+5434,0
+5435,3
+5436,0
+5437,0
+5438,1
+5439,3
+5440,1
+5441,3
+5442,3
+5443,3
+5444,1
+5445,0
+5446,2
+5447,0
+5448,0
+5449,1
+5450,0
+5451,2
+5452,3
+5453,1
+5454,0
+5455,0
+5456,0
+5457,0
+5458,0
+5459,0
+5460,2
+5461,0
+5462,1
+5463,0
+5464,0
+5465,0
+5466,0
+5467,0
+5468,1
+5469,0
+5470,0
+5471,0
+5472,0
+5473,0
+5474,0
+5475,1
+5476,3
+5477,2
+5478,0
+5479,0
+5480,0
+5481,2
+5482,2
+5483,1
+5484,0
+5485,0
+5486,1
+5487,0
+5488,0
+5489,3
+5490,0
+5491,0
+5492,2
+5493,2
+5494,1
+5495,0
+5496,0
+5497,0
+5498,0
+5499,3
+5500,2
+5501,0
+5502,0
+5503,0
+5504,3
+5505,3
+5506,3
+5507,0
+5508,3
+5509,3
+5510,3
+5511,2
+5512,3
+5513,0
+5514,3
+5515,3
+5516,3
+5517,3
+5518,2
+5519,0
+5520,0
+5521,3
+5522,0
+5523,3
+5524,3
+5525,3
+5526,3
+5527,3
+5528,1
+5529,0
+5530,2
+5531,0
+5532,0
+5533,3
+5534,0
+5535,1
+5536,2
+5537,3
+5538,0
+5539,0
+5540,2
+5541,2
+5542,0
+5543,1
+5544,2
+5545,0
+5546,0
+5547,3
+5548,3
+5549,0
+5550,3
+5551,0
+5552,1
+5553,0
+5554,0
+5555,0
+5556,1
+5557,0
+5558,0
+5559,0
+5560,0
+5561,1
+5562,0
+5563,3
+5564,2
+5565,1
+5566,3
+5567,2
+5568,0
+5569,2
+5570,0
+5571,0
+5572,0
+5573,2
+5574,0
+5575,2
+5576,1
+5577,0
+5578,3
+5579,0
+5580,0
+5581,0
+5582,0
+5583,3
+5584,1
+5585,3
+5586,1
+5587,0
+5588,0
+5589,1
+5590,3
+5591,3
+5592,2
+5593,2
+5594,2
+5595,2
+5596,1
+5597,0
+5598,0
+5599,1
+5600,0
+5601,1
+5602,2
+5603,3
+5604,3
+5605,2
+5606,3
+5607,3
+5608,2
+5609,0
+5610,2
+5611,3
+5612,1
+5613,2
+5614,3
+5615,0
+5616,0
+5617,0
+5618,1
+5619,1
+5620,3
+5621,0
+5622,3
+5623,0
+5624,0
+5625,0
+5626,3
+5627,3
+5628,3
+5629,2
+5630,2
+5631,2
+5632,0
+5633,3
+5634,2
+5635,0
+5636,0
+5637,0
+5638,2
+5639,0
+5640,0
+5641,2
+5642,0
+5643,0
+5644,0
+5645,3
+5646,2
+5647,2
+5648,1
+5649,3
+5650,2
+5651,1
+5652,0
+5653,0
+5654,0
+5655,1
+5656,3
+5657,0
+5658,3
+5659,0
+5660,0
+5661,0
+5662,3
+5663,2
+5664,3
+5665,0
+5666,2
+5667,1
+5668,2
+5669,0
+5670,2
+5671,0
+5672,0
+5673,3
+5674,1
+5675,2
+5676,3
+5677,3
+5678,1
+5679,3
+5680,0
+5681,1
+5682,0
+5683,0
+5684,0
+5685,0
+5686,1
+5687,3
+5688,0
+5689,1
+5690,0
+5691,0
+5692,0
+5693,2
+5694,0
+5695,0
+5696,0
+5697,2
+5698,3
+5699,0
+5700,2
+5701,3
+5702,2
+5703,3
+5704,0
+5705,0
+5706,0
+5707,0
+5708,0
+5709,0
+5710,3
+5711,2
+5712,0
+5713,0
+5714,0
+5715,0
+5716,2
+5717,0
+5718,2
+5719,0
+5720,0
+5721,0
+5722,2
+5723,1
+5724,3
+5725,2
+5726,0
+5727,3
+5728,3
+5729,0
+5730,0
+5731,0
+5732,0
+5733,0
+5734,1
+5735,0
+5736,3
+5737,3
+5738,0
+5739,0
+5740,0
+5741,0
+5742,3
+5743,0
+5744,1
+5745,0
+5746,1
+5747,3
+5748,1
+5749,0
+5750,0
+5751,1
+5752,0
+5753,0
+5754,3
+5755,0
+5756,0
+5757,3
+5758,0
+5759,0
+5760,0
+5761,2
+5762,3
+5763,1
+5764,1
+5765,0
+5766,0
+5767,2
+5768,3
+5769,0
+5770,2
+5771,0
+5772,2
+5773,1
+5774,0
+5775,0
+5776,1
+5777,0
+5778,0
+5779,3
+5780,2
+5781,0
+5782,3
+5783,2
+5784,3
+5785,0
+5786,1
+5787,2
+5788,3
+5789,0
+5790,0
+5791,2
+5792,0
+5793,2
+5794,2
+5795,1
+5796,0
+5797,3
+5798,2
+5799,0
+5800,0
+5801,2
+5802,3
+5803,3
+5804,1
+5805,3
+5806,3
+5807,3
+5808,1
+5809,1
+5810,0
+5811,0
+5812,0
+5813,0
+5814,1
+5815,0
+5816,1
+5817,3
+5818,3
+5819,3
+5820,0
+5821,1
+5822,3
+5823,1
+5824,3
+5825,0
+5826,1
+5827,0
+5828,0
+5829,0
+5830,0
+5831,3
+5832,0
+5833,2
+5834,0
+5835,2
+5836,3
+5837,2
+5838,2
+5839,0
+5840,2
+5841,2
+5842,1
+5843,0
+5844,1
+5845,2
+5846,0
+5847,2
+5848,1
+5849,0
+5850,1
+5851,1
+5852,2
+5853,2
+5854,0
+5855,3
+5856,0
+5857,2
+5858,0
+5859,1
+5860,3
+5861,3
+5862,3
+5863,3
+5864,1
+5865,2
+5866,0
+5867,2
+5868,0
+5869,0
+5870,2
+5871,1
+5872,1
+5873,0
+5874,0
+5875,0
+5876,2
+5877,2
+5878,2
+5879,0
+5880,1
+5881,1
+5882,1
+5883,0
+5884,2
+5885,0
+5886,3
+5887,0
+5888,0
+5889,0
+5890,2
+5891,1
+5892,0
+5893,0
+5894,3
+5895,1
+5896,0
+5897,0
+5898,2
+5899,0
+5900,0
+5901,3
+5902,1
+5903,2
+5904,0
+5905,3
+5906,0
+5907,3
+5908,0
+5909,3
+5910,0
+5911,3
+5912,3
+5913,2
+5914,0
+5915,0
+5916,0
+5917,3
+5918,2
+5919,0
+5920,1
+5921,3
+5922,0
+5923,0
+5924,3
+5925,0
+5926,2
+5927,2
+5928,0
+5929,0
+5930,0
+5931,2
+5932,0
+5933,0
+5934,3
+5935,0
+5936,0
+5937,2
+5938,0
+5939,2
+5940,1
+5941,1
+5942,1
+5943,3
+5944,0
+5945,1
+5946,0
+5947,2
+5948,3
+5949,0
+5950,2
+5951,2
+5952,1
+5953,2
+5954,0
+5955,0
+5956,3
+5957,1
+5958,0
+5959,3
+5960,3
+5961,0
+5962,2
+5963,0
+5964,0
+5965,0
+5966,3
+5967,0
+5968,3
+5969,0
+5970,3
+5971,0
+5972,2
+5973,1
+5974,1
+5975,0
+5976,0
+5977,1
+5978,2
+5979,3
+5980,2
+5981,1
+5982,0
+5983,3
+5984,3
+5985,2
+5986,3
+5987,1
+5988,2
+5989,0
+5990,0
+5991,1
+5992,3
+5993,0
+5994,0
+5995,0
+5996,2
+5997,2
+5998,0
+5999,3
+6000,0
+6001,3
+6002,1
+6003,0
+6004,3
+6005,1
+6006,3
+6007,0
+6008,0
+6009,2
+6010,3
+6011,2
+6012,0
+6013,3
+6014,0
+6015,3
+6016,3
+6017,3
+6018,0
+6019,2
+6020,0
+6021,0
+6022,2
+6023,3
+6024,3
+6025,1
+6026,0
+6027,0
+6028,0
+6029,0
+6030,3
+6031,0
+6032,0
+6033,3
+6034,0
+6035,2
+6036,0
+6037,0
+6038,2
+6039,0
+6040,2
+6041,2
+6042,2
+6043,1
+6044,0
+6045,1
+6046,2
+6047,1
+6048,1
+6049,0
+6050,1
+6051,0
+6052,3
+6053,0
+6054,0
+6055,0
+6056,3
+6057,1
+6058,2
+6059,2
+6060,0
+6061,0
+6062,3
+6063,3
+6064,3
+6065,2
+6066,0
+6067,1
+6068,2
+6069,0
+6070,0
+6071,2
+6072,0
+6073,2
+6074,2
+6075,1
+6076,0
+6077,1
+6078,0
+6079,2
+6080,3
+6081,2
+6082,0
+6083,0
+6084,0
+6085,2
+6086,2
+6087,1
+6088,1
+6089,3
+6090,3
+6091,0
+6092,0
+6093,0
+6094,1
+6095,3
+6096,0
+6097,3
+6098,1
+6099,2
+6100,0
+6101,2
+6102,0
+6103,2
+6104,0
+6105,0
+6106,0
+6107,0
+6108,0
+6109,0
+6110,2
+6111,1
+6112,0
+6113,0
+6114,2
+6115,3
+6116,0
+6117,0
+6118,0
+6119,0
+6120,0
+6121,2
+6122,3
+6123,0
+6124,3
+6125,2
+6126,0
+6127,2
+6128,0
+6129,0
+6130,1
+6131,0
+6132,0
+6133,0
+6134,3
+6135,0
+6136,0
+6137,3
+6138,0
+6139,2
+6140,2
+6141,0
+6142,2
+6143,2
+6144,3
+6145,3
+6146,0
+6147,1
+6148,0
+6149,0
+6150,0
+6151,2
+6152,0
+6153,2
+6154,0
+6155,3
+6156,1
+6157,3
+6158,2
+6159,0
+6160,0
+6161,0
+6162,0
+6163,0
+6164,3
+6165,0
+6166,1
+6167,0
+6168,2
+6169,0
+6170,0
+6171,2
+6172,0
+6173,2
+6174,0
+6175,3
+6176,0
+6177,2
+6178,2
+6179,2
+6180,1
+6181,3
+6182,3
+6183,0
+6184,0
+6185,2
+6186,0
+6187,0
+6188,3
+6189,0
+6190,0
+6191,3
+6192,2
+6193,0
+6194,2
+6195,3
+6196,0
+6197,2
+6198,0
+6199,0
+6200,0
+6201,1
+6202,2
+6203,0
+6204,0
+6205,0
+6206,0
+6207,1
+6208,3
+6209,2
+6210,2
+6211,1
+6212,3
+6213,2
+6214,0
+6215,3
+6216,3
+6217,1
+6218,1
+6219,0
+6220,0
+6221,0
+6222,0
+6223,0
+6224,1
+6225,0
+6226,1
+6227,3
+6228,1
+6229,0
+6230,0
+6231,0
+6232,0
+6233,3
+6234,2
+6235,3
+6236,0
+6237,0
+6238,0
+6239,0
+6240,0
+6241,0
+6242,0
+6243,1
+6244,0
+6245,2
+6246,2
+6247,0
+6248,0
+6249,0
+6250,3
+6251,1
+6252,1
+6253,0
+6254,0
+6255,0
+6256,3
+6257,0
+6258,0
+6259,3
+6260,0
+6261,0
+6262,2
+6263,2
+6264,3
+6265,3
+6266,3
+6267,0
+6268,0
+6269,3
+6270,0
+6271,2
+6272,2
+6273,0
+6274,3
+6275,2
+6276,2
+6277,0
+6278,0
+6279,1
+6280,1
+6281,2
+6282,0
+6283,0
+6284,1
+6285,0
+6286,0
+6287,3
+6288,2
+6289,1
+6290,3
+6291,3
+6292,0
+6293,0
+6294,3
+6295,0
+6296,1
+6297,0
+6298,0
+6299,2
+6300,3
+6301,3
+6302,2
+6303,0
+6304,2
+6305,0
+6306,0
+6307,0
+6308,0
+6309,2
+6310,1
+6311,3
+6312,2
+6313,0
+6314,3
+6315,3
+6316,3
+6317,2
+6318,3
+6319,3
+6320,3
+6321,3
+6322,3
+6323,2
+6324,2
+6325,0
+6326,3
+6327,0
+6328,2
+6329,0
+6330,0
+6331,0
+6332,3
+6333,0
+6334,3
+6335,0
+6336,3
+6337,0
+6338,0
+6339,0
+6340,3
+6341,0
+6342,0
+6343,2
+6344,0
+6345,1
+6346,1
+6347,3
+6348,2
+6349,1
+6350,0
+6351,0
+6352,3
+6353,2
+6354,0
+6355,0
+6356,0
+6357,3
+6358,3
+6359,2
+6360,0
+6361,0
+6362,3
+6363,2
+6364,3
+6365,3
+6366,2
+6367,1
+6368,0
+6369,3
+6370,2
+6371,3
+6372,0
+6373,3
+6374,0
+6375,0
+6376,2
+6377,0
+6378,0
+6379,0
+6380,2
+6381,1
+6382,3
+6383,2
+6384,0
+6385,3
+6386,2
+6387,0
+6388,0
+6389,3
+6390,3
+6391,3
+6392,3
+6393,0
+6394,3
+6395,0
+6396,3
+6397,0
+6398,0
+6399,1
+6400,1
+6401,0
+6402,1
+6403,0
+6404,3
+6405,3
+6406,2
+6407,0
+6408,2
+6409,3
+6410,1
+6411,2
+6412,2
+6413,0
+6414,0
+6415,0
+6416,2
+6417,0
+6418,0
+6419,1
+6420,0
+6421,2
+6422,3
+6423,2
+6424,0
+6425,2
+6426,1
+6427,0
+6428,0
+6429,0
+6430,2
+6431,0
+6432,2
+6433,1
+6434,2
+6435,1
+6436,1
+6437,2
+6438,3
+6439,1
+6440,3
+6441,2
+6442,2
+6443,0
+6444,1
+6445,0
+6446,3
+6447,0
+6448,0
+6449,2
+6450,3
+6451,0
+6452,3
+6453,0
+6454,3
+6455,0
+6456,0
+6457,0
+6458,3
+6459,2
+6460,0
+6461,3
+6462,2
+6463,0
+6464,2
+6465,0
+6466,0
+6467,1
+6468,1
+6469,1
+6470,0
+6471,0
+6472,0
+6473,2
+6474,0
+6475,1
+6476,2
+6477,3
+6478,0
+6479,2
+6480,3
+6481,3
+6482,2
+6483,2
+6484,2
+6485,3
+6486,0
+6487,1
+6488,0
+6489,0
+6490,0
+6491,0
+6492,0
+6493,2
+6494,3
+6495,0
+6496,2
+6497,0
+6498,2
+6499,3
+6500,3
+6501,1
+6502,0
+6503,3
+6504,0
+6505,0
+6506,3
+6507,0
+6508,3
+6509,3
+6510,0
+6511,2
+6512,3
+6513,3
+6514,1
+6515,1
+6516,2
+6517,1
+6518,2
+6519,0
+6520,2
+6521,3
+6522,0
+6523,0
+6524,1
+6525,0
+6526,3
+6527,3
+6528,0
+6529,1
+6530,1
+6531,0
+6532,0
+6533,0
+6534,0
+6535,0
+6536,3
+6537,2
+6538,2
+6539,2
+6540,0
+6541,0
+6542,0
+6543,0
+6544,0
+6545,1
+6546,3
+6547,0
+6548,0
+6549,1
+6550,1
+6551,0
+6552,0
+6553,2
+6554,2
+6555,0
+6556,2
+6557,2
+6558,1
+6559,3
+6560,2
+6561,1
+6562,1
+6563,2
+6564,0
+6565,0
+6566,3
+6567,3
+6568,0
+6569,2
+6570,1
+6571,2
+6572,0
+6573,0
+6574,0
+6575,3
+6576,0
+6577,3
+6578,0
+6579,0
+6580,1
+6581,0
+6582,3
+6583,0
+6584,1
+6585,0
+6586,0
+6587,0
+6588,3
+6589,0
+6590,0
+6591,0
+6592,0
+6593,3
+6594,0
+6595,0
+6596,0
+6597,2
+6598,2
+6599,3
+6600,3
+6601,0
+6602,0
+6603,0
+6604,3
+6605,3
+6606,3
+6607,2
+6608,1
+6609,0
+6610,0
+6611,1
+6612,2
+6613,3
+6614,2
+6615,0
+6616,2
+6617,3
+6618,2
+6619,0
+6620,0
+6621,0
+6622,3
+6623,3
+6624,0
+6625,1
+6626,0
+6627,3
+6628,0
+6629,0
+6630,3
+6631,3
+6632,2
+6633,2
+6634,0
+6635,1
+6636,0
+6637,2
+6638,2
+6639,0
+6640,3
+6641,1
+6642,0
+6643,3
+6644,2
+6645,0
+6646,0
+6647,0
+6648,3
+6649,3
+6650,0
+6651,0
+6652,0
+6653,3
+6654,3
+6655,0
+6656,0
+6657,0
+6658,2
+6659,1
+6660,3
+6661,3
+6662,2
+6663,0
+6664,0
+6665,0
+6666,0
+6667,0
+6668,0
+6669,3
+6670,0
+6671,3
+6672,0
+6673,0
+6674,0
+6675,1
+6676,2
+6677,0
+6678,2
+6679,2
+6680,0
+6681,0
+6682,0
+6683,0
+6684,3
+6685,2
+6686,2
+6687,1
+6688,2
+6689,0
+6690,0
+6691,2
+6692,3
+6693,1
+6694,3
+6695,0
+6696,2
+6697,0
+6698,3
+6699,0
+6700,2
+6701,0
+6702,3
+6703,1
+6704,0
+6705,2
+6706,1
+6707,2
+6708,1
+6709,3
+6710,0
+6711,2
+6712,0
+6713,2
+6714,0
+6715,0
+6716,3
+6717,3
+6718,2
+6719,2
+6720,2
+6721,0
+6722,0
+6723,0
+6724,0
+6725,0
+6726,0
+6727,1
+6728,1
+6729,0
+6730,0
+6731,1
+6732,2
+6733,0
+6734,0
+6735,2
+6736,2
+6737,0
+6738,0
+6739,0
+6740,0
+6741,1
+6742,1
+6743,1
+6744,0
+6745,3
+6746,3
+6747,0
+6748,1
+6749,0
+6750,0
+6751,3
+6752,0
+6753,0
+6754,3
+6755,0
+6756,3
+6757,2
+6758,1
+6759,3
+6760,0
+6761,3
+6762,2
+6763,0
+6764,3
+6765,0
+6766,3
+6767,3
+6768,0
+6769,3
+6770,2
+6771,2
+6772,2
+6773,2
+6774,0
+6775,3
+6776,0
+6777,0
+6778,1
+6779,2
+6780,3
+6781,3
+6782,2
+6783,1
+6784,2
+6785,0
+6786,3
+6787,3
+6788,1
+6789,0
+6790,2
+6791,0
+6792,2
+6793,2
+6794,0
+6795,0
+6796,0
+6797,0
+6798,0
+6799,0
+6800,0
+6801,0
+6802,0
+6803,0
+6804,0
+6805,0
+6806,0
+6807,3
+6808,0
+6809,1
+6810,0
+6811,1
+6812,0
+6813,2
+6814,3
+6815,1
+6816,2
+6817,1
+6818,3
+6819,0
+6820,1
+6821,1
+6822,3
+6823,0
+6824,0
+6825,2
+6826,2
+6827,3
+6828,3
+6829,0
+6830,3
+6831,0
+6832,0
+6833,2
+6834,1
+6835,0
+6836,3
+6837,2
+6838,0
+6839,3
+6840,0
+6841,0
+6842,3
+6843,1
+6844,0
+6845,3
+6846,0
+6847,0
+6848,0
+6849,3
+6850,2
+6851,0
+6852,2
+6853,3
+6854,3
+6855,0
+6856,0
+6857,3
+6858,3
+6859,0
+6860,0
+6861,3
+6862,3
+6863,0
+6864,0
+6865,1
+6866,2
+6867,3
+6868,2
+6869,1
+6870,1
+6871,3
+6872,2
+6873,0
+6874,1
+6875,0
+6876,0
+6877,2
+6878,0
+6879,1
+6880,3
+6881,3
+6882,3
+6883,1
+6884,2
+6885,0
+6886,0
+6887,0
+6888,0
+6889,1
+6890,3
+6891,0
+6892,1
+6893,3
+6894,3
+6895,3
+6896,1
+6897,1
+6898,0
+6899,1
+6900,2
+6901,2
+6902,0
+6903,1
+6904,0
+6905,2
+6906,2
+6907,0
+6908,0
+6909,2
+6910,0
+6911,0
+6912,0
+6913,1
+6914,3
+6915,1
+6916,3
+6917,1
+6918,3
+6919,2
+6920,0
+6921,1
+6922,0
+6923,1
+6924,0
+6925,2
+6926,2
+6927,0
+6928,2
+6929,1
+6930,3
+6931,1
+6932,0
+6933,3
+6934,3
+6935,3
+6936,3
+6937,0
+6938,0
+6939,0
+6940,2
+6941,0
+6942,1
+6943,0
+6944,0
+6945,0
+6946,2
+6947,3
+6948,2
+6949,1
+6950,3
+6951,2
+6952,2
+6953,2
+6954,0
+6955,1
+6956,0
+6957,2
+6958,0
+6959,0
+6960,0
+6961,3
+6962,2
+6963,0
+6964,3
+6965,1
+6966,2
+6967,0
+6968,0
+6969,3
+6970,3
+6971,0
+6972,0
+6973,0
+6974,0
+6975,0
+6976,0
+6977,0
+6978,3
+6979,0
+6980,0
+6981,0
+6982,0
+6983,2
+6984,3
+6985,3
+6986,3
+6987,0
+6988,0
+6989,1
+6990,0
+6991,2
+6992,2
+6993,3
+6994,2
+6995,0
+6996,1
+6997,1
+6998,2
+6999,1
+7000,2
+7001,2
+7002,0
+7003,3
+7004,0
+7005,1
+7006,0
+7007,0
+7008,0
+7009,0
+7010,2
+7011,1
+7012,0
+7013,0
+7014,0
+7015,0
+7016,2
+7017,0
+7018,0
+7019,0
+7020,2
+7021,0
+7022,0
+7023,2
+7024,0
+7025,1
+7026,0
+7027,0
+7028,2
+7029,1
+7030,0
+7031,2
+7032,3
+7033,3
+7034,0
+7035,3
+7036,3
+7037,2
+7038,0
+7039,0
+7040,0
+7041,2
+7042,0
+7043,0
+7044,3
+7045,0
+7046,0
+7047,3
+7048,1
+7049,2
+7050,1
+7051,1
+7052,1
+7053,0
+7054,0
+7055,0
+7056,0
+7057,0
+7058,1
+7059,0
+7060,0
+7061,2
+7062,2
+7063,0
+7064,0
+7065,2
+7066,0
+7067,2
+7068,2
+7069,0
+7070,0
+7071,2
+7072,2
+7073,2
+7074,2
+7075,3
+7076,0
+7077,0
+7078,3
+7079,3
+7080,2
+7081,2
+7082,1
+7083,0
+7084,2
+7085,0
+7086,1
+7087,2
+7088,2
+7089,1
+7090,0
+7091,2
+7092,0
+7093,3
+7094,2
+7095,3
+7096,0
+7097,0
+7098,0
+7099,2
+7100,1
+7101,3
+7102,0
+7103,2
+7104,2
+7105,0
+7106,1
+7107,2
+7108,3
+7109,3
+7110,0
+7111,1
+7112,2
+7113,0
+7114,3
+7115,0
+7116,0
+7117,3
+7118,0
+7119,0
+7120,0
+7121,3
+7122,0
+7123,0
+7124,3
+7125,2
+7126,2
+7127,1
+7128,0
+7129,0
+7130,0
+7131,2
+7132,2
+7133,0
+7134,0
+7135,1
+7136,1
+7137,0
+7138,0
+7139,2
+7140,1
+7141,1
+7142,0
+7143,3
+7144,0
+7145,3
+7146,0
+7147,2
+7148,0
+7149,0
+7150,3
+7151,3
+7152,3
+7153,0
+7154,2
+7155,0
+7156,2
+7157,3
+7158,3
+7159,3
+7160,1
+7161,1
+7162,1
+7163,2
+7164,3
+7165,0
+7166,1
+7167,0
+7168,0
+7169,0
+7170,2
+7171,0
+7172,0
+7173,3
+7174,3
+7175,3
+7176,2
+7177,2
+7178,0
+7179,3
+7180,0
+7181,2
+7182,1
+7183,3
+7184,0
+7185,0
+7186,0
+7187,3
+7188,0
+7189,3
+7190,0
+7191,3
+7192,0
+7193,2
+7194,3
+7195,0
+7196,2
+7197,0
+7198,0
+7199,0
+7200,1
+7201,0
+7202,3
+7203,0
+7204,0
+7205,0
+7206,2
+7207,0
+7208,0
+7209,2
+7210,1
+7211,3
+7212,3
+7213,3
+7214,0
+7215,0
+7216,0
+7217,1
+7218,0
+7219,1
+7220,1
+7221,0
+7222,1
+7223,2
+7224,0
+7225,0
+7226,3
+7227,3
+7228,2
+7229,0
+7230,2
+7231,2
+7232,2
+7233,0
+7234,0
+7235,0
+7236,1
+7237,0
+7238,1
+7239,3
+7240,1
+7241,3
+7242,3
+7243,2
+7244,2
+7245,3
+7246,2
+7247,2
+7248,3
+7249,1
+7250,0
+7251,2
+7252,1
+7253,2
+7254,2
+7255,2
+7256,2
+7257,3
+7258,0
+7259,0
+7260,0
+7261,0
+7262,2
+7263,1
+7264,0
+7265,0
+7266,1
+7267,0
+7268,0
+7269,3
+7270,1
+7271,2
+7272,0
+7273,3
+7274,2
+7275,1
+7276,3
+7277,0
+7278,0
+7279,2
+7280,1
+7281,3
+7282,1
+7283,3
+7284,3
+7285,0
+7286,1
+7287,3
+7288,3
+7289,1
+7290,3
+7291,0
+7292,1
+7293,3
+7294,2
+7295,2
+7296,2
+7297,0
+7298,0
+7299,1
+7300,2
+7301,1
+7302,2
+7303,0
+7304,1
+7305,0
+7306,3
+7307,0
+7308,1
+7309,0
+7310,0
+7311,2
+7312,3
+7313,1
+7314,3
+7315,0
+7316,1
+7317,1
+7318,1
+7319,0
+7320,0
+7321,2
+7322,0
+7323,3
+7324,0
+7325,0
+7326,0
+7327,2
+7328,3
+7329,0
+7330,0
+7331,0
+7332,3
+7333,3
+7334,0
+7335,1
+7336,0
+7337,3
+7338,3
+7339,2
+7340,2
+7341,1
+7342,0
+7343,1
+7344,3
+7345,3
+7346,0
+7347,2
+7348,3
+7349,1
+7350,0
+7351,3
+7352,2
+7353,0
+7354,2
+7355,0
+7356,1
+7357,1
+7358,0
+7359,3
+7360,0
+7361,0
+7362,1
+7363,3
+7364,0
+7365,1
+7366,2
+7367,0
+7368,0
+7369,2
+7370,3
+7371,1
+7372,0
+7373,0
+7374,0
+7375,1
+7376,2
+7377,0
+7378,2
+7379,0
+7380,0
+7381,2
+7382,0
+7383,1
+7384,2
+7385,2
+7386,2
+7387,0
+7388,0
+7389,2
+7390,0
+7391,0
+7392,1
+7393,0
+7394,3
+7395,2
+7396,1
+7397,2
+7398,0
+7399,3
+7400,2
+7401,2
+7402,0
+7403,1
+7404,0
+7405,0
+7406,1
+7407,0
+7408,0
+7409,2
+7410,2
+7411,3
+7412,0
+7413,0
+7414,0
+7415,3
+7416,3
+7417,0
+7418,2
+7419,1
+7420,3
+7421,0
+7422,3
+7423,3
+7424,1
+7425,3
+7426,0
+7427,0
+7428,3
+7429,0
+7430,3
+7431,2
+7432,3
+7433,2
+7434,0
+7435,1
+7436,0
+7437,0
+7438,0
+7439,2
+7440,0
+7441,2
+7442,3
+7443,3
+7444,1
+7445,0
+7446,0
+7447,0
+7448,0
+7449,0
+7450,1
+7451,2
+7452,3
+7453,0
+7454,0
+7455,0
+7456,3
+7457,0
+7458,2
+7459,0
+7460,2
+7461,0
+7462,0
+7463,0
+7464,3
+7465,3
+7466,2
+7467,0
+7468,0
+7469,3
+7470,3
+7471,3
+7472,2
+7473,1
+7474,0
+7475,0
+7476,1
+7477,2
+7478,0
+7479,0
+7480,0
+7481,0
+7482,3
+7483,0
+7484,2
+7485,3
+7486,2
+7487,2
+7488,0
+7489,0
+7490,0
+7491,0
+7492,2
+7493,0
+7494,3
+7495,0
+7496,0
+7497,3
+7498,0
+7499,3
+7500,0
+7501,0
+7502,0
+7503,3
+7504,1
+7505,0
+7506,0
+7507,0
+7508,0
+7509,2
+7510,3
+7511,0
+7512,3
+7513,3
+7514,1
+7515,2
+7516,1
+7517,2
+7518,0
+7519,3
+7520,1
+7521,3
+7522,0
+7523,0
+7524,0
+7525,1
+7526,0
+7527,3
+7528,0
+7529,0
+7530,2
+7531,2
+7532,0
+7533,2
+7534,0
+7535,2
+7536,3
+7537,2
+7538,0
+7539,0
+7540,0
+7541,2
+7542,0
+7543,0
+7544,0
+7545,2
+7546,3
+7547,0
+7548,3
+7549,0
+7550,2
+7551,0
+7552,0
+7553,2
+7554,3
+7555,3
+7556,3
+7557,0
+7558,3
+7559,1
+7560,0
+7561,2
+7562,0
+7563,3
+7564,3
+7565,3
+7566,2
+7567,0
+7568,0
+7569,3
+7570,0
+7571,3
+7572,0
+7573,2
+7574,2
+7575,1
+7576,3
+7577,0
+7578,1
+7579,0
+7580,0
+7581,0
+7582,2
+7583,1
+7584,0
+7585,0
+7586,0
+7587,1
+7588,0
+7589,0
+7590,0
+7591,3
+7592,2
+7593,0
+7594,3
+7595,0
+7596,2
+7597,1
+7598,1
+7599,0
+7600,3
+7601,3
+7602,0
+7603,0
+7604,1
+7605,0
+7606,3
+7607,2
+7608,0
+7609,3
+7610,3
+7611,0
+7612,0
+7613,0
+7614,0
+7615,3
+7616,2
+7617,0
+7618,0
+7619,1
+7620,0
+7621,1
+7622,0
+7623,3
+7624,0
+7625,1
+7626,3
+7627,0
+7628,3
+7629,0
+7630,0
+7631,0
+7632,1
+7633,3
+7634,3
+7635,1
+7636,0
+7637,1
+7638,2
+7639,3
+7640,2
+7641,2
+7642,0
+7643,2
+7644,0
+7645,2
+7646,3
+7647,1
+7648,2
+7649,0
+7650,1
+7651,3
+7652,2
+7653,1
+7654,2
+7655,0
+7656,0
+7657,3
+7658,0
+7659,3
+7660,2
+7661,0
+7662,0
+7663,3
+7664,2
+7665,0
+7666,2
+7667,0
+7668,0
+7669,3
+7670,2
+7671,0
+7672,0
+7673,2
+7674,2
+7675,2
+7676,0
+7677,0
+7678,1
+7679,3
+7680,0
+7681,1
+7682,3
+7683,0
+7684,2
+7685,0
+7686,0
+7687,2
+7688,0
+7689,1
+7690,0
+7691,1
+7692,0
+7693,2
+7694,3
+7695,3
+7696,0
+7697,0
+7698,0
+7699,2
+7700,2
+7701,2
+7702,3
+7703,0
+7704,0
+7705,2
+7706,0
+7707,3
+7708,3
+7709,0
+7710,2
+7711,0
+7712,0
+7713,2
+7714,3
+7715,1
+7716,3
+7717,0
+7718,3
+7719,3
+7720,0
+7721,0
+7722,0
+7723,1
+7724,0
+7725,2
+7726,0
+7727,0
+7728,0
+7729,1
+7730,0
+7731,3
+7732,3
+7733,0
+7734,2
+7735,1
+7736,2
+7737,3
+7738,1
+7739,0
+7740,3
+7741,3
+7742,0
+7743,0
+7744,3
+7745,0
+7746,0
+7747,3
+7748,1
+7749,3
+7750,0
+7751,3
+7752,0
+7753,2
+7754,0
+7755,0
+7756,1
+7757,1
+7758,1
+7759,1
+7760,3
+7761,0
+7762,2
+7763,0
+7764,0
+7765,0
+7766,3
+7767,2
+7768,3
+7769,3
+7770,0
+7771,3
+7772,0
+7773,0
+7774,3
+7775,2
+7776,1
+7777,3
+7778,1
+7779,3
+7780,3
+7781,0
+7782,0
+7783,1
+7784,2
+7785,1
+7786,2
+7787,3
+7788,1
+7789,0
+7790,3
+7791,0
+7792,2
+7793,3
+7794,0
+7795,3
+7796,2
+7797,2
+7798,3
+7799,0
+7800,3
+7801,3
+7802,3
+7803,3
+7804,0
+7805,3
+7806,1
+7807,0
+7808,3
+7809,0
+7810,3
+7811,3
+7812,2
+7813,1
+7814,0
+7815,2
+7816,0
+7817,1
+7818,2
+7819,3
+7820,0
+7821,0
+7822,0
+7823,3
+7824,0
+7825,3
+7826,0
+7827,3
+7828,3
+7829,1
+7830,0
+7831,0
+7832,0
+7833,1
+7834,0
+7835,3
+7836,3
+7837,0
+7838,0
+7839,1
+7840,1
+7841,0
+7842,2
+7843,0
+7844,0
+7845,0
+7846,3
+7847,0
+7848,0
+7849,0
+7850,2
+7851,0
+7852,0
+7853,1
+7854,0
+7855,3
+7856,1
+7857,0
+7858,0
+7859,3
+7860,0
+7861,0
+7862,0
+7863,0
+7864,3
+7865,0
+7866,1
+7867,0
+7868,3
+7869,3
+7870,0
+7871,0
+7872,0
+7873,2
+7874,3
+7875,3
+7876,2
+7877,0
+7878,2
+7879,0
+7880,2
+7881,1
+7882,0
+7883,0
+7884,2
+7885,0
+7886,0
+7887,2
+7888,2
+7889,1
+7890,0
+7891,3
+7892,1
+7893,2
+7894,3
+7895,0
+7896,0
+7897,1
+7898,2
+7899,3
+7900,0
+7901,0
+7902,1
+7903,1
+7904,0
+7905,1
+7906,2
+7907,0
+7908,0
+7909,3
+7910,1
+7911,2
+7912,2
+7913,2
+7914,0
+7915,3
+7916,3
+7917,0
+7918,0
+7919,0
+7920,1
+7921,0
+7922,3
+7923,0
+7924,1
+7925,0
+7926,1
+7927,2
+7928,1
+7929,0
+7930,0
+7931,1
+7932,3
+7933,2
+7934,1
+7935,0
+7936,1
+7937,0
+7938,0
+7939,0
+7940,3
+7941,0
+7942,0
+7943,1
+7944,2
+7945,0
+7946,2
+7947,0
+7948,0
+7949,2
+7950,0
+7951,0
+7952,0
+7953,1
+7954,0
+7955,3
+7956,3
+7957,3
+7958,3
+7959,2
+7960,3
+7961,0
+7962,1
+7963,3
+7964,0
+7965,0
+7966,0
+7967,0
+7968,1
+7969,0
+7970,2
+7971,2
+7972,2
+7973,3
+7974,0
+7975,3
+7976,0
+7977,2
+7978,1
+7979,1
+7980,0
+7981,0
+7982,2
+7983,3
+7984,3
+7985,0
+7986,0
+7987,2
+7988,2
+7989,0
+7990,3
+7991,2
+7992,0
+7993,0
+7994,0
+7995,1
+7996,1
+7997,2
+7998,1
+7999,0
+8000,0
+8001,0
+8002,1
+8003,3
+8004,0
+8005,3
+8006,2
+8007,2
+8008,1
+8009,1
+8010,2
+8011,0
+8012,0
+8013,3
+8014,3
+8015,0
+8016,3
+8017,3
+8018,0
+8019,0
+8020,3
+8021,0
+8022,0
+8023,3
+8024,0
+8025,0
+8026,2
+8027,1
+8028,3
+8029,0
+8030,2
+8031,2
+8032,2
+8033,2
+8034,0
+8035,0
+8036,3
+8037,2
+8038,0
+8039,3
+8040,3
+8041,0
+8042,3
+8043,0
+8044,2
+8045,3
+8046,0
+8047,0
+8048,0
+8049,2
+8050,0
+8051,3
+8052,2
+8053,0
+8054,0
+8055,1
+8056,2
+8057,3
+8058,0
+8059,1
+8060,1
+8061,1
+8062,0
+8063,0
+8064,3
+8065,2
+8066,0
+8067,0
+8068,1
+8069,0
+8070,3
+8071,0
+8072,1
+8073,1
+8074,2
+8075,2
+8076,0
+8077,0
+8078,0
+8079,0
+8080,0
+8081,0
+8082,1
+8083,3
+8084,3
+8085,0
+8086,3
+8087,0
+8088,0
+8089,0
+8090,0
+8091,0
+8092,0
+8093,0
+8094,0
+8095,3
+8096,2
+8097,2
+8098,0
+8099,3
+8100,3
+8101,2
+8102,2
+8103,0
+8104,0
+8105,3
+8106,1
+8107,0
+8108,3
+8109,2
+8110,1
+8111,0
+8112,0
+8113,3
+8114,2
+8115,1
+8116,1
+8117,0
+8118,2
+8119,0
+8120,0
+8121,0
+8122,2
+8123,2
+8124,0
+8125,3
+8126,0
+8127,1
+8128,0
+8129,0
+8130,1
+8131,0
+8132,3
+8133,1
+8134,1
+8135,1
+8136,2
+8137,2
+8138,1
+8139,1
+8140,0
+8141,2
+8142,2
+8143,0
+8144,0
+8145,1
+8146,1
+8147,2
+8148,3
+8149,3
+8150,3
+8151,3
+8152,1
+8153,0
+8154,2
+8155,2
+8156,0
+8157,0
+8158,0
+8159,2
+8160,0
+8161,2
+8162,2
+8163,2
+8164,3
+8165,3
+8166,3
+8167,3
+8168,0
+8169,3
+8170,0
+8171,1
+8172,1
+8173,0
+8174,3
+8175,1
+8176,0
+8177,3
+8178,0
+8179,3
+8180,1
+8181,0
+8182,1
+8183,3
+8184,3
+8185,2
+8186,2
+8187,2
+8188,3
+8189,2
+8190,3
+8191,0
+8192,0
+8193,0
+8194,1
+8195,1
+8196,1
+8197,0
+8198,2
+8199,3
+8200,3
+8201,0
+8202,3
+8203,3
+8204,1
+8205,0
+8206,2
+8207,0
+8208,3
+8209,0
+8210,0
+8211,1
+8212,3
+8213,0
+8214,0
+8215,0
+8216,3
+8217,2
+8218,1
+8219,3
+8220,0
+8221,3
+8222,2
+8223,0
+8224,0
+8225,0
+8226,1
+8227,0
+8228,0
+8229,0
+8230,3
+8231,0
+8232,3
+8233,0
+8234,2
+8235,3
+8236,3
+8237,0
+8238,2
+8239,0
+8240,0
+8241,0
+8242,0
+8243,0
+8244,0
+8245,0
+8246,3
+8247,0
+8248,2
+8249,3
+8250,0
+8251,0
+8252,1
+8253,2
+8254,0
+8255,3
+8256,0
+8257,0
+8258,0
+8259,3
+8260,3
+8261,3
+8262,1
+8263,0
+8264,0
+8265,3
+8266,3
+8267,0
+8268,2
+8269,3
+8270,2
+8271,0
+8272,0
+8273,3
+8274,0
+8275,3
+8276,3
+8277,0
+8278,2
+8279,0
+8280,2
+8281,0
+8282,0
+8283,3
+8284,2
+8285,0
+8286,0
+8287,2
+8288,2
+8289,0
+8290,0
+8291,0
+8292,0
+8293,1
+8294,0
+8295,0
+8296,1
+8297,1
+8298,0
+8299,1
+8300,3
+8301,0
+8302,0
+8303,1
+8304,0
+8305,0
+8306,2
+8307,2
+8308,3
+8309,0
+8310,3
+8311,3
+8312,0
+8313,0
+8314,0
+8315,3
+8316,0
+8317,2
+8318,3
+8319,0
+8320,0
+8321,0
+8322,0
+8323,0
+8324,2
+8325,2
+8326,0
+8327,3
+8328,2
+8329,0
+8330,2
+8331,3
+8332,3
+8333,1
+8334,0
+8335,0
+8336,3
+8337,2
+8338,0
+8339,3
+8340,0
+8341,1
+8342,2
+8343,0
+8344,1
+8345,0
+8346,0
+8347,0
+8348,3
+8349,2
+8350,3
+8351,3
+8352,0
+8353,2
+8354,3
+8355,0
+8356,2
+8357,3
+8358,0
+8359,3
+8360,0
+8361,3
+8362,3
+8363,2
+8364,3
+8365,0
+8366,2
+8367,2
+8368,2
+8369,1
+8370,3
+8371,0
+8372,3
+8373,1
+8374,3
+8375,3
+8376,0
+8377,2
+8378,2
+8379,0
+8380,2
+8381,3
+8382,0
+8383,0
+8384,3
+8385,0
+8386,2
+8387,3
+8388,1
+8389,2
+8390,2
+8391,1
+8392,3
+8393,0
+8394,0
+8395,2
+8396,3
+8397,0
+8398,0
+8399,2
+8400,0
+8401,1
+8402,3
+8403,3
+8404,3
+8405,0
+8406,2
+8407,0
+8408,0
+8409,0
+8410,0
+8411,3
+8412,2
+8413,1
+8414,3
+8415,2
+8416,0
+8417,0
+8418,3
+8419,0
+8420,3
+8421,2
+8422,2
+8423,2
+8424,3
+8425,0
+8426,0
+8427,0
+8428,0
+8429,2
+8430,3
+8431,1
+8432,2
+8433,0
+8434,0
+8435,3
+8436,1
+8437,0
+8438,0
+8439,3
+8440,0
+8441,0
+8442,2
+8443,2
+8444,1
+8445,2
+8446,1
+8447,0
+8448,2
+8449,0
+8450,0
+8451,3
+8452,0
+8453,2
+8454,1
+8455,0
+8456,1
+8457,0
+8458,0
+8459,0
+8460,0
+8461,2
+8462,0
+8463,3
+8464,1
+8465,0
+8466,2
+8467,0
+8468,3
+8469,2
+8470,0
+8471,1
+8472,0
+8473,1
+8474,3
+8475,0
+8476,0
+8477,3
+8478,2
+8479,2
+8480,0
+8481,0
+8482,3
+8483,2
+8484,2
+8485,3
+8486,2
+8487,2
+8488,1
+8489,0
+8490,2
+8491,1
+8492,2
+8493,2
+8494,0
+8495,0
+8496,0
+8497,2
+8498,0
+8499,0
+8500,3
+8501,2
+8502,2
+8503,2
+8504,1
+8505,2
+8506,0
+8507,0
+8508,1
+8509,3
+8510,0
+8511,0
+8512,3
+8513,0
+8514,0
+8515,0
+8516,3
+8517,0
+8518,3
+8519,3
+8520,3
+8521,0
+8522,0
+8523,1
+8524,2
+8525,1
+8526,0
+8527,2
+8528,1
+8529,0
+8530,0
+8531,2
+8532,1
+8533,3
+8534,3
+8535,2
+8536,2
+8537,0
+8538,2
+8539,2
+8540,0
+8541,2
+8542,3
+8543,2
+8544,0
+8545,0
+8546,0
+8547,2
+8548,0
+8549,3
+8550,0
+8551,0
+8552,3
+8553,2
+8554,0
+8555,1
+8556,2
+8557,0
+8558,0
+8559,3
+8560,3
+8561,1
+8562,0
+8563,0
+8564,2
+8565,0
+8566,0
+8567,0
+8568,3
+8569,3
+8570,3
+8571,2
+8572,3
+8573,0
+8574,1
+8575,0
+8576,2
+8577,0
+8578,0
+8579,1
+8580,3
+8581,2
+8582,3
+8583,3
+8584,0
+8585,3
+8586,0
+8587,0
+8588,0
+8589,2
+8590,2
+8591,2
+8592,1
+8593,3
+8594,2
+8595,1
+8596,0
+8597,0
+8598,2
+8599,3
+8600,0
+8601,3
+8602,0
+8603,3
+8604,3
+8605,1
+8606,0
+8607,0
+8608,1
+8609,2
+8610,1
+8611,0
+8612,0
+8613,0
+8614,0
+8615,3
+8616,2
+8617,0
+8618,0
+8619,1
+8620,0
+8621,3
+8622,0
+8623,2
+8624,0
+8625,3
+8626,0
+8627,0
+8628,3
+8629,0
+8630,0
+8631,0
+8632,0
+8633,1
+8634,3
+8635,2
+8636,0
+8637,3
+8638,3
+8639,0
+8640,0
+8641,0
+8642,3
+8643,2
+8644,3
+8645,1
+8646,1
+8647,0
+8648,1
+8649,0
+8650,2
+8651,3
+8652,1
+8653,0
+8654,0
+8655,0
+8656,2
+8657,3
+8658,2
+8659,3
+8660,0
+8661,3
+8662,2
+8663,0
+8664,0
+8665,1
+8666,0
+8667,1
+8668,0
+8669,0
+8670,2
+8671,0
+8672,3
+8673,0
+8674,0
+8675,0
+8676,3
+8677,1
+8678,3
+8679,1
+8680,0
+8681,0
+8682,0
+8683,3
+8684,0
+8685,0
+8686,2
+8687,0
+8688,0
+8689,0
+8690,0
+8691,0
+8692,2
+8693,0
+8694,0
+8695,1
+8696,0
+8697,2
+8698,0
+8699,2
+8700,0
+8701,0
+8702,2
+8703,1
+8704,2
+8705,0
+8706,0
+8707,0
+8708,0
+8709,0
+8710,0
+8711,0
+8712,2
+8713,0
+8714,1
+8715,0
+8716,0
+8717,3
+8718,0
+8719,0
+8720,3
+8721,2
+8722,2
+8723,0
+8724,3
+8725,3
+8726,0
+8727,0
+8728,0
+8729,2
+8730,1
+8731,0
+8732,0
+8733,0
+8734,0
+8735,0
+8736,0
+8737,0
+8738,0
+8739,3
+8740,0
+8741,0
+8742,0
+8743,0
+8744,3
+8745,0
+8746,1
+8747,0
+8748,1
+8749,0
+8750,2
+8751,2
+8752,0
+8753,0
+8754,0
+8755,0
+8756,3
+8757,3
+8758,3
+8759,1
+8760,0
+8761,0
+8762,2
+8763,1
+8764,3
+8765,0
+8766,0
+8767,2
+8768,3
+8769,3
+8770,0
+8771,0
+8772,3
+8773,3
+8774,3
+8775,0
+8776,3
+8777,2
+8778,1
+8779,3
+8780,2
+8781,0
+8782,0
+8783,0
+8784,2
+8785,0
+8786,0
+8787,1
+8788,3
+8789,0
+8790,3
+8791,3
+8792,2
+8793,0
+8794,0
+8795,3
+8796,0
+8797,0
+8798,0
+8799,2
+8800,2
+8801,3
+8802,3
+8803,0
+8804,0
+8805,3
+8806,0
+8807,3
+8808,0
+8809,0
+8810,1
+8811,0
+8812,3
+8813,2
+8814,2
+8815,0
+8816,0
+8817,0
+8818,3
+8819,2
+8820,2
+8821,0
+8822,0
+8823,0
+8824,0
+8825,3
+8826,3
+8827,2
+8828,3
+8829,2
+8830,0
+8831,2
+8832,2
+8833,0
+8834,1
+8835,0
+8836,2
+8837,0
+8838,2
+8839,0
+8840,0
+8841,3
+8842,0
+8843,3
+8844,2
+8845,0
+8846,3
+8847,3
+8848,3
+8849,3
+8850,2
+8851,0
+8852,2
+8853,3
+8854,3
+8855,0
+8856,0
+8857,0
+8858,0
+8859,0
+8860,3
+8861,3
+8862,3
+8863,2
+8864,0
+8865,0
+8866,3
+8867,1
+8868,3
+8869,0
+8870,0
+8871,0
+8872,2
+8873,0
+8874,0
+8875,3
+8876,1
+8877,3
+8878,1
+8879,0
+8880,2
+8881,0
+8882,2
+8883,3
+8884,0
+8885,1
+8886,0
+8887,0
+8888,0
+8889,0
+8890,3
+8891,0
+8892,0
+8893,0
+8894,1
+8895,1
+8896,2
+8897,0
+8898,3
+8899,1
+8900,3
+8901,0
+8902,2
+8903,1
+8904,2
+8905,0
+8906,0
+8907,0
+8908,0
+8909,0
+8910,3
+8911,0
+8912,2
+8913,3
+8914,2
+8915,3
+8916,2
+8917,0
+8918,2
+8919,0
+8920,0
+8921,1
+8922,3
+8923,2
+8924,0
+8925,3
+8926,0
+8927,3
+8928,1
+8929,1
+8930,1
+8931,0
+8932,0
+8933,2
+8934,3
+8935,2
+8936,1
+8937,2
+8938,3
+8939,2
+8940,1
+8941,2
+8942,3
+8943,2
+8944,2
+8945,0
+8946,1
+8947,1
+8948,2
+8949,3
+8950,0
+8951,0
+8952,3
+8953,2
+8954,1
+8955,0
+8956,3
+8957,0
+8958,3
+8959,0
+8960,0
+8961,2
+8962,3
+8963,0
+8964,2
+8965,1
+8966,0
+8967,0
+8968,1
+8969,2
+8970,2
+8971,2
+8972,3
+8973,3
+8974,3
+8975,0
+8976,1
+8977,0
+8978,3
+8979,0
+8980,0
+8981,3
+8982,1
+8983,0
+8984,1
+8985,0
+8986,0
+8987,0
+8988,2
+8989,0
+8990,3
+8991,0
+8992,0
+8993,3
+8994,0
+8995,0
+8996,3
+8997,1
+8998,0
+8999,0
+9000,2
+9001,1
+9002,3
+9003,0
+9004,0
+9005,0
+9006,1
+9007,2
+9008,0
+9009,0
+9010,3
+9011,3
+9012,0
+9013,0
+9014,0
+9015,3
+9016,3
+9017,0
+9018,2
+9019,3
+9020,0
+9021,2
+9022,2
+9023,2
+9024,2
+9025,3
+9026,2
+9027,1
+9028,2
+9029,2
+9030,0
+9031,1
+9032,0
+9033,0
+9034,3
+9035,0
+9036,3
+9037,2
+9038,1
+9039,0
+9040,3
+9041,0
+9042,0
+9043,0
+9044,0
+9045,2
+9046,0
+9047,1
+9048,0
+9049,3
+9050,2
+9051,2
+9052,0
+9053,0
+9054,1
+9055,3
+9056,3
+9057,2
+9058,3
+9059,2
+9060,0
+9061,2
+9062,1
+9063,3
+9064,0
+9065,0
+9066,0
+9067,3
+9068,0
+9069,0
+9070,0
+9071,0
+9072,0
+9073,1
+9074,0
+9075,1
+9076,0
+9077,3
+9078,0
+9079,0
+9080,3
+9081,0
+9082,0
+9083,0
+9084,1
+9085,0
+9086,0
+9087,1
+9088,1
+9089,2
+9090,3
+9091,0
+9092,0
+9093,0
+9094,3
+9095,0
+9096,3
+9097,0
+9098,1
+9099,2
+9100,0
+9101,3
+9102,2
+9103,0
+9104,0
+9105,1
+9106,0
+9107,0
+9108,0
+9109,2
+9110,0
+9111,0
+9112,0
+9113,3
+9114,3
+9115,3
+9116,0
+9117,1
+9118,0
+9119,1
+9120,0
+9121,2
+9122,1
+9123,1
+9124,3
+9125,1
+9126,2
+9127,1
+9128,3
+9129,1
+9130,0
+9131,0
+9132,0
+9133,3
+9134,0
+9135,1
+9136,0
+9137,2
+9138,3
+9139,0
+9140,3
+9141,2
+9142,0
+9143,3
+9144,3
+9145,0
+9146,2
+9147,2
+9148,2
+9149,0
+9150,1
+9151,0
+9152,0
+9153,3
+9154,3
+9155,2
+9156,2
+9157,3
+9158,2
+9159,3
+9160,0
+9161,3
+9162,3
+9163,3
+9164,1
+9165,1
+9166,0
+9167,0
+9168,2
+9169,0
+9170,0
+9171,1
+9172,2
+9173,3
+9174,1
+9175,0
+9176,2
+9177,0
+9178,1
+9179,0
+9180,0
+9181,1
+9182,3
+9183,2
+9184,0
+9185,1
+9186,3
+9187,3
+9188,0
+9189,3
+9190,0
+9191,0
+9192,0
+9193,0
+9194,0
+9195,0
+9196,2
+9197,1
+9198,1
+9199,2
+9200,3
+9201,0
+9202,0
+9203,3
+9204,1
+9205,0
+9206,3
+9207,3
+9208,0
+9209,0
+9210,0
+9211,0
+9212,3
+9213,0
+9214,2
+9215,2
+9216,0
+9217,0
+9218,0
+9219,2
+9220,2
+9221,0
+9222,1
+9223,2
+9224,0
+9225,0
+9226,0
+9227,0
+9228,0
+9229,1
+9230,3
+9231,0
+9232,0
+9233,2
+9234,0
+9235,1
+9236,2
+9237,1
+9238,3
+9239,0
+9240,3
+9241,2
+9242,3
+9243,1
+9244,3
+9245,1
+9246,0
+9247,3
+9248,3
+9249,1
+9250,0
+9251,0
+9252,2
+9253,3
+9254,0
+9255,2
+9256,1
+9257,0
+9258,1
+9259,2
+9260,2
+9261,0
+9262,0
+9263,2
+9264,1
+9265,0
+9266,3
+9267,3
+9268,0
+9269,0
+9270,3
+9271,1
+9272,0
+9273,1
+9274,2
+9275,0
+9276,3
+9277,0
+9278,1
+9279,0
+9280,0
+9281,1
+9282,1
+9283,1
+9284,0
+9285,0
+9286,2
+9287,0
+9288,2
+9289,2
+9290,2
+9291,1
+9292,3
+9293,0
+9294,3
+9295,2
+9296,0
+9297,3
+9298,0
+9299,2
+9300,2
+9301,0
+9302,0
+9303,3
+9304,1
+9305,0
+9306,1
+9307,2
+9308,3
+9309,3
+9310,1
+9311,3
+9312,3
+9313,2
+9314,3
+9315,0
+9316,2
+9317,3
+9318,0
+9319,0
+9320,1
+9321,2
+9322,2
+9323,2
+9324,0
+9325,0
+9326,3
+9327,2
+9328,0
+9329,0
+9330,2
+9331,2
+9332,3
+9333,3
+9334,0
+9335,2
+9336,3
+9337,2
+9338,0
+9339,0
+9340,3
+9341,0
+9342,0
+9343,2
+9344,0
+9345,3
+9346,0
+9347,0
+9348,3
+9349,3
+9350,2
+9351,3
+9352,2
+9353,0
+9354,2
+9355,1
+9356,2
+9357,0
+9358,0
+9359,3
+9360,3
+9361,0
+9362,0
+9363,1
+9364,3
+9365,0
+9366,0
+9367,0
+9368,0
+9369,1
+9370,2
+9371,2
+9372,3
+9373,3
+9374,3
+9375,1
+9376,0
+9377,2
+9378,2
+9379,0
+9380,3
+9381,1
+9382,0
+9383,0
+9384,0
+9385,0
+9386,3
+9387,2
+9388,3
+9389,3
+9390,0
+9391,0
+9392,0
+9393,3
+9394,2
+9395,0
+9396,0
+9397,1
+9398,1
+9399,0
+9400,2
+9401,0
+9402,3
+9403,2
+9404,0
+9405,0
+9406,0
+9407,3
+9408,0
+9409,3
+9410,3
+9411,1
+9412,1
+9413,0
+9414,0
+9415,0
+9416,2
+9417,2
+9418,0
+9419,2
+9420,0
+9421,0
+9422,2
+9423,2
+9424,3
+9425,3
+9426,0
+9427,2
+9428,0
+9429,0
+9430,3
+9431,2
+9432,2
+9433,0
+9434,3
+9435,0
+9436,0
+9437,2
+9438,0
+9439,3
+9440,0
+9441,0
+9442,0
+9443,0
+9444,0
+9445,1
+9446,0
+9447,1
+9448,1
+9449,0
+9450,0
+9451,0
+9452,0
+9453,1
+9454,0
+9455,0
+9456,0
+9457,3
+9458,2
+9459,0
+9460,0
+9461,0
+9462,0
+9463,0
+9464,3
+9465,0
+9466,2
+9467,1
+9468,2
+9469,2
+9470,2
+9471,3
+9472,0
+9473,3
+9474,2
+9475,0
+9476,0
+9477,0
+9478,1
+9479,2
+9480,0
+9481,3
+9482,3
+9483,2
+9484,1
+9485,3
+9486,3
+9487,3
+9488,2
+9489,3
+9490,3
+9491,1
+9492,0
+9493,0
+9494,1
+9495,0
+9496,1
+9497,2
+9498,2
+9499,0
+9500,0
+9501,1
+9502,2
+9503,0
+9504,0
+9505,0
+9506,0
+9507,1
+9508,0
+9509,2
+9510,0
+9511,3
+9512,2
+9513,2
+9514,3
+9515,2
+9516,2
+9517,0
+9518,0
+9519,1
+9520,3
+9521,0
+9522,1
+9523,1
+9524,0
+9525,0
+9526,2
+9527,0
+9528,0
+9529,0
+9530,3
+9531,0
+9532,2
+9533,2
+9534,1
+9535,0
+9536,3
+9537,3
+9538,0
+9539,0
+9540,0
+9541,3
+9542,0
+9543,1
+9544,2
+9545,3
+9546,0
+9547,1
+9548,3
+9549,3
+9550,2
+9551,2
+9552,0
+9553,0
+9554,1
+9555,3
+9556,3
+9557,0
+9558,1
+9559,3
+9560,3
+9561,1
+9562,2
+9563,3
+9564,2
+9565,0
+9566,2
+9567,3
+9568,0
+9569,0
+9570,1
+9571,2
+9572,1
+9573,0
+9574,0
+9575,0
+9576,0
+9577,0
+9578,2
+9579,1
+9580,0
+9581,1
+9582,0
+9583,3
+9584,3
+9585,2
+9586,0
+9587,0
+9588,3
+9589,3
+9590,0
+9591,3
+9592,2
+9593,1
+9594,3
+9595,3
+9596,3
+9597,3
+9598,0
+9599,1
+9600,0
+9601,0
+9602,1
+9603,1
+9604,0
+9605,2
+9606,0
+9607,3
+9608,3
+9609,2
+9610,2
+9611,0
+9612,0
+9613,0
+9614,1
+9615,0
+9616,2
+9617,0
+9618,0
+9619,1
+9620,2
+9621,0
+9622,0
+9623,0
+9624,2
+9625,2
+9626,1
+9627,0
+9628,3
+9629,3
+9630,1
+9631,1
+9632,0
+9633,3
+9634,0
+9635,0
+9636,0
+9637,0
+9638,2
+9639,0
+9640,3
+9641,0
+9642,2
+9643,0
+9644,0
+9645,0
+9646,1
+9647,3
+9648,2
+9649,0
+9650,1
+9651,3
+9652,2
+9653,3
+9654,1
+9655,3
+9656,0
+9657,2
+9658,2
+9659,0
+9660,0
+9661,0
+9662,0
+9663,0
+9664,0
+9665,1
+9666,2
+9667,3
+9668,3
+9669,0
+9670,2
+9671,2
+9672,0
+9673,0
+9674,3
+9675,0
+9676,2
+9677,0
+9678,0
+9679,0
+9680,1
+9681,0
+9682,3
+9683,2
+9684,2
+9685,2
+9686,2
+9687,0
+9688,0
+9689,0
+9690,3
+9691,1
+9692,3
+9693,0
+9694,0
+9695,0
+9696,3
+9697,0
+9698,3
+9699,2
+9700,2
+9701,0
+9702,0
+9703,2
+9704,1
+9705,3
+9706,2
+9707,0
+9708,3
+9709,0
+9710,1
+9711,3
+9712,3
+9713,3
+9714,3
+9715,0
+9716,0
+9717,2
+9718,3
+9719,3
+9720,2
+9721,0
+9722,3
+9723,3
+9724,0
+9725,0
+9726,0
+9727,0
+9728,3
+9729,0
+9730,1
+9731,0
+9732,3
+9733,0
+9734,0
+9735,1
+9736,1
+9737,3
+9738,0
+9739,2
+9740,3
+9741,3
+9742,1
+9743,2
+9744,2
+9745,0
+9746,0
+9747,3
+9748,1
+9749,0
+9750,2
+9751,0
+9752,0
+9753,0
+9754,1
+9755,2
+9756,3
+9757,3
+9758,3
+9759,0
+9760,0
+9761,3
+9762,0
+9763,3
+9764,0
+9765,1
+9766,3
+9767,2
+9768,2
+9769,0
+9770,3
+9771,1
+9772,2
+9773,2
+9774,0
+9775,0
+9776,3
+9777,3
+9778,1
+9779,0
+9780,1
+9781,0
+9782,0
+9783,0
+9784,0
+9785,0
+9786,0
+9787,0
+9788,0
+9789,0
+9790,1
+9791,0
+9792,3
+9793,3
+9794,1
+9795,2
+9796,0
+9797,0
+9798,2
+9799,0
+9800,0
+9801,1
+9802,0
+9803,3
+9804,0
+9805,3
+9806,0
+9807,0
+9808,0
+9809,0
+9810,3
+9811,3
+9812,1
+9813,2
+9814,2
+9815,3
+9816,0
+9817,1
+9818,2
+9819,2
+9820,1
+9821,0
+9822,3
+9823,2
+9824,0
+9825,0
+9826,2
+9827,2
+9828,0
+9829,0
+9830,0
+9831,3
+9832,0
+9833,0
+9834,3
+9835,0
+9836,0
+9837,2
+9838,0
+9839,3
+9840,0
+9841,1
+9842,1
+9843,3
+9844,2
+9845,3
+9846,0
+9847,0
+9848,0
+9849,2
+9850,0
+9851,1
+9852,0
+9853,3
+9854,3
+9855,0
+9856,0
+9857,0
+9858,0
+9859,3
+9860,2
+9861,1
+9862,0
+9863,2
+9864,2
+9865,0
+9866,0
+9867,0
+9868,0
+9869,0
+9870,0
+9871,2
+9872,0
+9873,2
+9874,0
+9875,0
+9876,0
+9877,0
+9878,1
+9879,2
+9880,1
+9881,2
+9882,3
+9883,3
+9884,1
+9885,1
+9886,0
+9887,2
+9888,2
+9889,3
+9890,3
+9891,0
+9892,0
+9893,2
+9894,3
+9895,0
+9896,1
+9897,0
+9898,3
+9899,0
+9900,0
+9901,0
+9902,0
+9903,3
+9904,0
+9905,2
+9906,0
+9907,2
+9908,2
+9909,0
+9910,0
+9911,0
+9912,0
+9913,2
+9914,0
+9915,3
+9916,0
+9917,3
+9918,1
+9919,0
+9920,2
+9921,3
+9922,1
+9923,3
+9924,2
+9925,3
+9926,3
+9927,0
+9928,0
+9929,3
+9930,1
+9931,0
+9932,2
+9933,3
+9934,0
+9935,1
+9936,0
+9937,0
+9938,0
+9939,0
+9940,3
+9941,1
+9942,0
+9943,3
+9944,3
+9945,3
+9946,0
+9947,0
+9948,0
+9949,1
+9950,1
+9951,1
+9952,3
+9953,3
+9954,1
+9955,1
+9956,2
+9957,1
+9958,2
+9959,0
+9960,0
+9961,0
+9962,0
+9963,2
+9964,2
+9965,0
+9966,2
+9967,0
+9968,0
+9969,3
+9970,0
+9971,1
+9972,1
+9973,3
+9974,0
+9975,0
+9976,1
+9977,1
+9978,3
+9979,0
+9980,3
+9981,0
+9982,0
+9983,0
+9984,2
+9985,3
+9986,3
+9987,2
+9988,1
+9989,2
+9990,1
+9991,1
+9992,1
+9993,3
+9994,2
+9995,3
+9996,0
+9997,0
+9998,0
+9999,0
+10000,3
+10001,0
+10002,0
+10003,0
+10004,0
+10005,2
+10006,3
+10007,0
+10008,0
+10009,2
+10010,3
+10011,3
+10012,1
+10013,0
+10014,0
+10015,2
+10016,3
+10017,0
+10018,3
+10019,2
+10020,3
+10021,3
+10022,3
+10023,1
+10024,1
+10025,0
+10026,1
+10027,0
+10028,2
+10029,0
+10030,0
+10031,3
+10032,3
+10033,2
+10034,3
+10035,2
+10036,1
+10037,0
+10038,0
+10039,0
+10040,0
+10041,2
+10042,2
+10043,3
+10044,2
+10045,3
+10046,3
+10047,1
+10048,0
+10049,2
+10050,0
+10051,1
+10052,0
+10053,3
+10054,0
+10055,1
+10056,0
+10057,3
+10058,2
+10059,0
+10060,1
+10061,2
+10062,3
+10063,3
+10064,1
+10065,2
+10066,1
+10067,2
+10068,1
+10069,0
+10070,1
+10071,0
+10072,0
+10073,0
+10074,3
+10075,0
+10076,0
+10077,3
+10078,3
+10079,3
+10080,2
+10081,1
+10082,2
+10083,0
+10084,1
+10085,3
+10086,0
+10087,1
+10088,1
+10089,2
+10090,1
+10091,2
+10092,0
+10093,2
+10094,2
+10095,0
+10096,2
+10097,3
+10098,2
+10099,3
+10100,3
+10101,3
+10102,1
+10103,0
+10104,3
+10105,0
+10106,0
+10107,1
+10108,0
+10109,3
+10110,2
+10111,0
+10112,0
+10113,2
+10114,0
+10115,2
+10116,2
+10117,2
+10118,0
+10119,2
+10120,2
+10121,1
+10122,0
+10123,0
+10124,3
+10125,3
+10126,3
+10127,3
+10128,0
+10129,0
+10130,0
+10131,3
+10132,2
+10133,0
+10134,0
+10135,1
+10136,0
+10137,0
+10138,0
+10139,0
+10140,0
+10141,0
+10142,1
+10143,0
+10144,0
+10145,2
+10146,0
+10147,0
+10148,2
+10149,0
+10150,2
+10151,0
+10152,3
+10153,2
+10154,0
+10155,0
+10156,0
+10157,3
+10158,0
+10159,3
+10160,0
+10161,3
+10162,1
+10163,0
+10164,2
+10165,0
+10166,0
+10167,0
+10168,0
+10169,0
+10170,0
+10171,0
+10172,3
+10173,3
+10174,3
+10175,2
+10176,3
+10177,1
+10178,1
+10179,1
+10180,3
+10181,0
+10182,0
+10183,0
+10184,0
+10185,2
+10186,2
+10187,3
+10188,0
+10189,3
+10190,0
+10191,0
+10192,2
+10193,3
+10194,2
+10195,0
+10196,2
+10197,0
+10198,3
+10199,2
+10200,0
+10201,2
+10202,1
+10203,2
+10204,0
+10205,1
+10206,0
+10207,0
+10208,2
+10209,0
+10210,3
+10211,0
+10212,0
+10213,0
+10214,0
+10215,0
+10216,3
+10217,0
+10218,0
+10219,1
+10220,3
+10221,3
+10222,3
+10223,0
+10224,3
+10225,0
+10226,0
+10227,0
+10228,2
+10229,2
+10230,0
+10231,0
+10232,0
+10233,1
+10234,0
+10235,3
+10236,3
+10237,0
+10238,1
+10239,3
+10240,2
+10241,2
+10242,0
+10243,2
+10244,0
+10245,3
+10246,1
+10247,0
+10248,0
+10249,2
+10250,3
+10251,2
+10252,0
+10253,3
+10254,3
+10255,2
+10256,0
+10257,3
+10258,0
+10259,0
+10260,3
+10261,0
+10262,0
+10263,0
+10264,0
+10265,2
+10266,0
+10267,0
+10268,2
+10269,0
+10270,0
+10271,0
+10272,0
+10273,0
+10274,1
+10275,1
+10276,0
+10277,3
+10278,0
+10279,0
+10280,2
+10281,3
+10282,1
+10283,1
+10284,0
+10285,2
+10286,0
+10287,3
+10288,0
+10289,3
+10290,2
+10291,0
+10292,2
+10293,3
+10294,3
+10295,2
+10296,2
+10297,0
+10298,0
+10299,0
+10300,3
+10301,3
+10302,2
+10303,0
+10304,0
+10305,2
+10306,0
+10307,3
+10308,0
+10309,3
+10310,3
+10311,0
+10312,1
+10313,0
+10314,1
+10315,0
+10316,0
+10317,2
+10318,0
+10319,1
+10320,1
+10321,0
+10322,0
+10323,0
+10324,0
+10325,2
+10326,3
+10327,3
+10328,3
+10329,3
+10330,0
+10331,0
+10332,1
+10333,1
+10334,1
+10335,0
+10336,0
+10337,2
+10338,0
+10339,0
+10340,3
+10341,2
+10342,0
+10343,2
+10344,2
+10345,0
+10346,0
+10347,2
+10348,2
+10349,0
+10350,0
+10351,0
+10352,0
+10353,0
+10354,0
+10355,2
+10356,0
+10357,0
+10358,0
+10359,0
+10360,0
+10361,1
+10362,0
+10363,2
+10364,2
+10365,1
+10366,0
+10367,0
+10368,2
+10369,0
+10370,2
+10371,0
+10372,0
+10373,3
+10374,3
+10375,2
+10376,0
+10377,3
+10378,0
+10379,3
+10380,0
+10381,2
+10382,2
+10383,0
+10384,1
+10385,0
+10386,0
+10387,3
+10388,0
+10389,1
+10390,3
+10391,0
+10392,0
+10393,0
+10394,2
+10395,0
+10396,2
+10397,0
+10398,0
+10399,0
+10400,2
+10401,0
+10402,3
+10403,3
+10404,3
+10405,0
+10406,2
+10407,3
+10408,0
+10409,0
+10410,0
+10411,1
+10412,3
+10413,0
+10414,1
+10415,0
+10416,0
+10417,2
+10418,2
+10419,1
+10420,0
+10421,1
+10422,0
+10423,0
+10424,1
+10425,2
+10426,2
+10427,0
+10428,3
+10429,0
+10430,0
+10431,0
+10432,1
+10433,0
+10434,3
+10435,0
+10436,3
+10437,3
+10438,1
+10439,1
+10440,0
+10441,0
+10442,0
+10443,0
+10444,3
+10445,2
+10446,3
+10447,2
+10448,1
+10449,3
+10450,3
+10451,0
+10452,3
+10453,0
+10454,2
+10455,0
+10456,0
+10457,3
+10458,0
+10459,3
+10460,1
+10461,0
+10462,3
+10463,0
+10464,2
+10465,1
+10466,0
+10467,3
+10468,1
+10469,0
+10470,3
+10471,0
+10472,1
+10473,0
+10474,1
+10475,0
+10476,1
+10477,0
+10478,1
+10479,1
+10480,0
+10481,0
+10482,3
+10483,1
+10484,0
+10485,1
+10486,1
+10487,0
+10488,0
+10489,0
+10490,2
+10491,3
+10492,0
+10493,0
+10494,0
+10495,0
+10496,1
+10497,0
+10498,0
+10499,1
+10500,2
+10501,2
+10502,0
+10503,0
+10504,3
+10505,3
+10506,0
+10507,1
+10508,3
+10509,0
+10510,2
+10511,3
+10512,0
+10513,2
+10514,0
+10515,2
+10516,3
+10517,0
+10518,2
+10519,1
+10520,2
+10521,0
+10522,3
+10523,2
+10524,3
+10525,0
+10526,3
+10527,2
+10528,1
+10529,1
+10530,0
+10531,2
+10532,1
+10533,3
+10534,3
+10535,1
+10536,2
+10537,0
+10538,1
+10539,1
+10540,0
+10541,2
+10542,0
+10543,1
+10544,2
+10545,3
+10546,0
+10547,2
+10548,0
+10549,1
+10550,0
+10551,3
+10552,0
+10553,0
+10554,0
+10555,2
+10556,0
+10557,3
+10558,2
+10559,0
+10560,2
+10561,0
+10562,3
+10563,1
+10564,3
+10565,0
+10566,0
+10567,3
+10568,0
+10569,0
+10570,2
+10571,0
+10572,0
+10573,0
+10574,0
+10575,0
+10576,2
+10577,0
+10578,2
+10579,0
+10580,0
+10581,2
+10582,0
+10583,2
+10584,0
+10585,3
+10586,0
+10587,0
+10588,2
+10589,2
+10590,0
+10591,3
+10592,2
+10593,0
+10594,0
+10595,0
+10596,0
+10597,0
+10598,2
+10599,2
+10600,2
+10601,1
+10602,1
+10603,2
+10604,3
+10605,3
+10606,0
+10607,3
+10608,1
+10609,0
+10610,3
+10611,0
+10612,0
+10613,3
+10614,3
+10615,2
+10616,1
+10617,1
+10618,3
+10619,3
+10620,1
+10621,0
+10622,2
+10623,0
+10624,2
+10625,2
+10626,3
+10627,1
+10628,0
+10629,0
+10630,3
+10631,0
+10632,0
+10633,3
+10634,1
+10635,3
+10636,0
+10637,0
+10638,3
+10639,1
+10640,0
+10641,0
+10642,3
+10643,3
+10644,1
+10645,0
+10646,1
+10647,1
+10648,3
+10649,2
+10650,1
+10651,2
+10652,0
+10653,2
+10654,2
+10655,1
+10656,2
+10657,1
+10658,3
+10659,1
+10660,1
+10661,1
+10662,3
+10663,1
+10664,2
+10665,0
+10666,3
+10667,0
+10668,2
+10669,0
+10670,2
+10671,0
+10672,2
+10673,1
+10674,0
+10675,1
+10676,2
+10677,0
+10678,3
+10679,2
+10680,3
+10681,1
+10682,0
+10683,0
+10684,0
+10685,3
+10686,3
+10687,2
+10688,2
+10689,0
+10690,0
+10691,1
+10692,0
+10693,3
+10694,0
+10695,2
+10696,2
+10697,0
+10698,0
+10699,0
+10700,2
+10701,3
+10702,0
+10703,2
+10704,2
+10705,1
+10706,0
+10707,3
+10708,3
+10709,0
+10710,0
+10711,2
+10712,0
+10713,0
+10714,2
+10715,1
+10716,2
+10717,0
+10718,3
+10719,3
+10720,0
+10721,0
+10722,0
+10723,2
+10724,1
+10725,3
+10726,0
+10727,2
+10728,0
+10729,2
+10730,0
+10731,2
+10732,0
+10733,3
+10734,0
+10735,1
+10736,3
+10737,2
+10738,0
+10739,0
+10740,0
+10741,0
+10742,3
+10743,3
+10744,0
diff --git a/stacker.py b/stacker.py
new file mode 100644
index 0000000000000000000000000000000000000000..403968a56ff1c3e441f9f0a1aacf61f738c935c2
--- /dev/null
+++ b/stacker.py
@@ -0,0 +1,60 @@
+import os
+import numpy as np
+import pandas as pd
+import pickle
+import xgboost as xgb
+
+from sklearn.metrics import accuracy_score, f1_score, confusion_matrix
+
+from features_extractor import FeatureExtractor
+
+saved_stacks_path = 'saved_stacks'
+saved_stacks_dir = os.listdir(saved_stacks_path)
+
+y_train_list=[]
+y_test_list=[]
+y_true_list=[]
+for path in saved_stacks_dir:
+    path = os.path.join(saved_stacks_path, path)
+    stack_data = pickle.load(open(path, "rb"))
+
+    y_train = stack_data['Y_train_pred']
+    y_train_list += [y_train[:, np.newaxis]]
+
+    y_test = stack_data['Y_test_pred']
+    y_test_list += [y_test[:, np.newaxis]]
+
+    y_true = stack_data['Y_true_pred']
+    y_true_list += [y_true[:, np.newaxis]]
+
+y_train_med = np.median(np.concatenate(y_train_list, axis=1), axis=1)
+y_test_med = np.median(np.concatenate(y_test_list, axis=1), axis=1)
+y_true_med = np.median(np.concatenate(y_true_list, axis=1), axis=1)
+
+pred_df = pd.DataFrame(np.argmax(y_true_med, axis=1), columns=['label'])
+pred_df.to_csv("med_sample_submission.csv", index=True, index_label='Id')
+
+fe = FeatureExtractor(['train.csv', 'train_legacy.csv'], test_size=0.2)
+
+Y_train = np.ravel(fe.train_df[['label']])
+Y_test = np.ravel(fe.test_df[['label']])
+
+stacked_model = xgb.XGBClassifier(n_estimators=300, max_depth=10,
+                                  learning_rate=0.02, subsample=0.8, colsample_bytree=0.5,
+                                  min_child_weight=0, scale_pos_weight=1,
+                                  objective='multi:softprob', verbosity=1)
+
+
+stacked_model.fit(y_train_med, Y_train)
+
+test_pred = stacked_model.predict(y_test_med)
+stacked_score = f1_score(Y_test, test_pred, average=None)
+print("Final Test : ", stacked_score)
+print(confusion_matrix(Y_test, test_pred))
+
+y_true_stacked = stacked_model.predict(y_true_med)
+pred_df = pd.DataFrame(np.argmax(y_true_stacked, axis=1), columns=['label'])
+pred_df.to_csv("stacked_sample_submission.csv", index=True, index_label='Id')
+
+
+
diff --git a/venv/Lib/site-packages/rope-0.14.0.dist-info/DESCRIPTION.rst b/venv/Lib/site-packages/rope-0.14.0.dist-info/DESCRIPTION.rst
new file mode 100644
index 0000000000000000000000000000000000000000..d4dc96796ec6d333512937bf912421bc94586bf2
--- /dev/null
+++ b/venv/Lib/site-packages/rope-0.14.0.dist-info/DESCRIPTION.rst
@@ -0,0 +1,28 @@
+
+
+.. _GitHub python-rope / rope: https://github.com/python-rope/rope
+
+
+========================================
+ rope, a python refactoring library ...
+========================================
+
+
+Overview
+========
+
+`Rope`_ is a python refactoring library.
+
+.. _`rope`: https://github.com/python-rope/rope
+
+
+Notes
+============
+
+* Nick Smith <nicks@fastmail.fm> takes over maintaining rope. Many thanks to
+  Matej Cepl for his work maintaining rope for the past few years!!
+* Partial Python3 support, please file bugs and contribute patches if you
+  encounter gaps.
+
+
+
diff --git a/venv/Lib/site-packages/rope-0.14.0.dist-info/INSTALLER b/venv/Lib/site-packages/rope-0.14.0.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/rope-0.14.0.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/rope-0.14.0.dist-info/METADATA b/venv/Lib/site-packages/rope-0.14.0.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..1393b0da9b9876f50199fabc81c83f3771eb336c
--- /dev/null
+++ b/venv/Lib/site-packages/rope-0.14.0.dist-info/METADATA
@@ -0,0 +1,56 @@
+Metadata-Version: 2.0
+Name: rope
+Version: 0.14.0
+Summary: a python refactoring library...
+Home-page: https://github.com/python-rope/rope
+Author: Ali Gholami Rudi
+Author-email: aligrudi@users.sourceforge.net
+License: GNU GPL
+Description-Content-Type: UNKNOWN
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Operating System :: OS Independent
+Classifier: Environment :: X11 Applications
+Classifier: Environment :: Win32 (MS Windows)
+Classifier: Environment :: MacOS X
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
+Classifier: Natural Language :: English
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Topic :: Software Development
+
+
+
+.. _GitHub python-rope / rope: https://github.com/python-rope/rope
+
+
+========================================
+ rope, a python refactoring library ...
+========================================
+
+
+Overview
+========
+
+`Rope`_ is a python refactoring library.
+
+.. _`rope`: https://github.com/python-rope/rope
+
+
+Notes
+============
+
+* Nick Smith <nicks@fastmail.fm> takes over maintaining rope. Many thanks to
+  Matej Cepl for his work maintaining rope for the past few years!!
+* Partial Python3 support, please file bugs and contribute patches if you
+  encounter gaps.
+
+
+
diff --git a/venv/Lib/site-packages/rope-0.14.0.dist-info/RECORD b/venv/Lib/site-packages/rope-0.14.0.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..924b81c0cd0b7f60120bc7d344c5733b55aaf1e7
--- /dev/null
+++ b/venv/Lib/site-packages/rope-0.14.0.dist-info/RECORD
@@ -0,0 +1,189 @@
+rope-0.14.0.dist-info/DESCRIPTION.rst,sha256=RzRBs7wozJU1WbkRB1kDYOAXpVPgxTK5tJDkO3imTWQ,566
+rope-0.14.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+rope-0.14.0.dist-info/METADATA,sha256=zm_Ap8SZHzOUF_JRsy6pnDJjAiVX1nokX4xdc09UcFI,1668
+rope-0.14.0.dist-info/RECORD,,
+rope-0.14.0.dist-info/WHEEL,sha256=8Lm45v9gcYRm70DrgFGVe4WsUtUMi1_0Tso1hqPGMjA,92
+rope-0.14.0.dist-info/metadata.json,sha256=Q5nkxIXxMTEXdAg2Nftd2S7MQa_cuvMWLmFwdbwhH24,1157
+rope-0.14.0.dist-info/top_level.txt,sha256=9J29TEx1omxK0VahSxM3eA1sZ6iwoJLxY_CXl4eF1K0,5
+rope/__init__.py,sha256=dTX3sZMs5pNrubrJkB01233a8_xcS1G66Lj85y-F-zQ,914
+rope/__pycache__/__init__.cpython-37.pyc,,
+rope/base/__init__.py,sha256=a4VjhgbOTCCUwef7_68RbfnHqwVd6L69HKsjRvIlK8s,161
+rope/base/__pycache__/__init__.cpython-37.pyc,,
+rope/base/__pycache__/arguments.cpython-37.pyc,,
+rope/base/__pycache__/ast.cpython-37.pyc,,
+rope/base/__pycache__/astutils.cpython-37.pyc,,
+rope/base/__pycache__/builtins.cpython-37.pyc,,
+rope/base/__pycache__/change.cpython-37.pyc,,
+rope/base/__pycache__/codeanalyze.cpython-37.pyc,,
+rope/base/__pycache__/default_config.cpython-37.pyc,,
+rope/base/__pycache__/evaluate.cpython-37.pyc,,
+rope/base/__pycache__/exceptions.cpython-37.pyc,,
+rope/base/__pycache__/fscommands.cpython-37.pyc,,
+rope/base/__pycache__/history.cpython-37.pyc,,
+rope/base/__pycache__/libutils.cpython-37.pyc,,
+rope/base/__pycache__/prefs.cpython-37.pyc,,
+rope/base/__pycache__/project.cpython-37.pyc,,
+rope/base/__pycache__/pycore.cpython-37.pyc,,
+rope/base/__pycache__/pynames.cpython-37.pyc,,
+rope/base/__pycache__/pynamesdef.cpython-37.pyc,,
+rope/base/__pycache__/pyobjects.cpython-37.pyc,,
+rope/base/__pycache__/pyobjectsdef.cpython-37.pyc,,
+rope/base/__pycache__/pyscopes.cpython-37.pyc,,
+rope/base/__pycache__/resourceobserver.cpython-37.pyc,,
+rope/base/__pycache__/resources.cpython-37.pyc,,
+rope/base/__pycache__/simplify.cpython-37.pyc,,
+rope/base/__pycache__/stdmods.cpython-37.pyc,,
+rope/base/__pycache__/taskhandle.cpython-37.pyc,,
+rope/base/__pycache__/worder.cpython-37.pyc,,
+rope/base/arguments.py,sha256=H1RgB02ZMHSuqjxJ-uYp7dNHVIoD98G29EsSL_uJSKo,3298
+rope/base/ast.py,sha256=cZeaeW3h7vi35lOnY8N-CqXQHMheDrnU6fLvAQuRHoM,2284
+rope/base/astutils.py,sha256=LJ2aj4yvrArILif6eEDGDDridP7eqwM-lxDVP0v_ZQE,1651
+rope/base/builtins.py,sha256=Ow--sZ_JC4sAJqAxn5gQLCOmkuJO7GfzfV9EaASa1rU,26486
+rope/base/change.py,sha256=Kb-25HoJr-eOBcVvmp_O81CzSaHCfWQHK8KFF5na1KI,13575
+rope/base/codeanalyze.py,sha256=MTN3N1WDLk3JokvOyZb75ahz6ibDJeFNItOHMC9bFDU,11011
+rope/base/default_config.py,sha256=6sLNzh3zKZBfx_bb2T7d4wRflUK67OKxdNg4KXMOV5s,4794
+rope/base/evaluate.py,sha256=2jp-wnaJSyVm0W7cEE_Zxd_8n84H7gqqqxfn3dfn7CM,12725
+rope/base/exceptions.py,sha256=GVW7ZhhYGFR2g0lOwpe9lOdTCxoKefP8arFHa1NSEcg,1446
+rope/base/fscommands.py,sha256=HyUpliZr22gfaiDq6KiVxNB4XfkL--evYqFp-7aQcIo,7983
+rope/base/history.py,sha256=_hPV3PSzlv6MUGV4eVBJt-ypS4kzO9kE4ml3IGqJAvI,8654
+rope/base/libutils.py,sha256=GJNwkTj-CLsG4sVX59FzdgXJxODgGlYyTaArn1UXwvg,3952
+rope/base/oi/__init__.py,sha256=_3s_kIc6gY-hUoAguoUDRLcCSDWGDGZhr-pcIm-Y1A0,1684
+rope/base/oi/__pycache__/__init__.cpython-37.pyc,,
+rope/base/oi/__pycache__/doa.cpython-37.pyc,,
+rope/base/oi/__pycache__/memorydb.cpython-37.pyc,,
+rope/base/oi/__pycache__/objectdb.cpython-37.pyc,,
+rope/base/oi/__pycache__/objectinfo.cpython-37.pyc,,
+rope/base/oi/__pycache__/runmod.cpython-37.pyc,,
+rope/base/oi/__pycache__/soa.cpython-37.pyc,,
+rope/base/oi/__pycache__/soi.cpython-37.pyc,,
+rope/base/oi/__pycache__/transform.cpython-37.pyc,,
+rope/base/oi/doa.py,sha256=prknCVfQ8lvVZSslaz_3Mk3mgIkbmeZR0_U6BmGto4k,7310
+rope/base/oi/memorydb.py,sha256=pQ36Cm22wvE4gMl53Di7NBOJusnLNt6WxlnR_6iuyds,3098
+rope/base/oi/objectdb.py,sha256=AmTRp69V-tkPH0UZERXNJKM9BpLFrhZNL1aa9xu_zKY,4753
+rope/base/oi/objectinfo.py,sha256=J0SUOBIrfPvBBPKtHGZmPIetGJuNuCEXp4mhYQIIOoI,8767
+rope/base/oi/runmod.py,sha256=tM5E6a4D7zbdnh1r28D-vkLfWF5GKgi8KIxvU1Bf2iA,8455
+rope/base/oi/soa.py,sha256=0x497SO9LvRBD_3Elkh3_neQJ-DIFg4PFG8NL1raxs8,5636
+rope/base/oi/soi.py,sha256=8InPygj-DGs1db_H69Lu0IyoVysOmEA1Jf0wZoX-i9M,7894
+rope/base/oi/transform.py,sha256=NeMLzSo5fvnQUeSF6wKKRxwLu77kOOnsGc5pQkecMOE,9862
+rope/base/oi/type_hinting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+rope/base/oi/type_hinting/__pycache__/__init__.cpython-37.pyc,,
+rope/base/oi/type_hinting/__pycache__/evaluate.cpython-37.pyc,,
+rope/base/oi/type_hinting/__pycache__/factory.cpython-37.pyc,,
+rope/base/oi/type_hinting/__pycache__/interfaces.cpython-37.pyc,,
+rope/base/oi/type_hinting/__pycache__/utils.cpython-37.pyc,,
+rope/base/oi/type_hinting/evaluate.py,sha256=H5seMtt_MCeZ2yNYKHKTOVlzyoduF39N_58g6NFxxQg,9046
+rope/base/oi/type_hinting/factory.py,sha256=bbcrZbKc7-jrpG2CW5gBr9QZU31WAIdZ0_EF6mF0ZBc,2522
+rope/base/oi/type_hinting/interfaces.py,sha256=KMA4ck9o_5o-kmZmXL5tU2xjldBnCvhx24TJoiHWl_8,724
+rope/base/oi/type_hinting/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+rope/base/oi/type_hinting/providers/__pycache__/__init__.cpython-37.pyc,,
+rope/base/oi/type_hinting/providers/__pycache__/composite.cpython-37.pyc,,
+rope/base/oi/type_hinting/providers/__pycache__/docstrings.cpython-37.pyc,,
+rope/base/oi/type_hinting/providers/__pycache__/inheritance.cpython-37.pyc,,
+rope/base/oi/type_hinting/providers/__pycache__/interfaces.cpython-37.pyc,,
+rope/base/oi/type_hinting/providers/__pycache__/numpydocstrings.cpython-37.pyc,,
+rope/base/oi/type_hinting/providers/__pycache__/pep0484_type_comments.cpython-37.pyc,,
+rope/base/oi/type_hinting/providers/composite.py,sha256=2W1IZKVBgAHX8dn07EJuxjS35TOvI1UkyzSPodJ_Lb0,1859
+rope/base/oi/type_hinting/providers/docstrings.py,sha256=BA93BWstYuKavH1jji2-Bv3d-p7qpT_SOd6WILBOg74,6194
+rope/base/oi/type_hinting/providers/inheritance.py,sha256=LiFPj2YJJTckKONMdyT6qA_x0aoRYHM98jjvMF7pxY0,2119
+rope/base/oi/type_hinting/providers/interfaces.py,sha256=h4_GsZyiPAHqPL6G7nPfePZDLB9dE0SmQYoIS2Py6_0,1078
+rope/base/oi/type_hinting/providers/numpydocstrings.py,sha256=BCSZbjg5lcd30hNGzye-0b41DCbNgrm9J0XGp4DAG1Q,1380
+rope/base/oi/type_hinting/providers/pep0484_type_comments.py,sha256=FuDJRhKRvxKqm4p8X6xh_SLCrq6ZL-0ZcWF6dxl7B8I,1539
+rope/base/oi/type_hinting/resolvers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+rope/base/oi/type_hinting/resolvers/__pycache__/__init__.cpython-37.pyc,,
+rope/base/oi/type_hinting/resolvers/__pycache__/composite.cpython-37.pyc,,
+rope/base/oi/type_hinting/resolvers/__pycache__/interfaces.cpython-37.pyc,,
+rope/base/oi/type_hinting/resolvers/__pycache__/types.cpython-37.pyc,,
+rope/base/oi/type_hinting/resolvers/composite.py,sha256=HcEsazg2fieXSPJpOUweG9PLAB_fzC9JGwMJhumPEis,779
+rope/base/oi/type_hinting/resolvers/interfaces.py,sha256=M8xMYVDxO9Wm-Jd4JF_H4kFU-30AZv39oM4RNBAlupw,414
+rope/base/oi/type_hinting/resolvers/types.py,sha256=MD_bxrIcSJmKnEEfqbeLxZZq-CoxgDBuY2PEBrWNvX8,611
+rope/base/oi/type_hinting/utils.py,sha256=A1WGMpTMuA0AoXtBE2nLWvs_z1QCOEF8Xj6vE5zZO9s,4520
+rope/base/prefs.py,sha256=stjBZ0PCrRvbuotZJw1768rFgURTYcXoGONPSXLpOq4,1094
+rope/base/project.py,sha256=pttN5WKe3FVG1iADgBu5sPAEzQndm1YiOtD2RnUuu7g,16460
+rope/base/pycore.py,sha256=qUc-6k_yZ0bE6z7MxU6kd9le8H7mwKol1t1Bg5oUmkQ,12973
+rope/base/pynames.py,sha256=yvPOPyay3SKe9WGgCgPNld9-mcMUB7hFO_DgQTzlSz4,5931
+rope/base/pynamesdef.py,sha256=ibysKImj7jDUFMFpqm3RN9iHPBiLWpJon72cx1oc2Ig,1719
+rope/base/pyobjects.py,sha256=Zo4cRURuol1dxxA96mcqzEBPck0thh35YJNuywsfkos,8875
+rope/base/pyobjectsdef.py,sha256=lPIsGh7xREP3z2A2Uu0xsTiuBQLibh6F86E9VDP9Knc,20178
+rope/base/pyscopes.py,sha256=zw6zZrQ8qPKKt6O05uK3Ipmz1_O6_2Hv58W8q6j-Wbc,9752
+rope/base/resourceobserver.py,sha256=ZzqcEJp8ZnYVeumeC4y21sNKpXup17E-oyOxOF8eS8g,10280
+rope/base/resources.py,sha256=9U25gYnYfI4-39tU0rFMw7JHw-HXWqBCDStrGA1SGqM,7342
+rope/base/simplify.py,sha256=vnyeDUZ6I5Q-n2Am2E_1KFZTvDmnWQ8IyTIc_339RY8,1692
+rope/base/stdmods.py,sha256=PUVFW-jIRZEc57bZVTTC3qnJ1ZriX1TdOqE0EKiDyes,1868
+rope/base/taskhandle.py,sha256=68_PvCX_mqrJjWq7gTnAUlhTs7KC6cBUO8WcT3w1yDw,2874
+rope/base/utils/__init__.py,sha256=d5BnLRbQcsIZTKB-rSkV09_Mhuy-ElDk__l5xoR1Nbc,2730
+rope/base/utils/__pycache__/__init__.cpython-37.pyc,,
+rope/base/utils/__pycache__/datastructures.cpython-37.pyc,,
+rope/base/utils/__pycache__/pycompat.cpython-37.pyc,,
+rope/base/utils/datastructures.py,sha256=d2OKPP93b6We7_4_0OLkFYSgQUfkDEd9QFbPl25V9BM,1826
+rope/base/utils/pycompat.py,sha256=o8gWnlnQg28NHCa-HIceJMJVIXMbgqUQ31j4hBdGyIw,1127
+rope/base/worder.py,sha256=OHIZ1dQPTfwKzpsW7raf_LzlyH4kW1fj2JkStAZr2oo,21191
+rope/contrib/__init__.py,sha256=2td2_QPauCvImOVmz3a860j2yE-W3stg9BOh1Mb4dlE,169
+rope/contrib/__pycache__/__init__.cpython-37.pyc,,
+rope/contrib/__pycache__/autoimport.cpython-37.pyc,,
+rope/contrib/__pycache__/changestack.cpython-37.pyc,,
+rope/contrib/__pycache__/codeassist.cpython-37.pyc,,
+rope/contrib/__pycache__/finderrors.cpython-37.pyc,,
+rope/contrib/__pycache__/findit.cpython-37.pyc,,
+rope/contrib/__pycache__/fixmodnames.cpython-37.pyc,,
+rope/contrib/__pycache__/fixsyntax.cpython-37.pyc,,
+rope/contrib/__pycache__/generate.cpython-37.pyc,,
+rope/contrib/autoimport.py,sha256=0-BUi1lpq2r7JCQDrkR0zG7ZOqyhHzvs1VV_I0IOK04,8196
+rope/contrib/changestack.py,sha256=sMcj4ugeYf29bLKRwnRXxRjkBTTXnZfkzCsS3Qeu4G8,1392
+rope/contrib/codeassist.py,sha256=zdQhv5RsX32CfPEP7NGcuv6bAWzpibSFL5OC5QGMH0s,26806
+rope/contrib/finderrors.py,sha256=wRaqtDOUIT7vBpm-6qbdzGdPZ8OaE3SvQH76j4EfYnU,2934
+rope/contrib/findit.py,sha256=wcaQf6Pbj6nNi68h4nCVgX4aV_FZGoOjYSFj01DRYOg,4417
+rope/contrib/fixmodnames.py,sha256=oTRRK-g1AyNOVePe7aWppS_usicEm3frq8JcTzVUATc,2241
+rope/contrib/fixsyntax.py,sha256=89677hrUg6vA1CRLp2NiAufc5Mel7R_iSdhXbuBR7ew,6881
+rope/contrib/generate.py,sha256=G4hsobAKb3V-8oBQ1tc2B9oCUFl9pQpZgP5c4xCX7ME,14353
+rope/refactor/__init__.py,sha256=ljN2iK1nG8uzKm8zMWNsFb0hyMTVBu_miIhGz6E4FSY,2097
+rope/refactor/__pycache__/__init__.cpython-37.pyc,,
+rope/refactor/__pycache__/change_signature.cpython-37.pyc,,
+rope/refactor/__pycache__/encapsulate_field.cpython-37.pyc,,
+rope/refactor/__pycache__/extract.cpython-37.pyc,,
+rope/refactor/__pycache__/functionutils.cpython-37.pyc,,
+rope/refactor/__pycache__/inline.cpython-37.pyc,,
+rope/refactor/__pycache__/introduce_factory.cpython-37.pyc,,
+rope/refactor/__pycache__/introduce_parameter.cpython-37.pyc,,
+rope/refactor/__pycache__/localtofield.cpython-37.pyc,,
+rope/refactor/__pycache__/method_object.cpython-37.pyc,,
+rope/refactor/__pycache__/move.cpython-37.pyc,,
+rope/refactor/__pycache__/multiproject.cpython-37.pyc,,
+rope/refactor/__pycache__/occurrences.cpython-37.pyc,,
+rope/refactor/__pycache__/patchedast.cpython-37.pyc,,
+rope/refactor/__pycache__/rename.cpython-37.pyc,,
+rope/refactor/__pycache__/restructure.cpython-37.pyc,,
+rope/refactor/__pycache__/similarfinder.cpython-37.pyc,,
+rope/refactor/__pycache__/sourceutils.cpython-37.pyc,,
+rope/refactor/__pycache__/suites.cpython-37.pyc,,
+rope/refactor/__pycache__/topackage.cpython-37.pyc,,
+rope/refactor/__pycache__/usefunction.cpython-37.pyc,,
+rope/refactor/__pycache__/wildcards.cpython-37.pyc,,
+rope/refactor/change_signature.py,sha256=hkBpjINnBVwqc9u4dhGin3nGKsvDku6WNiA__ZhbIBc,13467
+rope/refactor/encapsulate_field.py,sha256=xRGLfJbIV0ZpZFHnok6ES28U5B-B8y0bXjTgb6BGbho,8761
+rope/refactor/extract.py,sha256=A11zvxGtjLskM-r761QDsLHqDbkpYsCU0LkfSXaTPbs,29343
+rope/refactor/functionutils.py,sha256=9ANJ2Ri6x-y3lfsWZu8QRK6Vtu-d_zPciLTucknBwHY,8413
+rope/refactor/importutils/__init__.py,sha256=w7SZAoST_Xad4teWbg79WmcflT8rkEEdAzQYsmAiZ24,13361
+rope/refactor/importutils/__pycache__/__init__.cpython-37.pyc,,
+rope/refactor/importutils/__pycache__/actions.cpython-37.pyc,,
+rope/refactor/importutils/__pycache__/importinfo.cpython-37.pyc,,
+rope/refactor/importutils/__pycache__/module_imports.cpython-37.pyc,,
+rope/refactor/importutils/actions.py,sha256=2vIs-_HLwAyZNP8_UudupFgobkl8D2MfWiWVGjREp74,14206
+rope/refactor/importutils/importinfo.py,sha256=HrINeI4YslVwau1qok3TW8_RL4ymTV3mo2yXiiE2kY0,5759
+rope/refactor/importutils/module_imports.py,sha256=9lWkJy92F8uYLJjc5M3zxhR3oMv7aprHgnE7NpFcD_g,19010
+rope/refactor/inline.py,sha256=MOvn8U4pif2RW4o5oISH9Z2Fb2sdX7RaMQA3xRbMM6U,25380
+rope/refactor/introduce_factory.py,sha256=ccjSxVc-1MYfLwfF2Yg4exJziHgWAzKLbd8PGqmbLJE,6190
+rope/refactor/introduce_parameter.py,sha256=yLz6VxjShrZhgCT6REU5mcv0z6_HKZh9FvqEiYLcblI,3908
+rope/refactor/localtofield.py,sha256=7YZMjcn35x8QDkTDGG7mDKKttOF54U79TUGEmniiBIw,2052
+rope/refactor/method_object.py,sha256=YvNRQOTrS6AWTAd4IpXWYOe-hS_aUk3djG_2nndIxgE,3932
+rope/refactor/move.py,sha256=KQ6LIUqZUPd7EoYSZX4nl1ztSCQ2TQXx8C6A3Ss1p8Q,33304
+rope/refactor/multiproject.py,sha256=ngYFgL-J8CLBuT1UONBlZO_nTnAwxtHb5PS2OHH6JzQ,2615
+rope/refactor/occurrences.py,sha256=zbXIU41OIq2q9Ju28jdquGWscqgv6jM94hRgocWG3WU,12841
+rope/refactor/patchedast.py,sha256=42kfkdry0FsFIt_Uhv9AzRZIE_XflwaKtDEFjkrbEL0,28944
+rope/refactor/rename.py,sha256=Du_40DzAo9gVfduoc9pQW-BjT8uHDxtnAX24IpG8d2M,9384
+rope/refactor/restructure.py,sha256=h3QlLi0lN18dPZmyyaLMXzzOlCo00antwATGzHcuALs,11595
+rope/refactor/similarfinder.py,sha256=VERdp7zee1ePyvNPGapwJL062SMD1PnCL3gGON7kF10,12486
+rope/refactor/sourceutils.py,sha256=RKDJ7iXiE95M-vXefG1zpmvn6yhIkIlRlKeCFzPDsr4,2955
+rope/refactor/suites.py,sha256=CF47hvELKPXImS9esJKFl2FVFlEUZshBUGasLTC_ieU,4931
+rope/refactor/topackage.py,sha256=2INH2Gw5c8-b4518wqWaTPOFyo4ZFg_zLzg50ODLEak,1269
+rope/refactor/usefunction.py,sha256=zGhm0wldnsXiHBQ-uYrCR2q904itOvcVkKXndLQRh3s,6280
+rope/refactor/wildcards.py,sha256=lrqS0oeWcY9yoOfPjgghdXRLRMPCDPp0_dIZFy4KTgY,5833
diff --git a/venv/Lib/site-packages/rope-0.14.0.dist-info/WHEEL b/venv/Lib/site-packages/rope-0.14.0.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..6261a26e7a4c380ad73a4316b8a18d8fa839205d
--- /dev/null
+++ b/venv/Lib/site-packages/rope-0.14.0.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.30.0)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/venv/Lib/site-packages/rope-0.14.0.dist-info/metadata.json b/venv/Lib/site-packages/rope-0.14.0.dist-info/metadata.json
new file mode 100644
index 0000000000000000000000000000000000000000..6263a8e5e1798fd2682dc1bdd5828b3cc8f91cb3
--- /dev/null
+++ b/venv/Lib/site-packages/rope-0.14.0.dist-info/metadata.json
@@ -0,0 +1 @@
+{"classifiers": ["Development Status :: 4 - Beta", "Operating System :: OS Independent", "Environment :: X11 Applications", "Environment :: Win32 (MS Windows)", "Environment :: MacOS X", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Software Development"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"contacts": [{"email": "aligrudi@users.sourceforge.net", "name": "Ali Gholami Rudi", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/python-rope/rope"}}}, "generator": "bdist_wheel (0.30.0)", "license": "GNU GPL", "metadata_version": "2.0", "name": "rope", "summary": "a python refactoring library...", "version": "0.14.0"}
\ No newline at end of file
diff --git a/venv/Lib/site-packages/rope-0.14.0.dist-info/top_level.txt b/venv/Lib/site-packages/rope-0.14.0.dist-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..649b5f000e3b85ccdbfb79b5988eb2a721940b30
--- /dev/null
+++ b/venv/Lib/site-packages/rope-0.14.0.dist-info/top_level.txt
@@ -0,0 +1 @@
+rope
diff --git a/venv/Lib/site-packages/rope/__init__.py b/venv/Lib/site-packages/rope/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..f85a713438986debf349ffff2f847179d9d296d8
--- /dev/null
+++ b/venv/Lib/site-packages/rope/__init__.py
@@ -0,0 +1,24 @@
+"""rope, a python refactoring library"""
+
+INFO = __doc__
+VERSION = '0.14.0'
+COPYRIGHT = """\
+Copyright (C) 2019 Matej Cepl
+Copyright (C) 2015-2018 Nicholas Smith
+Copyright (C) 2014-2015 Matej Cepl
+Copyright (C) 2006-2012 Ali Gholami Rudi
+Copyright (C) 2009-2012 Anton Gritsay
+
+This program 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 3 of the License, or (at your option) any later version.
+
+This program 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 program.  If not, see
+<https://www.gnu.org/licenses/>."""
diff --git a/venv/Lib/site-packages/rope/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..789f178109641dd890a26e97dda1a3f5c4503f29
Binary files /dev/null and b/venv/Lib/site-packages/rope/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__init__.py b/venv/Lib/site-packages/rope/base/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff5f8c63ae9daa3003f17b157039e0562837ee48
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/__init__.py
@@ -0,0 +1,8 @@
+"""Base rope package
+
+This package contains rope core modules that are used by other modules
+and packages.
+
+"""
+
+__all__ = ['project', 'libutils', 'exceptions']
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ae53efd4d6a0df0d478b5a5482be7dd10b0af421
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/arguments.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/arguments.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7148841f18fcc5be818a93b7f39a48ed24a7adf9
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/arguments.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/ast.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/ast.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2f4591894896ef2145d3005864fec180191a93b3
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/ast.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/astutils.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/astutils.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cc25e971ed6ef5934b55ed775329c4fc56f4aff4
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/astutils.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/builtins.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/builtins.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..837fcf91f929cd977bdf41b8f8c595fcc84dcffb
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/builtins.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/change.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/change.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4ec09e0cfeec843c0f4526cf0735d0f3fefdcca5
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/change.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/codeanalyze.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/codeanalyze.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..865fd7c5450004e563edbd29e1d715fff385988b
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/codeanalyze.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/default_config.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/default_config.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f0355a2ab9d3b77c3827cd178fa305421edc1238
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/default_config.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/evaluate.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/evaluate.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dd41d1422d7e1ffdc56c031dbce42110f49bd153
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/evaluate.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/exceptions.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/exceptions.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6c9b4f1c6102142a101b9eaa8006676ae9dc1811
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/exceptions.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/fscommands.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/fscommands.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ca8f6dbeec6052d1f9e1a4257ea51e2e9f49be61
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/fscommands.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/history.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/history.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a87810228bdd731c97d9ef5fd17487238285e39e
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/history.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/libutils.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/libutils.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..47ec606966278f35edb2fca62667ccfb46fa1a0b
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/libutils.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/prefs.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/prefs.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..71907c1431044e2ea1e8ccec76f0e7f31b9e3849
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/prefs.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/project.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/project.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e98c39d7e4dc9656078581e67226be582ba22faf
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/project.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/pycore.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/pycore.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..acca53e98ddfb8e75bfb713da7f2cb95a63d500e
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/pycore.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/pynames.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/pynames.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5d3e891c65207151a7af810aace9cc813ac4533c
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/pynames.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/pynamesdef.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/pynamesdef.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..af8f16959370eaccea4b39b5d0181df754c57c4d
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/pynamesdef.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/pyobjects.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/pyobjects.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cee82f9851872d205d5f257ef05562c9961d38b4
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/pyobjects.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/pyobjectsdef.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/pyobjectsdef.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d68f802f81b57bad229ab335a97b370774b2795e
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/pyobjectsdef.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/pyscopes.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/pyscopes.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7ba43a6e987b341575a127697675dfdd96764b2a
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/pyscopes.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/resourceobserver.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/resourceobserver.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1c620da3c4e30e05a52349d953c422456ef59957
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/resourceobserver.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/resources.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/resources.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8b0ad295532f096671a5660a8db34ff0a59213b4
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/resources.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/simplify.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/simplify.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3a2dd8c4833c2e7ac872673dcf0e8057ac9215f2
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/simplify.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/stdmods.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/stdmods.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..28749a0f788767758e22b7b37981e797f972f5e6
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/stdmods.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/taskhandle.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/taskhandle.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3c48f28ca204c18e4d463e8adfa927546f6e30d8
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/taskhandle.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/__pycache__/worder.cpython-37.pyc b/venv/Lib/site-packages/rope/base/__pycache__/worder.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..af32380d82a16179865c4e2e2d20c11809da59a6
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/__pycache__/worder.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/arguments.py b/venv/Lib/site-packages/rope/base/arguments.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ba43640663f56918921fb668285b897a1deaefa
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/arguments.py
@@ -0,0 +1,111 @@
+import rope.base.evaluate
+from rope.base import ast
+
+
+class Arguments(object):
+    """A class for evaluating parameters passed to a function
+
+    You can use the `create_arguments` factory.  It handles implicit
+    first arguments.
+
+    """
+
+    def __init__(self, args, scope):
+        self.args = args
+        self.scope = scope
+        self.instance = None
+
+    def get_arguments(self, parameters):
+        result = []
+        for pyname in self.get_pynames(parameters):
+            if pyname is None:
+                result.append(None)
+            else:
+                result.append(pyname.get_object())
+        return result
+
+    def get_pynames(self, parameters):
+        result = [None] * max(len(parameters), len(self.args))
+        for index, arg in enumerate(self.args):
+            if isinstance(arg, ast.keyword) and arg.arg in parameters:
+                result[parameters.index(arg.arg)] = self._evaluate(arg.value)
+            else:
+                result[index] = self._evaluate(arg)
+        return result
+
+    def get_instance_pyname(self):
+        if self.args:
+            return self._evaluate(self.args[0])
+
+    def _evaluate(self, ast_node):
+        return rope.base.evaluate.eval_node(self.scope, ast_node)
+
+
+def create_arguments(primary, pyfunction, call_node, scope):
+    """A factory for creating `Arguments`"""
+    args = list(call_node.args)
+    args.extend(call_node.keywords)
+    called = call_node.func
+    # XXX: Handle constructors
+    if _is_method_call(primary, pyfunction) and \
+       isinstance(called, ast.Attribute):
+        args.insert(0, called.value)
+    return Arguments(args, scope)
+
+
+class ObjectArguments(object):
+
+    def __init__(self, pynames):
+        self.pynames = pynames
+
+    def get_arguments(self, parameters):
+        result = []
+        for pyname in self.pynames:
+            if pyname is None:
+                result.append(None)
+            else:
+                result.append(pyname.get_object())
+        return result
+
+    def get_pynames(self, parameters):
+        return self.pynames
+
+    def get_instance_pyname(self):
+        return self.pynames[0]
+
+
+class MixedArguments(object):
+
+    def __init__(self, pyname, arguments, scope):
+        """`argumens` is an instance of `Arguments`"""
+        self.pyname = pyname
+        self.args = arguments
+
+    def get_pynames(self, parameters):
+        return [self.pyname] + self.args.get_pynames(parameters[1:])
+
+    def get_arguments(self, parameters):
+        result = []
+        for pyname in self.get_pynames(parameters):
+            if pyname is None:
+                result.append(None)
+            else:
+                result.append(pyname.get_object())
+        return result
+
+    def get_instance_pyname(self):
+        return self.pyname
+
+
+def _is_method_call(primary, pyfunction):
+    if primary is None:
+        return False
+    pyobject = primary.get_object()
+    if isinstance(pyobject.get_type(), rope.base.pyobjects.PyClass) and \
+       isinstance(pyfunction, rope.base.pyobjects.PyFunction) and \
+       isinstance(pyfunction.parent, rope.base.pyobjects.PyClass):
+        return True
+    if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass) and \
+       isinstance(pyfunction, rope.base.builtins.BuiltinFunction):
+        return True
+    return False
diff --git a/venv/Lib/site-packages/rope/base/ast.py b/venv/Lib/site-packages/rope/base/ast.py
new file mode 100644
index 0000000000000000000000000000000000000000..d43c83c55bed265f936352df2393c52d059d81d4
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/ast.py
@@ -0,0 +1,76 @@
+import _ast
+from _ast import *
+
+from rope.base import fscommands
+
+try:
+    unicode
+except NameError:
+    unicode = str
+
+
+def parse(source, filename='<string>'):
+    # NOTE: the raw string should be given to `compile` function
+    if isinstance(source, unicode):
+        source = fscommands.unicode_to_file_data(source)
+    if b'\r' in source:
+        source = source.replace(b'\r\n', b'\n').replace(b'\r', b'\n')
+    if not source.endswith(b'\n'):
+        source += b'\n'
+    try:
+        return compile(source, filename, 'exec', _ast.PyCF_ONLY_AST)
+    except (TypeError, ValueError) as e:
+        error = SyntaxError()
+        error.lineno = 1
+        error.filename = filename
+        error.msg = str(e)
+        raise error
+
+
+def walk(node, walker):
+    """Walk the syntax tree"""
+    method_name = '_' + node.__class__.__name__
+    method = getattr(walker, method_name, None)
+    if method is not None:
+        if isinstance(node, _ast.ImportFrom) and node.module is None:
+            # In python < 2.7 ``node.module == ''`` for relative imports
+            # but for python 2.7 it is None. Generalizing it to ''.
+            node.module = ''
+        return method(node)
+    for child in get_child_nodes(node):
+        walk(child, walker)
+
+
+def get_child_nodes(node):
+    if isinstance(node, _ast.Module):
+        return node.body
+    result = []
+    if node._fields is not None:
+        for name in node._fields:
+            child = getattr(node, name)
+            if isinstance(child, list):
+                for entry in child:
+                    if isinstance(entry, _ast.AST):
+                        result.append(entry)
+            if isinstance(child, _ast.AST):
+                result.append(child)
+    return result
+
+
+def call_for_nodes(node, callback, recursive=False):
+    """If callback returns `True` the child nodes are skipped"""
+    result = callback(node)
+    if recursive and not result:
+        for child in get_child_nodes(node):
+            call_for_nodes(child, callback, recursive)
+
+
+def get_children(node):
+    result = []
+    if node._fields is not None:
+        for name in node._fields:
+            if name in ['lineno', 'col_offset']:
+                continue
+            child = getattr(node, name)
+            result.append(child)
+    return result
diff --git a/venv/Lib/site-packages/rope/base/astutils.py b/venv/Lib/site-packages/rope/base/astutils.py
new file mode 100644
index 0000000000000000000000000000000000000000..6c0b3d78e2e5d198be10a6bb339c8e5de2e36c97
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/astutils.py
@@ -0,0 +1,64 @@
+from rope.base import ast
+
+
+def get_name_levels(node):
+    """Return a list of ``(name, level)`` tuples for assigned names
+
+    The `level` is `None` for simple assignments and is a list of
+    numbers for tuple assignments for example in::
+
+      a, (b, c) = x
+
+    The levels for for `a` is ``[0]``, for `b` is ``[1, 0]`` and for
+    `c` is ``[1, 1]``.
+
+    """
+    visitor = _NodeNameCollector()
+    ast.walk(node, visitor)
+    return visitor.names
+
+
+class _NodeNameCollector(object):
+
+    def __init__(self, levels=None):
+        self.names = []
+        self.levels = levels
+        self.index = 0
+
+    def _add_node(self, node):
+        new_levels = []
+        if self.levels is not None:
+            new_levels = list(self.levels)
+            new_levels.append(self.index)
+        self.index += 1
+        self._added(node, new_levels)
+
+    def _added(self, node, levels):
+        if hasattr(node, 'id'):
+            self.names.append((node.id, levels))
+
+    def _Name(self, node):
+        self._add_node(node)
+
+    def _ExceptHandler(self, node):
+        self.names.append((node.name, []))
+
+    def _Tuple(self, node):
+        new_levels = []
+        if self.levels is not None:
+            new_levels = list(self.levels)
+            new_levels.append(self.index)
+        self.index += 1
+        visitor = _NodeNameCollector(new_levels)
+        for child in ast.get_child_nodes(node):
+            ast.walk(child, visitor)
+        self.names.extend(visitor.names)
+
+    def _Subscript(self, node):
+        self._add_node(node)
+
+    def _Attribute(self, node):
+        self._add_node(node)
+
+    def _Slice(self, node):
+        self._add_node(node)
diff --git a/venv/Lib/site-packages/rope/base/builtins.py b/venv/Lib/site-packages/rope/base/builtins.py
new file mode 100644
index 0000000000000000000000000000000000000000..bd3d9381d5af72de87c563cd389834930902fcdc
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/builtins.py
@@ -0,0 +1,826 @@
+"""This module trys to support builtin types and functions."""
+import inspect
+import io
+
+try:
+    raw_input
+except NameError:
+    raw_input = input
+
+import rope.base.evaluate
+from rope.base.utils import pycompat
+from rope.base import pynames, pyobjects, arguments, utils
+
+
+class BuiltinModule(pyobjects.AbstractModule):
+
+    def __init__(self, name, pycore=None, initial={}):
+        super(BuiltinModule, self).__init__()
+        self.name = name
+        self.pycore = pycore
+        self.initial = initial
+
+    parent = None
+
+    def get_attributes(self):
+        return self.attributes
+
+    def get_doc(self):
+        if self.module:
+            return self.module.__doc__
+
+    def get_name(self):
+        return self.name.split('.')[-1]
+
+    @property
+    @utils.saveit
+    def attributes(self):
+        result = _object_attributes(self.module, self)
+        result.update(self.initial)
+        if self.pycore is not None:
+            submodules = self.pycore._builtin_submodules(self.name)
+            for name, module in submodules.items():
+                result[name] = rope.base.builtins.BuiltinName(module)
+        return result
+
+    @property
+    @utils.saveit
+    def module(self):
+        try:
+            result = __import__(self.name)
+            for token in self.name.split('.')[1:]:
+                result = getattr(result, token, None)
+            return result
+        except ImportError:
+            return
+
+
+class _BuiltinElement(object):
+
+    def __init__(self, builtin, parent=None):
+        self.builtin = builtin
+        self._parent = parent
+
+    def get_doc(self):
+        if self.builtin:
+            return getattr(self.builtin, '__doc__', None)
+
+    def get_name(self):
+        if self.builtin:
+            return getattr(self.builtin, '__name__', None)
+
+    @property
+    def parent(self):
+        if self._parent is None:
+            return builtins
+        return self._parent
+
+
+class BuiltinClass(_BuiltinElement, pyobjects.AbstractClass):
+
+    def __init__(self, builtin, attributes, parent=None):
+        _BuiltinElement.__init__(self, builtin, parent)
+        pyobjects.AbstractClass.__init__(self)
+        self.initial = attributes
+
+    @utils.saveit
+    def get_attributes(self):
+        result = _object_attributes(self.builtin, self)
+        result.update(self.initial)
+        return result
+
+    def get_module(self):
+        return builtins
+
+
+class BuiltinFunction(_BuiltinElement, pyobjects.AbstractFunction):
+
+    def __init__(self, returned=None, function=None, builtin=None,
+                 argnames=[], parent=None):
+        _BuiltinElement.__init__(self, builtin, parent)
+        pyobjects.AbstractFunction.__init__(self)
+        self.argnames = argnames
+        self.returned = returned
+        self.function = function
+
+    def get_returned_object(self, args):
+        if self.function is not None:
+            return self.function(_CallContext(self.argnames, args))
+        else:
+            return self.returned
+
+    def get_param_names(self, special_args=True):
+        return self.argnames
+
+
+class BuiltinUnknown(_BuiltinElement, pyobjects.PyObject):
+
+    def __init__(self, builtin):
+        super(BuiltinUnknown, self).__init__(pyobjects.get_unknown())
+        self.builtin = builtin
+        self.type = pyobjects.get_unknown()
+
+    def get_name(self):
+        return getattr(type(self.builtin), '__name__', None)
+
+    @utils.saveit
+    def get_attributes(self):
+        return _object_attributes(self.builtin, self)
+
+
+def _object_attributes(obj, parent):
+    attributes = {}
+    for name in dir(obj):
+        if name == 'None':
+            continue
+        try:
+            child = getattr(obj, name)
+        except AttributeError:
+            # descriptors are allowed to raise AttributeError
+            # even if they are in dir()
+            continue
+        pyobject = None
+        if inspect.isclass(child):
+            pyobject = BuiltinClass(child, {}, parent=parent)
+        elif inspect.isroutine(child):
+            pyobject = BuiltinFunction(builtin=child, parent=parent)
+        else:
+            pyobject = BuiltinUnknown(builtin=child)
+        attributes[name] = BuiltinName(pyobject)
+    return attributes
+
+
+def _create_builtin_type_getter(cls):
+    def _get_builtin(*args):
+        if not hasattr(cls, '_generated'):
+            cls._generated = {}
+        if args not in cls._generated:
+            cls._generated[args] = cls(*args)
+        return cls._generated[args]
+    return _get_builtin
+
+
+def _create_builtin_getter(cls):
+    type_getter = _create_builtin_type_getter(cls)
+
+    def _get_builtin(*args):
+        return pyobjects.PyObject(type_getter(*args))
+    return _get_builtin
+
+
+class _CallContext(object):
+
+    def __init__(self, argnames, args):
+        self.argnames = argnames
+        self.args = args
+
+    def _get_scope_and_pyname(self, pyname):
+        if pyname is not None and isinstance(pyname, pynames.AssignedName):
+            pymodule, lineno = pyname.get_definition_location()
+            if pymodule is None:
+                return None, None
+            if lineno is None:
+                lineno = 1
+            scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+            name = None
+            while name is None and scope is not None:
+                for current in scope.get_names():
+                    if scope[current] is pyname:
+                        name = current
+                        break
+                else:
+                    scope = scope.parent
+            return scope, name
+        return None, None
+
+    def get_argument(self, name):
+        if self.args:
+            args = self.args.get_arguments(self.argnames)
+            return args[self.argnames.index(name)]
+
+    def get_pyname(self, name):
+        if self.args:
+            args = self.args.get_pynames(self.argnames)
+            if name in self.argnames:
+                return args[self.argnames.index(name)]
+
+    def get_arguments(self, argnames):
+        if self.args:
+            return self.args.get_arguments(argnames)
+
+    def get_pynames(self, argnames):
+        if self.args:
+            return self.args.get_pynames(argnames)
+
+    def get_per_name(self):
+        if self.args is None:
+            return None
+        pyname = self.args.get_instance_pyname()
+        scope, name = self._get_scope_and_pyname(pyname)
+        if name is not None:
+            pymodule = pyname.get_definition_location()[0]
+            return pymodule.pycore.object_info.get_per_name(scope, name)
+        return None
+
+    def save_per_name(self, value):
+        if self.args is None:
+            return None
+        pyname = self.args.get_instance_pyname()
+        scope, name = self._get_scope_and_pyname(pyname)
+        if name is not None:
+            pymodule = pyname.get_definition_location()[0]
+            pymodule.pycore.object_info.save_per_name(scope, name, value)
+
+
+class _AttributeCollector(object):
+
+    def __init__(self, type):
+        self.attributes = {}
+        self.type = type
+
+    def __call__(self, name, returned=None, function=None,
+                 argnames=['self'], check_existence=True,
+                 parent=None):
+        try:
+            builtin = getattr(self.type, name)
+        except AttributeError:
+            if check_existence:
+                raise
+            builtin = None
+        self.attributes[name] = BuiltinName(
+            BuiltinFunction(returned=returned, function=function,
+                            argnames=argnames, builtin=builtin,
+                            parent=parent))
+
+    def __setitem__(self, name, value):
+        self.attributes[name] = value
+
+
+class List(BuiltinClass):
+
+    def __init__(self, holding=None):
+        self.holding = holding
+        collector = _AttributeCollector(list)
+
+        collector('__iter__', function=self._iterator_get, parent=self)
+        collector('__new__', function=self._new_list, parent=self)
+
+        # Adding methods
+        collector('append', function=self._list_add,
+                  argnames=['self', 'value'], parent=self)
+        collector('__setitem__', function=self._list_add,
+                  argnames=['self', 'index', 'value'], parent=self)
+        collector('insert', function=self._list_add,
+                  argnames=['self', 'index', 'value'], parent=self)
+        collector('extend', function=self._self_set,
+                  argnames=['self', 'iterable'], parent=self)
+
+        # Getting methods
+        collector('__getitem__', function=self._list_get, parent=self)
+        collector('pop', function=self._list_get, parent=self)
+        try:
+            collector('__getslice__', function=self._list_get)
+        except AttributeError:
+            pass
+
+        super(List, self).__init__(list, collector.attributes)
+
+    def _new_list(self, args):
+        return _create_builtin(args, get_list)
+
+    def _list_add(self, context):
+        if self.holding is not None:
+            return
+        holding = context.get_argument('value')
+        if holding is not None and holding != pyobjects.get_unknown():
+            context.save_per_name(holding)
+
+    def _self_set(self, context):
+        if self.holding is not None:
+            return
+        iterable = context.get_pyname('iterable')
+        holding = _infer_sequence_for_pyname(iterable)
+        if holding is not None and holding != pyobjects.get_unknown():
+            context.save_per_name(holding)
+
+    def _list_get(self, context):
+        if self.holding is not None:
+            args = context.get_arguments(['self', 'key'])
+            if (len(args) > 1 and args[1] is not None and
+                    args[1].get_type() == builtins['slice'].get_object()):
+                return get_list(self.holding)
+            return self.holding
+        return context.get_per_name()
+
+    def _iterator_get(self, context):
+        return get_iterator(self._list_get(context))
+
+    def _self_get(self, context):
+        return get_list(self._list_get(context))
+
+
+get_list = _create_builtin_getter(List)
+get_list_type = _create_builtin_type_getter(List)
+
+
+class Dict(BuiltinClass):
+
+    def __init__(self, keys=None, values=None):
+        self.keys = keys
+        self.values = values
+        collector = _AttributeCollector(dict)
+        collector('__new__', function=self._new_dict, parent=self)
+        collector('__setitem__', function=self._dict_add, parent=self)
+        collector('popitem', function=self._item_get, parent=self)
+        collector('pop', function=self._value_get, parent=self)
+        collector('get', function=self._key_get, parent=self)
+        collector('keys', function=self._key_list, parent=self)
+        collector('values', function=self._value_list, parent=self)
+        collector('items', function=self._item_list, parent=self)
+        collector('copy', function=self._self_get, parent=self)
+        collector('__getitem__', function=self._value_get, parent=self)
+        collector('__iter__', function=self._key_iter, parent=self)
+        collector('update', function=self._self_set, parent=self)
+        super(Dict, self).__init__(dict, collector.attributes)
+
+    def _new_dict(self, args):
+        def do_create(holding=None):
+            if holding is None:
+                return get_dict()
+            type = holding.get_type()
+            if isinstance(type, Tuple) and \
+                    len(type.get_holding_objects()) == 2:
+                return get_dict(*type.get_holding_objects())
+        return _create_builtin(args, do_create)
+
+    def _dict_add(self, context):
+        if self.keys is not None:
+            return
+        key, value = context.get_arguments(['self', 'key', 'value'])[1:]
+        if key is not None and key != pyobjects.get_unknown():
+            context.save_per_name(get_tuple(key, value))
+
+    def _item_get(self, context):
+        if self.keys is not None:
+            return get_tuple(self.keys, self.values)
+        item = context.get_per_name()
+        if item is None or not isinstance(item.get_type(), Tuple):
+            return get_tuple(self.keys, self.values)
+        return item
+
+    def _value_get(self, context):
+        item = self._item_get(context).get_type()
+        return item.get_holding_objects()[1]
+
+    def _key_get(self, context):
+        item = self._item_get(context).get_type()
+        return item.get_holding_objects()[0]
+
+    def _value_list(self, context):
+        return get_list(self._value_get(context))
+
+    def _key_list(self, context):
+        return get_list(self._key_get(context))
+
+    def _item_list(self, context):
+        return get_list(self._item_get(context))
+
+    def _value_iter(self, context):
+        return get_iterator(self._value_get(context))
+
+    def _key_iter(self, context):
+        return get_iterator(self._key_get(context))
+
+    def _item_iter(self, context):
+        return get_iterator(self._item_get(context))
+
+    def _self_get(self, context):
+        item = self._item_get(context).get_type()
+        key, value = item.get_holding_objects()[:2]
+        return get_dict(key, value)
+
+    def _self_set(self, context):
+        if self.keys is not None:
+            return
+        new_dict = context.get_pynames(['self', 'd'])[1]
+        if new_dict and isinstance(new_dict.get_object().get_type(), Dict):
+            args = arguments.ObjectArguments([new_dict])
+            items = new_dict.get_object()['popitem'].\
+                get_object().get_returned_object(args)
+            context.save_per_name(items)
+        else:
+            holding = _infer_sequence_for_pyname(new_dict)
+            if holding is not None and isinstance(holding.get_type(), Tuple):
+                context.save_per_name(holding)
+
+
+get_dict = _create_builtin_getter(Dict)
+get_dict_type = _create_builtin_type_getter(Dict)
+
+
+class Tuple(BuiltinClass):
+
+    def __init__(self, *objects):
+        self.objects = objects
+        first = None
+        if objects:
+            first = objects[0]
+        attributes = {
+            '__getitem__': BuiltinName(BuiltinFunction(first)),  # TODO: add slice support
+            '__getslice__':
+            BuiltinName(BuiltinFunction(pyobjects.PyObject(self))),
+            '__new__': BuiltinName(BuiltinFunction(function=self._new_tuple)),
+            '__iter__': BuiltinName(BuiltinFunction(get_iterator(first)))}
+        super(Tuple, self).__init__(tuple, attributes)
+
+    def get_holding_objects(self):
+        return self.objects
+
+    def _new_tuple(self, args):
+        return _create_builtin(args, get_tuple)
+
+
+get_tuple = _create_builtin_getter(Tuple)
+get_tuple_type = _create_builtin_type_getter(Tuple)
+
+
+class Set(BuiltinClass):
+
+    def __init__(self, holding=None):
+        self.holding = holding
+        collector = _AttributeCollector(set)
+        collector('__new__', function=self._new_set)
+
+        self_methods = ['copy', 'difference', 'intersection',
+                        'symmetric_difference', 'union']
+        for method in self_methods:
+            collector(method, function=self._self_get, parent=self)
+        collector('add', function=self._set_add, parent=self)
+        collector('update', function=self._self_set, parent=self)
+        collector('update', function=self._self_set, parent=self)
+        collector('symmetric_difference_update', function=self._self_set,
+                  parent=self)
+        collector('difference_update', function=self._self_set, parent=self)
+
+        collector('pop', function=self._set_get, parent=self)
+        collector('__iter__', function=self._iterator_get, parent=self)
+        super(Set, self).__init__(set, collector.attributes)
+
+    def _new_set(self, args):
+        return _create_builtin(args, get_set)
+
+    def _set_add(self, context):
+        if self.holding is not None:
+            return
+        holding = context.get_arguments(['self', 'value'])[1]
+        if holding is not None and holding != pyobjects.get_unknown():
+            context.save_per_name(holding)
+
+    def _self_set(self, context):
+        if self.holding is not None:
+            return
+        iterable = context.get_pyname('iterable')
+        holding = _infer_sequence_for_pyname(iterable)
+        if holding is not None and holding != pyobjects.get_unknown():
+            context.save_per_name(holding)
+
+    def _set_get(self, context):
+        if self.holding is not None:
+            return self.holding
+        return context.get_per_name()
+
+    def _iterator_get(self, context):
+        return get_iterator(self._set_get(context))
+
+    def _self_get(self, context):
+        return get_list(self._set_get(context))
+
+
+get_set = _create_builtin_getter(Set)
+get_set_type = _create_builtin_type_getter(Set)
+
+
+class Str(BuiltinClass):
+
+    def __init__(self):
+        self_object = pyobjects.PyObject(self)
+        collector = _AttributeCollector(str)
+        collector('__iter__', get_iterator(self_object), check_existence=False)
+
+        self_methods = ['__getitem__', 'capitalize', 'center',
+                        'encode', 'expandtabs', 'join', 'ljust',
+                        'lower', 'lstrip', 'replace', 'rjust', 'rstrip',
+                        'strip', 'swapcase', 'title', 'translate', 'upper',
+                        'zfill']
+        for method in self_methods:
+            collector(method, self_object, parent=self)
+
+        py2_self_methods = ["__getslice__", "decode"]
+        for method in py2_self_methods:
+            try:
+                collector(method, self_object)
+            except AttributeError:
+                pass
+
+        for method in ['rsplit', 'split', 'splitlines']:
+            collector(method, get_list(self_object), parent=self)
+
+        super(Str, self).__init__(str, collector.attributes)
+
+    def get_doc(self):
+        return str.__doc__
+
+
+get_str = _create_builtin_getter(Str)
+get_str_type = _create_builtin_type_getter(Str)
+
+
+class BuiltinName(pynames.PyName):
+
+    def __init__(self, pyobject):
+        self.pyobject = pyobject
+
+    def get_object(self):
+        return self.pyobject
+
+    def get_definition_location(self):
+        return (None, None)
+
+
+class Iterator(pyobjects.AbstractClass):
+
+    def __init__(self, holding=None):
+        super(Iterator, self).__init__()
+        self.holding = holding
+        self.attributes = {
+            'next': BuiltinName(BuiltinFunction(self.holding)),
+            '__iter__': BuiltinName(BuiltinFunction(self))}
+
+    def get_attributes(self):
+        return self.attributes
+
+    def get_returned_object(self, args):
+        return self.holding
+
+get_iterator = _create_builtin_getter(Iterator)
+
+
+class Generator(pyobjects.AbstractClass):
+
+    def __init__(self, holding=None):
+        super(Generator, self).__init__()
+        self.holding = holding
+        self.attributes = {
+            'next': BuiltinName(BuiltinFunction(self.holding)),
+            '__iter__': BuiltinName(BuiltinFunction(
+                get_iterator(self.holding))),
+            'close': BuiltinName(BuiltinFunction()),
+            'send': BuiltinName(BuiltinFunction()),
+            'throw': BuiltinName(BuiltinFunction())}
+
+    def get_attributes(self):
+        return self.attributes
+
+    def get_returned_object(self, args):
+        return self.holding
+
+get_generator = _create_builtin_getter(Generator)
+
+
+class File(BuiltinClass):
+
+    def __init__(self, filename=None, mode='r', *args):
+        self.filename = filename
+        self.mode = mode
+        self.args = args
+        str_object = get_str()
+        str_list = get_list(get_str())
+        attributes = {}
+
+        def add(name, returned=None, function=None):
+            builtin = getattr(io.TextIOBase, name, None)
+            attributes[name] = BuiltinName(
+                BuiltinFunction(returned=returned, function=function,
+                                builtin=builtin))
+        add('__iter__', get_iterator(str_object))
+        add('__enter__', returned=self)
+        for method in ['next', 'read', 'readline', 'readlines']:
+            add(method, str_list)
+        for method in ['close', 'flush', 'lineno', 'isatty', 'seek', 'tell',
+                       'truncate', 'write', 'writelines']:
+            add(method)
+        super(File, self).__init__(open, attributes)
+
+
+get_file = _create_builtin_getter(File)
+get_file_type = _create_builtin_type_getter(File)
+
+
+class Property(BuiltinClass):
+
+    def __init__(self, fget=None, fset=None, fdel=None, fdoc=None):
+        self._fget = fget
+        self._fdoc = fdoc
+        attributes = {
+            'fget': BuiltinName(BuiltinFunction()),
+            'fset': BuiltinName(pynames.UnboundName()),
+            'fdel': BuiltinName(pynames.UnboundName()),
+            '__new__': BuiltinName(
+                BuiltinFunction(function=_property_function))}
+        super(Property, self).__init__(property, attributes)
+
+    def get_property_object(self, args):
+        if isinstance(self._fget, pyobjects.AbstractFunction):
+            return self._fget.get_returned_object(args)
+
+
+def _property_function(args):
+    parameters = args.get_arguments(['fget', 'fset', 'fdel', 'fdoc'])
+    return pyobjects.PyObject(Property(parameters[0]))
+
+
+class Lambda(pyobjects.AbstractFunction):
+
+    def __init__(self, node, scope):
+        super(Lambda, self).__init__()
+        self.node = node
+        self.arguments = node.args
+        self.scope = scope
+
+    def get_returned_object(self, args):
+        result = rope.base.evaluate.eval_node(self.scope, self.node.body)
+        if result is not None:
+            return result.get_object()
+        else:
+            return pyobjects.get_unknown()
+
+    def get_module(self):
+        return self.parent.get_module()
+
+    def get_scope(self):
+        return self.scope
+
+    def get_kind(self):
+        return 'lambda'
+
+    def get_ast(self):
+        return self.node
+
+    def get_attributes(self):
+        return {}
+
+    def get_name(self):
+        return 'lambda'
+
+    def get_param_names(self, special_args=True):
+        result = [pycompat.get_ast_arg_arg(node) for node in self.arguments.args
+                  if isinstance(node, pycompat.ast_arg_type)]
+        if self.arguments.vararg:
+            result.append('*' + pycompat.get_ast_arg_arg(self.arguments.vararg))
+        if self.arguments.kwarg:
+            result.append('**' + pycompat.get_ast_arg_arg(self.arguments.kwarg))
+        return result
+
+    @property
+    def parent(self):
+        return self.scope.pyobject
+
+
+class BuiltinObject(BuiltinClass):
+
+    def __init__(self):
+        super(BuiltinObject, self).__init__(object, {})
+
+
+class BuiltinType(BuiltinClass):
+
+    def __init__(self):
+        super(BuiltinType, self).__init__(type, {})
+
+
+def _infer_sequence_for_pyname(pyname):
+    if pyname is None:
+        return None
+    seq = pyname.get_object()
+    args = arguments.ObjectArguments([pyname])
+    if '__iter__' in seq:
+        obj = seq['__iter__'].get_object()
+        if not isinstance(obj, pyobjects.AbstractFunction):
+            return None
+        iter = obj.get_returned_object(args)
+        if iter is not None and 'next' in iter:
+            holding = iter['next'].get_object().\
+                get_returned_object(args)
+            return holding
+
+
+def _create_builtin(args, creator):
+    passed = args.get_pynames(['sequence'])[0]
+    if passed is None:
+        holding = None
+    else:
+        holding = _infer_sequence_for_pyname(passed)
+    if holding is not None:
+        return creator(holding)
+    else:
+        return creator()
+
+
+def _open_function(args):
+    return _create_builtin(args, get_file)
+
+
+def _range_function(args):
+    return get_list()
+
+
+def _reversed_function(args):
+    return _create_builtin(args, get_iterator)
+
+
+def _sorted_function(args):
+    return _create_builtin(args, get_list)
+
+
+def _super_function(args):
+    passed_class, passed_self = args.get_arguments(['type', 'self'])
+    if passed_self is None:
+        return passed_class
+    else:
+        #pyclass = passed_self.get_type()
+        pyclass = passed_class
+        if isinstance(pyclass, pyobjects.AbstractClass):
+            supers = pyclass.get_superclasses()
+            if supers:
+                return pyobjects.PyObject(supers[0])
+        return passed_self
+
+
+def _zip_function(args):
+    args = args.get_pynames(['sequence'])
+    objects = []
+    for seq in args:
+        if seq is None:
+            holding = None
+        else:
+            holding = _infer_sequence_for_pyname(seq)
+        objects.append(holding)
+    tuple = get_tuple(*objects)
+    return get_list(tuple)
+
+
+def _enumerate_function(args):
+    passed = args.get_pynames(['sequence'])[0]
+    if passed is None:
+        holding = None
+    else:
+        holding = _infer_sequence_for_pyname(passed)
+    tuple = get_tuple(None, holding)
+    return get_iterator(tuple)
+
+
+def _iter_function(args):
+    passed = args.get_pynames(['sequence'])[0]
+    if passed is None:
+        holding = None
+    else:
+        holding = _infer_sequence_for_pyname(passed)
+    return get_iterator(holding)
+
+
+def _input_function(args):
+    return get_str()
+
+
+_initial_builtins = {
+    'list': BuiltinName(get_list_type()),
+    'dict': BuiltinName(get_dict_type()),
+    'tuple': BuiltinName(get_tuple_type()),
+    'set': BuiltinName(get_set_type()),
+    'str': BuiltinName(get_str_type()),
+    'file': BuiltinName(get_file_type()),
+    'open': BuiltinName(BuiltinFunction(function=_open_function,
+                        builtin=open)),
+    'unicode': BuiltinName(get_str_type()),
+    'range': BuiltinName(BuiltinFunction(function=_range_function,
+                         builtin=range)),
+    'reversed': BuiltinName(BuiltinFunction(function=_reversed_function,
+                            builtin=reversed)),
+    'sorted': BuiltinName(BuiltinFunction(function=_sorted_function,
+                          builtin=sorted)),
+    'super': BuiltinName(BuiltinFunction(function=_super_function,
+                         builtin=super)),
+    'property': BuiltinName(BuiltinFunction(function=_property_function,
+                            builtin=property)),
+    'zip': BuiltinName(BuiltinFunction(function=_zip_function, builtin=zip)),
+    'enumerate': BuiltinName(BuiltinFunction(function=_enumerate_function,
+                             builtin=enumerate)),
+    'object': BuiltinName(BuiltinObject()),
+    'type': BuiltinName(BuiltinType()),
+    'iter': BuiltinName(BuiltinFunction(function=_iter_function,
+                        builtin=iter)),
+    'raw_input': BuiltinName(BuiltinFunction(function=_input_function,
+                             builtin=raw_input)),
+}
+
+builtins = BuiltinModule(pycompat.builtins.__name__, initial=_initial_builtins)
diff --git a/venv/Lib/site-packages/rope/base/change.py b/venv/Lib/site-packages/rope/base/change.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe2ebf435adb36e28509d56f82ca5a707f78df1a
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/change.py
@@ -0,0 +1,450 @@
+import datetime
+import difflib
+import os
+import time
+
+import rope.base.fscommands
+from rope.base import taskhandle, exceptions, utils
+
+
+class Change(object):
+    """The base class for changes
+
+    Rope refactorings return `Change` objects.  They can be previewed,
+    committed or undone.
+    """
+
+    def do(self, job_set=None):
+        """Perform the change
+
+        .. note:: Do use this directly.  Use `Project.do()` instead.
+        """
+
+    def undo(self, job_set=None):
+        """Perform the change
+
+        .. note:: Do use this directly.  Use `History.undo()` instead.
+        """
+
+    def get_description(self):
+        """Return the description of this change
+
+        This can be used for previewing the changes.
+        """
+        return str(self)
+
+    def get_changed_resources(self):
+        """Return the list of resources that will be changed"""
+        return []
+
+    @property
+    @utils.saveit
+    def _operations(self):
+        return _ResourceOperations(self.resource.project)
+
+
+class ChangeSet(Change):
+    """A collection of `Change` objects
+
+    This class holds a collection of changes.  This class provides
+    these fields:
+
+    * `changes`: the list of changes
+    * `description`: the goal of these changes
+    """
+
+    def __init__(self, description, timestamp=None):
+        self.changes = []
+        self.description = description
+        self.time = timestamp
+
+    def do(self, job_set=taskhandle.NullJobSet()):
+        try:
+            done = []
+            for change in self.changes:
+                change.do(job_set)
+                done.append(change)
+            self.time = time.time()
+        except Exception:
+            for change in done:
+                change.undo()
+            raise
+
+    def undo(self, job_set=taskhandle.NullJobSet()):
+        try:
+            done = []
+            for change in reversed(self.changes):
+                change.undo(job_set)
+                done.append(change)
+        except Exception:
+            for change in done:
+                change.do()
+            raise
+
+    def add_change(self, change):
+        self.changes.append(change)
+
+    def get_description(self):
+        result = [str(self) + ':\n\n\n']
+        for change in self.changes:
+            result.append(change.get_description())
+            result.append('\n')
+        return ''.join(result)
+
+    def __str__(self):
+        if self.time is not None:
+            date = datetime.datetime.fromtimestamp(self.time)
+            if date.date() == datetime.date.today():
+                string_date = 'today'
+            elif date.date() == (datetime.date.today() -
+                                 datetime.timedelta(1)):
+                string_date = 'yesterday'
+            elif date.year == datetime.date.today().year:
+                string_date = date.strftime('%b %d')
+            else:
+                string_date = date.strftime('%d %b, %Y')
+            string_time = date.strftime('%H:%M:%S')
+            string_time = '%s %s ' % (string_date, string_time)
+            return self.description + ' - ' + string_time
+        return self.description
+
+    def get_changed_resources(self):
+        result = set()
+        for change in self.changes:
+            result.update(change.get_changed_resources())
+        return result
+
+
+def _handle_job_set(function):
+    """A decorator for handling `taskhandle.JobSet`\s
+
+    A decorator for handling `taskhandle.JobSet`\s for `do` and `undo`
+    methods of `Change`\s.
+    """
+    def call(self, job_set=taskhandle.NullJobSet()):
+        job_set.started_job(str(self))
+        function(self)
+        job_set.finished_job()
+    return call
+
+
+class ChangeContents(Change):
+    """A class to change the contents of a file
+
+    Fields:
+
+    * `resource`: The `rope.base.resources.File` to change
+    * `new_contents`: What to write in the file
+    """
+
+    def __init__(self, resource, new_contents, old_contents=None):
+        self.resource = resource
+        # IDEA: Only saving diffs; possible problems when undo/redoing
+        self.new_contents = new_contents
+        self.old_contents = old_contents
+
+    @_handle_job_set
+    def do(self):
+        if self.old_contents is None:
+            self.old_contents = self.resource.read()
+        self._operations.write_file(self.resource, self.new_contents)
+
+    @_handle_job_set
+    def undo(self):
+        if self.old_contents is None:
+            raise exceptions.HistoryError(
+                'Undoing a change that is not performed yet!')
+        self._operations.write_file(self.resource, self.old_contents)
+
+    def __str__(self):
+        return 'Change <%s>' % self.resource.path
+
+    def get_description(self):
+        new = self.new_contents
+        old = self.old_contents
+        if old is None:
+            if self.resource.exists():
+                old = self.resource.read()
+            else:
+                old = ''
+        result = difflib.unified_diff(
+            old.splitlines(True), new.splitlines(True),
+            'a/' + self.resource.path, 'b/' + self.resource.path)
+        return ''.join(list(result))
+
+    def get_changed_resources(self):
+        return [self.resource]
+
+
+class MoveResource(Change):
+    """Move a resource to a new location
+
+    Fields:
+
+    * `resource`: The `rope.base.resources.Resource` to move
+    * `new_resource`: The destination for move; It is the moved
+      resource not the folder containing that resource.
+    """
+
+    def __init__(self, resource, new_location, exact=False):
+        self.project = resource.project
+        self.resource = resource
+        if not exact:
+            new_location = _get_destination_for_move(resource, new_location)
+        if resource.is_folder():
+            self.new_resource = self.project.get_folder(new_location)
+        else:
+            self.new_resource = self.project.get_file(new_location)
+
+    @_handle_job_set
+    def do(self):
+        self._operations.move(self.resource, self.new_resource)
+
+    @_handle_job_set
+    def undo(self):
+        self._operations.move(self.new_resource, self.resource)
+
+    def __str__(self):
+        return 'Move <%s>' % self.resource.path
+
+    def get_description(self):
+        return 'rename from %s\nrename to %s' % (self.resource.path,
+                                                 self.new_resource.path)
+
+    def get_changed_resources(self):
+        return [self.resource, self.new_resource]
+
+
+class CreateResource(Change):
+    """A class to create a resource
+
+    Fields:
+
+    * `resource`: The resource to create
+    """
+
+    def __init__(self, resource):
+        self.resource = resource
+
+    @_handle_job_set
+    def do(self):
+        self._operations.create(self.resource)
+
+    @_handle_job_set
+    def undo(self):
+        self._operations.remove(self.resource)
+
+    def __str__(self):
+        return 'Create Resource <%s>' % (self.resource.path)
+
+    def get_description(self):
+        return 'new file %s' % (self.resource.path)
+
+    def get_changed_resources(self):
+        return [self.resource]
+
+    def _get_child_path(self, parent, name):
+        if parent.path == '':
+            return name
+        else:
+            return parent.path + '/' + name
+
+
+class CreateFolder(CreateResource):
+    """A class to create a folder
+
+    See docs for `CreateResource`.
+    """
+
+    def __init__(self, parent, name):
+        resource = parent.project.get_folder(
+            self._get_child_path(parent, name))
+        super(CreateFolder, self).__init__(resource)
+
+
+class CreateFile(CreateResource):
+    """A class to create a file
+
+    See docs for `CreateResource`.
+    """
+
+    def __init__(self, parent, name):
+        resource = parent.project.get_file(self._get_child_path(parent, name))
+        super(CreateFile, self).__init__(resource)
+
+
+class RemoveResource(Change):
+    """A class to remove a resource
+
+    Fields:
+
+    * `resource`: The resource to be removed
+    """
+
+    def __init__(self, resource):
+        self.resource = resource
+
+    @_handle_job_set
+    def do(self):
+        self._operations.remove(self.resource)
+
+    # TODO: Undoing remove operations
+    @_handle_job_set
+    def undo(self):
+        raise NotImplementedError(
+            'Undoing `RemoveResource` is not implemented yet.')
+
+    def __str__(self):
+        return 'Remove <%s>' % (self.resource.path)
+
+    def get_changed_resources(self):
+        return [self.resource]
+
+
+def count_changes(change):
+    """Counts the number of basic changes a `Change` will make"""
+    if isinstance(change, ChangeSet):
+        result = 0
+        for child in change.changes:
+            result += count_changes(child)
+        return result
+    return 1
+
+
+def create_job_set(task_handle, change):
+    return task_handle.create_jobset(str(change), count_changes(change))
+
+
+class _ResourceOperations(object):
+
+    def __init__(self, project):
+        self.project = project
+        self.fscommands = project.fscommands
+        self.direct_commands = rope.base.fscommands.FileSystemCommands()
+
+    def _get_fscommands(self, resource):
+        if self.project.is_ignored(resource):
+            return self.direct_commands
+        return self.fscommands
+
+    def write_file(self, resource, contents):
+        data = rope.base.fscommands.unicode_to_file_data(contents)
+        fscommands = self._get_fscommands(resource)
+        fscommands.write(resource.real_path, data)
+        for observer in list(self.project.observers):
+            observer.resource_changed(resource)
+
+    def move(self, resource, new_resource):
+        fscommands = self._get_fscommands(resource)
+        fscommands.move(resource.real_path, new_resource.real_path)
+        for observer in list(self.project.observers):
+            observer.resource_moved(resource, new_resource)
+
+    def create(self, resource):
+        if resource.is_folder():
+            self._create_resource(resource.path, kind='folder')
+        else:
+            self._create_resource(resource.path)
+        for observer in list(self.project.observers):
+            observer.resource_created(resource)
+
+    def remove(self, resource):
+        fscommands = self._get_fscommands(resource)
+        fscommands.remove(resource.real_path)
+        for observer in list(self.project.observers):
+            observer.resource_removed(resource)
+
+    def _create_resource(self, file_name, kind='file'):
+        resource_path = self.project._get_resource_path(file_name)
+        if os.path.exists(resource_path):
+            raise exceptions.RopeError('Resource <%s> already exists'
+                                       % resource_path)
+        resource = self.project.get_file(file_name)
+        if not resource.parent.exists():
+            raise exceptions.ResourceNotFoundError(
+                'Parent folder of <%s> does not exist' % resource.path)
+        fscommands = self._get_fscommands(resource)
+        try:
+            if kind == 'file':
+                fscommands.create_file(resource_path)
+            else:
+                fscommands.create_folder(resource_path)
+        except IOError as e:
+            raise exceptions.RopeError(e)
+
+
+def _get_destination_for_move(resource, destination):
+    dest_path = resource.project._get_resource_path(destination)
+    if os.path.isdir(dest_path):
+        if destination != '':
+            return destination + '/' + resource.name
+        else:
+            return resource.name
+    return destination
+
+
+class ChangeToData(object):
+
+    def convertChangeSet(self, change):
+        description = change.description
+        changes = []
+        for child in change.changes:
+            changes.append(self(child))
+        return (description, changes, change.time)
+
+    def convertChangeContents(self, change):
+        return (change.resource.path, change.new_contents, change.old_contents)
+
+    def convertMoveResource(self, change):
+        return (change.resource.path, change.new_resource.path)
+
+    def convertCreateResource(self, change):
+        return (change.resource.path, change.resource.is_folder())
+
+    def convertRemoveResource(self, change):
+        return (change.resource.path, change.resource.is_folder())
+
+    def __call__(self, change):
+        change_type = type(change)
+        if change_type in (CreateFolder, CreateFile):
+            change_type = CreateResource
+        method = getattr(self, 'convert' + change_type.__name__)
+        return (change_type.__name__, method(change))
+
+
+class DataToChange(object):
+
+    def __init__(self, project):
+        self.project = project
+
+    def makeChangeSet(self, description, changes, time=None):
+        result = ChangeSet(description, time)
+        for child in changes:
+            result.add_change(self(child))
+        return result
+
+    def makeChangeContents(self, path, new_contents, old_contents):
+        resource = self.project.get_file(path)
+        return ChangeContents(resource, new_contents, old_contents)
+
+    def makeMoveResource(self, old_path, new_path):
+        resource = self.project.get_file(old_path)
+        return MoveResource(resource, new_path, exact=True)
+
+    def makeCreateResource(self, path, is_folder):
+        if is_folder:
+            resource = self.project.get_folder(path)
+        else:
+            resource = self.project.get_file(path)
+        return CreateResource(resource)
+
+    def makeRemoveResource(self, path, is_folder):
+        if is_folder:
+            resource = self.project.get_folder(path)
+        else:
+            resource = self.project.get_file(path)
+        return RemoveResource(resource)
+
+    def __call__(self, data):
+        method = getattr(self, 'make' + data[0])
+        return method(*data[1])
diff --git a/venv/Lib/site-packages/rope/base/codeanalyze.py b/venv/Lib/site-packages/rope/base/codeanalyze.py
new file mode 100644
index 0000000000000000000000000000000000000000..1704e9ade971be894a459f54a441e6c397783481
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/codeanalyze.py
@@ -0,0 +1,362 @@
+import bisect
+import re
+import token
+import tokenize
+
+
+class ChangeCollector(object):
+
+    def __init__(self, text):
+        self.text = text
+        self.changes = []
+
+    def add_change(self, start, end, new_text=None):
+        if new_text is None:
+            new_text = self.text[start:end]
+        self.changes.append((start, end, new_text))
+
+    def get_changed(self):
+        if not self.changes:
+            return None
+
+        self.changes.sort(key=lambda x: x[:2])
+        pieces = []
+        last_changed = 0
+        for change in self.changes:
+            start, end, text = change
+            pieces.append(self.text[last_changed:start] + text)
+            last_changed = end
+        if last_changed < len(self.text):
+            pieces.append(self.text[last_changed:])
+        result = ''.join(pieces)
+        if result != self.text:
+            return result
+
+
+class SourceLinesAdapter(object):
+    """Adapts source to Lines interface
+
+    Note: The creation of this class is expensive.
+    """
+
+    def __init__(self, source_code):
+        self.code = source_code
+        self.starts = None
+        self._initialize_line_starts()
+
+    def _initialize_line_starts(self):
+        self.starts = []
+        self.starts.append(0)
+        try:
+            i = 0
+            while True:
+                i = self.code.index('\n', i) + 1
+                self.starts.append(i)
+        except ValueError:
+            pass
+        self.starts.append(len(self.code) + 1)
+
+    def get_line(self, lineno):
+        return self.code[self.starts[lineno - 1]:
+                         self.starts[lineno] - 1]
+
+    def length(self):
+        return len(self.starts) - 1
+
+    def get_line_number(self, offset):
+        return bisect.bisect(self.starts, offset)
+
+    def get_line_start(self, lineno):
+        return self.starts[lineno - 1]
+
+    def get_line_end(self, lineno):
+        return self.starts[lineno] - 1
+
+
+class ArrayLinesAdapter(object):
+
+    def __init__(self, lines):
+        self.lines = lines
+
+    def get_line(self, line_number):
+        return self.lines[line_number - 1]
+
+    def length(self):
+        return len(self.lines)
+
+
+class LinesToReadline(object):
+
+    def __init__(self, lines, start):
+        self.lines = lines
+        self.current = start
+
+    def readline(self):
+        if self.current <= self.lines.length():
+            self.current += 1
+            return self.lines.get_line(self.current - 1) + '\n'
+        return ''
+
+    def __call__(self):
+        return self.readline()
+
+
+class _CustomGenerator(object):
+
+    def __init__(self, lines):
+        self.lines = lines
+        self.in_string = ''
+        self.open_count = 0
+        self.continuation = False
+
+    def __call__(self):
+        size = self.lines.length()
+        result = []
+        i = 1
+        while i <= size:
+            while i <= size and not self.lines.get_line(i).strip():
+                i += 1
+            if i <= size:
+                start = i
+                while True:
+                    line = self.lines.get_line(i)
+                    self._analyze_line(line)
+                    if not (self.continuation or self.open_count or
+                            self.in_string) or i == size:
+                        break
+                    i += 1
+                result.append((start, i))
+                i += 1
+        return result
+
+    # Matches all backslashes before the token, to detect escaped quotes
+    _main_tokens = re.compile(r'(\\*)((\'\'\'|"""|\'|")|#|\[|\]|\{|\}|\(|\))')
+
+    def _analyze_line(self, line):
+        token = None
+        for match in self._main_tokens.finditer(line):
+            prefix = match.group(1)
+            token = match.group(2)
+            # Skip any tokens which are escaped
+            if len(prefix) % 2 == 1:
+                continue
+            if token in ["'''", '"""', "'", '"']:
+                if not self.in_string:
+                    self.in_string = token
+                elif self.in_string == token:
+                    self.in_string = ''
+            if self.in_string:
+                continue
+            if token == '#':
+                break
+            if token in '([{':
+                self.open_count += 1
+            elif token in ')]}':
+                self.open_count -= 1
+        if line and token != '#' and line.endswith('\\'):
+            self.continuation = True
+        else:
+            self.continuation = False
+
+
+def custom_generator(lines):
+    return _CustomGenerator(lines)()
+
+
+class LogicalLineFinder(object):
+
+    def __init__(self, lines):
+        self.lines = lines
+
+    def logical_line_in(self, line_number):
+        indents = count_line_indents(self.lines.get_line(line_number))
+        tries = 0
+        while True:
+            block_start = get_block_start(self.lines, line_number, indents)
+            try:
+                return self._block_logical_line(block_start, line_number)
+            except IndentationError as e:
+                tries += 1
+                if tries == 5:
+                    raise e
+                lineno = e.lineno + block_start - 1
+                indents = count_line_indents(self.lines.get_line(lineno))
+
+    def generate_starts(self, start_line=1, end_line=None):
+        for start, end in self.generate_regions(start_line, end_line):
+            yield start
+
+    def generate_regions(self, start_line=1, end_line=None):
+        # XXX: `block_start` should be at a better position!
+        block_start = 1
+        readline = LinesToReadline(self.lines, block_start)
+        try:
+            for start, end in self._logical_lines(readline):
+                real_start = start + block_start - 1
+                real_start = self._first_non_blank(real_start)
+                if end_line is not None and real_start >= end_line:
+                    break
+                real_end = end + block_start - 1
+                if real_start >= start_line:
+                    yield (real_start, real_end)
+        except tokenize.TokenError:
+            pass
+
+    def _block_logical_line(self, block_start, line_number):
+        readline = LinesToReadline(self.lines, block_start)
+        shifted = line_number - block_start + 1
+        region = self._calculate_logical(readline, shifted)
+        start = self._first_non_blank(region[0] + block_start - 1)
+        if region[1] is None:
+            end = self.lines.length()
+        else:
+            end = region[1] + block_start - 1
+        return start, end
+
+    def _calculate_logical(self, readline, line_number):
+        last_end = 1
+        try:
+            for start, end in self._logical_lines(readline):
+                if line_number <= end:
+                    return (start, end)
+                last_end = end + 1
+        except tokenize.TokenError as e:
+            current = e.args[1][0]
+            return (last_end, max(last_end, current - 1))
+        return (last_end, None)
+
+    def _logical_lines(self, readline):
+        last_end = 1
+        for current_token in tokenize.generate_tokens(readline):
+            current = current_token[2][0]
+            if current_token[0] == token.NEWLINE:
+                yield (last_end, current)
+                last_end = current + 1
+
+    def _first_non_blank(self, line_number):
+        current = line_number
+        while current < self.lines.length():
+            line = self.lines.get_line(current).strip()
+            if line and not line.startswith('#'):
+                return current
+            current += 1
+        return current
+
+
+def tokenizer_generator(lines):
+    return LogicalLineFinder(lines).generate_regions()
+
+
+class CachingLogicalLineFinder(object):
+
+    def __init__(self, lines, generate=custom_generator):
+        self.lines = lines
+        self._generate = generate
+
+    _starts = None
+
+    @property
+    def starts(self):
+        if self._starts is None:
+            self._init_logicals()
+        return self._starts
+
+    _ends = None
+
+    @property
+    def ends(self):
+        if self._ends is None:
+            self._init_logicals()
+        return self._ends
+
+    def _init_logicals(self):
+        """Should initialize _starts and _ends attributes"""
+        size = self.lines.length() + 1
+        self._starts = [None] * size
+        self._ends = [None] * size
+        for start, end in self._generate(self.lines):
+            self._starts[start] = True
+            self._ends[end] = True
+
+    def logical_line_in(self, line_number):
+        start = line_number
+        while start > 0 and not self.starts[start]:
+            start -= 1
+        if start == 0:
+            try:
+                start = self.starts.index(True, line_number)
+            except ValueError:
+                return (line_number, line_number)
+        return (start, self.ends.index(True, start))
+
+    def generate_starts(self, start_line=1, end_line=None):
+        if end_line is None:
+            end_line = self.lines.length()
+        for index in range(start_line, end_line):
+            if self.starts[index]:
+                yield index
+
+
+def get_block_start(lines, lineno, maximum_indents=80):
+    """Approximate block start"""
+    pattern = get_block_start_patterns()
+    for i in range(lineno, 0, -1):
+        match = pattern.search(lines.get_line(i))
+        if match is not None and \
+           count_line_indents(lines.get_line(i)) <= maximum_indents:
+            striped = match.string.lstrip()
+            # Maybe we're in a list comprehension or generator expression
+            if i > 1 and striped.startswith('if') or striped.startswith('for'):
+                bracs = 0
+                for j in range(i, min(i + 5, lines.length() + 1)):
+                    for c in lines.get_line(j):
+                        if c == '#':
+                            break
+                        if c in '[(':
+                            bracs += 1
+                        if c in ')]':
+                            bracs -= 1
+                            if bracs < 0:
+                                break
+                    if bracs < 0:
+                        break
+                if bracs < 0:
+                    continue
+            return i
+    return 1
+
+
+_block_start_pattern = None
+
+
+def get_block_start_patterns():
+    global _block_start_pattern
+    if not _block_start_pattern:
+        pattern = '^\\s*(((def|class|if|elif|except|for|while|with)\\s)|'\
+                  '((try|else|finally|except)\\s*:))'
+        _block_start_pattern = re.compile(pattern, re.M)
+    return _block_start_pattern
+
+
+def count_line_indents(line):
+    indents = 0
+    for char in line:
+        if char == ' ':
+            indents += 1
+        elif char == '\t':
+            indents += 8
+        else:
+            return indents
+    return 0
+
+
+def get_string_pattern():
+    start = r'(\b[uU]?[rR]?)?'
+    longstr = r'%s"""(\\.|"(?!"")|\\\n|[^"\\])*"""' % start
+    shortstr = r'%s"(\\.|\\\n|[^"\\])*"' % start
+    return '|'.join([longstr, longstr.replace('"', "'"),
+                     shortstr, shortstr.replace('"', "'")])
+
+
+def get_comment_pattern():
+    return r'#[^\n]*'
diff --git a/venv/Lib/site-packages/rope/base/default_config.py b/venv/Lib/site-packages/rope/base/default_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..dee2d1ae9a6be9cf0248130b6c6b9e2668052079
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/default_config.py
@@ -0,0 +1,114 @@
+# The default ``config.py``
+# flake8: noqa
+
+
+def set_prefs(prefs):
+    """This function is called before opening the project"""
+
+    # Specify which files and folders to ignore in the project.
+    # Changes to ignored resources are not added to the history and
+    # VCSs.  Also they are not returned in `Project.get_files()`.
+    # Note that ``?`` and ``*`` match all characters but slashes.
+    # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
+    # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
+    # '.svn': matches 'pkg/.svn' and all of its children
+    # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
+    # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
+    prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
+                                  '.hg', '.svn', '_svn', '.git', '.tox']
+
+    # Specifies which files should be considered python files.  It is
+    # useful when you have scripts inside your project.  Only files
+    # ending with ``.py`` are considered to be python files by
+    # default.
+    # prefs['python_files'] = ['*.py']
+
+    # Custom source folders:  By default rope searches the project
+    # for finding source folders (folders that should be searched
+    # for finding modules).  You can add paths to that list.  Note
+    # that rope guesses project source folders correctly most of the
+    # time; use this if you have any problems.
+    # The folders should be relative to project root and use '/' for
+    # separating folders regardless of the platform rope is running on.
+    # 'src/my_source_folder' for instance.
+    # prefs.add('source_folders', 'src')
+
+    # You can extend python path for looking up modules
+    # prefs.add('python_path', '~/python/')
+
+    # Should rope save object information or not.
+    prefs['save_objectdb'] = True
+    prefs['compress_objectdb'] = False
+
+    # If `True`, rope analyzes each module when it is being saved.
+    prefs['automatic_soa'] = True
+    # The depth of calls to follow in static object analysis
+    prefs['soa_followed_calls'] = 0
+
+    # If `False` when running modules or unit tests "dynamic object
+    # analysis" is turned off.  This makes them much faster.
+    prefs['perform_doa'] = True
+
+    # Rope can check the validity of its object DB when running.
+    prefs['validate_objectdb'] = True
+
+    # How many undos to hold?
+    prefs['max_history_items'] = 32
+
+    # Shows whether to save history across sessions.
+    prefs['save_history'] = True
+    prefs['compress_history'] = False
+
+    # Set the number spaces used for indenting.  According to
+    # :PEP:`8`, it is best to use 4 spaces.  Since most of rope's
+    # unit-tests use 4 spaces it is more reliable, too.
+    prefs['indent_size'] = 4
+
+    # Builtin and c-extension modules that are allowed to be imported
+    # and inspected by rope.
+    prefs['extension_modules'] = []
+
+    # Add all standard c-extensions to extension_modules list.
+    prefs['import_dynload_stdmods'] = True
+
+    # If `True` modules with syntax errors are considered to be empty.
+    # The default value is `False`; When `False` syntax errors raise
+    # `rope.base.exceptions.ModuleSyntaxError` exception.
+    prefs['ignore_syntax_errors'] = False
+
+    # If `True`, rope ignores unresolvable imports.  Otherwise, they
+    # appear in the importing namespace.
+    prefs['ignore_bad_imports'] = False
+
+    # If `True`, rope will insert new module imports as
+    # `from <package> import <module>` by default.
+    prefs['prefer_module_from_imports'] = False
+
+    # If `True`, rope will transform a comma list of imports into
+    # multiple separate import statements when organizing
+    # imports.
+    prefs['split_imports'] = False
+
+    # If `True`, rope will remove all top-level import statements and
+    # reinsert them at the top of the module when making changes.
+    prefs['pull_imports_to_top'] = True
+
+    # If `True`, rope will sort imports alphabetically by module name instead
+    # of alphabetically by import statement, with from imports after normal
+    # imports.
+    prefs['sort_imports_alphabetically'] = False
+
+    # Location of implementation of
+    # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general
+    # case, you don't have to change this value, unless you're an rope expert.
+    # Change this value to inject you own implementations of interfaces
+    # listed in module rope.base.oi.type_hinting.providers.interfaces
+    # For example, you can add you own providers for Django Models, or disable
+    # the search type-hinting in a class hierarchy, etc.
+    prefs['type_hinting_factory'] = (
+        'rope.base.oi.type_hinting.factory.default_type_hinting_factory')
+
+
+def project_opened(project):
+    """This function is called after opening the project"""
+    # Do whatever you like here!
diff --git a/venv/Lib/site-packages/rope/base/evaluate.py b/venv/Lib/site-packages/rope/base/evaluate.py
new file mode 100644
index 0000000000000000000000000000000000000000..ce38bd025b52fd0890355a0836e577198fa09698
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/evaluate.py
@@ -0,0 +1,333 @@
+import rope.base.builtins
+import rope.base.pynames
+import rope.base.pyobjects
+from rope.base import ast, astutils, exceptions, pyobjects, arguments, worder
+from rope.base.utils import pycompat
+
+
+BadIdentifierError = exceptions.BadIdentifierError
+
+
+def eval_location(pymodule, offset):
+    """Find the pyname at the offset"""
+    return eval_location2(pymodule, offset)[1]
+
+
+def eval_location2(pymodule, offset):
+    """Find the primary and pyname at offset"""
+    pyname_finder = ScopeNameFinder(pymodule)
+    return pyname_finder.get_primary_and_pyname_at(offset)
+
+
+def eval_node(scope, node):
+    """Evaluate a `ast.AST` node and return a PyName
+
+    Return `None` if the expression cannot be evaluated.
+    """
+    return eval_node2(scope, node)[1]
+
+
+def eval_node2(scope, node):
+    evaluator = StatementEvaluator(scope)
+    ast.walk(node, evaluator)
+    return evaluator.old_result, evaluator.result
+
+
+def eval_str(holding_scope, name):
+    return eval_str2(holding_scope, name)[1]
+
+
+def eval_str2(holding_scope, name):
+    try:
+        # parenthesizing for handling cases like 'a_var.\nattr'
+        node = ast.parse('(%s)' % name)
+    except SyntaxError:
+        raise BadIdentifierError(
+            'Not a resolvable python identifier selected.')
+    return eval_node2(holding_scope, node)
+
+
+class ScopeNameFinder(object):
+
+    def __init__(self, pymodule):
+        self.module_scope = pymodule.get_scope()
+        self.lines = pymodule.lines
+        self.worder = worder.Worder(pymodule.source_code, True)
+
+    def _is_defined_in_class_body(self, holding_scope, offset, lineno):
+        if lineno == holding_scope.get_start() and \
+           holding_scope.parent is not None and \
+           holding_scope.parent.get_kind() == 'Class' and \
+           self.worder.is_a_class_or_function_name_in_header(offset):
+            return True
+        if lineno != holding_scope.get_start() and \
+           holding_scope.get_kind() == 'Class' and \
+           self.worder.is_name_assigned_in_class_body(offset):
+            return True
+        return False
+
+    def _is_function_name_in_function_header(self, scope, offset, lineno):
+        if scope.get_start() <= lineno <= scope.get_body_start() and \
+           scope.get_kind() == 'Function' and \
+           self.worder.is_a_class_or_function_name_in_header(offset):
+            return True
+        return False
+
+    def get_pyname_at(self, offset):
+        return self.get_primary_and_pyname_at(offset)[1]
+
+    def get_primary_and_pyname_at(self, offset):
+        lineno = self.lines.get_line_number(offset)
+        holding_scope = self.module_scope.get_inner_scope_for_line(lineno)
+        # function keyword parameter
+        if self.worder.is_function_keyword_parameter(offset):
+            keyword_name = self.worder.get_word_at(offset)
+            pyobject = self.get_enclosing_function(offset)
+            if isinstance(pyobject, pyobjects.PyFunction):
+                return (None,
+                        pyobject.get_parameters().get(keyword_name, None))
+        # class body
+        if self._is_defined_in_class_body(holding_scope, offset, lineno):
+            class_scope = holding_scope
+            if lineno == holding_scope.get_start():
+                class_scope = holding_scope.parent
+            name = self.worder.get_primary_at(offset).strip()
+            try:
+                return (None, class_scope.pyobject[name])
+            except rope.base.exceptions.AttributeNotFoundError:
+                return (None, None)
+        # function header
+        if self._is_function_name_in_function_header(holding_scope,
+                                                     offset, lineno):
+            name = self.worder.get_primary_at(offset).strip()
+            return (None, holding_scope.parent[name])
+        # module in a from statement or an imported name that is aliased
+        if (self.worder.is_from_statement_module(offset) or
+            self.worder.is_import_statement_aliased_module(offset)):
+            module = self.worder.get_primary_at(offset)
+            module_pyname = self._find_module(module)
+            return (None, module_pyname)
+        if self.worder.is_from_aliased(offset):
+            name = self.worder.get_from_aliased(offset)
+        else:
+            name = self.worder.get_primary_at(offset)
+        return eval_str2(holding_scope, name)
+
+    def get_enclosing_function(self, offset):
+        function_parens = self.worder.find_parens_start_from_inside(offset)
+        try:
+            function_pyname = self.get_pyname_at(function_parens - 1)
+        except BadIdentifierError:
+            function_pyname = None
+        if function_pyname is not None:
+            pyobject = function_pyname.get_object()
+            if isinstance(pyobject, pyobjects.AbstractFunction):
+                return pyobject
+            elif isinstance(pyobject, pyobjects.AbstractClass) and \
+                    '__init__' in pyobject:
+                return pyobject['__init__'].get_object()
+            elif '__call__' in pyobject:
+                return pyobject['__call__'].get_object()
+        return None
+
+    def _find_module(self, module_name):
+        dots = 0
+        while module_name[dots] == '.':
+            dots += 1
+        return rope.base.pynames.ImportedModule(
+            self.module_scope.pyobject, module_name[dots:], dots)
+
+
+class StatementEvaluator(object):
+
+    def __init__(self, scope):
+        self.scope = scope
+        self.result = None
+        self.old_result = None
+
+    def _Name(self, node):
+        self.result = self.scope.lookup(node.id)
+
+    def _Attribute(self, node):
+        pyname = eval_node(self.scope, node.value)
+        if pyname is None:
+            pyname = rope.base.pynames.UnboundName()
+        self.old_result = pyname
+        if pyname.get_object() != rope.base.pyobjects.get_unknown():
+            try:
+                self.result = pyname.get_object()[node.attr]
+            except exceptions.AttributeNotFoundError:
+                self.result = None
+
+    def _Call(self, node):
+        primary, pyobject = self._get_primary_and_object_for_node(node.func)
+        if pyobject is None:
+            return
+
+        def _get_returned(pyobject):
+            args = arguments.create_arguments(primary, pyobject,
+                                              node, self.scope)
+            return pyobject.get_returned_object(args)
+        if isinstance(pyobject, rope.base.pyobjects.AbstractClass):
+            result = None
+            if '__new__' in pyobject:
+                new_function = pyobject['__new__'].get_object()
+                result = _get_returned(new_function)
+            if result is None or \
+               result == rope.base.pyobjects.get_unknown():
+                result = rope.base.pyobjects.PyObject(pyobject)
+            self.result = rope.base.pynames.UnboundName(pyobject=result)
+            return
+
+        pyfunction = None
+        if isinstance(pyobject, rope.base.pyobjects.AbstractFunction):
+            pyfunction = pyobject
+        elif '__call__' in pyobject:
+            pyfunction = pyobject['__call__'].get_object()
+        if pyfunction is not None:
+            self.result = rope.base.pynames.UnboundName(
+                pyobject=_get_returned(pyfunction))
+
+    def _Str(self, node):
+        self.result = rope.base.pynames.UnboundName(
+            pyobject=rope.base.builtins.get_str())
+
+    def _Num(self, node):
+        type_name = type(node.n).__name__
+        self.result = self._get_builtin_name(type_name)
+
+    def _get_builtin_name(self, type_name):
+        pytype = rope.base.builtins.builtins[type_name].get_object()
+        return rope.base.pynames.UnboundName(
+            rope.base.pyobjects.PyObject(pytype))
+
+    def _BinOp(self, node):
+        self.result = rope.base.pynames.UnboundName(
+            self._get_object_for_node(node.left))
+
+    def _BoolOp(self, node):
+        pyobject = self._get_object_for_node(node.values[0])
+        if pyobject is None:
+            pyobject = self._get_object_for_node(node.values[1])
+        self.result = rope.base.pynames.UnboundName(pyobject)
+
+    def _Repr(self, node):
+        self.result = self._get_builtin_name('str')
+
+    def _UnaryOp(self, node):
+        self.result = rope.base.pynames.UnboundName(
+            self._get_object_for_node(node.operand))
+
+    def _Compare(self, node):
+        self.result = self._get_builtin_name('bool')
+
+    def _Dict(self, node):
+        keys = None
+        values = None
+        if node.keys:
+            keys = self._get_object_for_node(node.keys[0])
+            values = self._get_object_for_node(node.values[0])
+        self.result = rope.base.pynames.UnboundName(
+            pyobject=rope.base.builtins.get_dict(keys, values))
+
+    def _List(self, node):
+        holding = None
+        if node.elts:
+            holding = self._get_object_for_node(node.elts[0])
+        self.result = rope.base.pynames.UnboundName(
+            pyobject=rope.base.builtins.get_list(holding))
+
+    def _ListComp(self, node):
+        pyobject = self._what_does_comprehension_hold(node)
+        self.result = rope.base.pynames.UnboundName(
+            pyobject=rope.base.builtins.get_list(pyobject))
+
+    def _GeneratorExp(self, node):
+        pyobject = self._what_does_comprehension_hold(node)
+        self.result = rope.base.pynames.UnboundName(
+            pyobject=rope.base.builtins.get_iterator(pyobject))
+
+    def _what_does_comprehension_hold(self, node):
+        scope = self._make_comprehension_scope(node)
+        pyname = eval_node(scope, node.elt)
+        return pyname.get_object() if pyname is not None else None
+
+    def _make_comprehension_scope(self, node):
+        scope = self.scope
+        module = scope.pyobject.get_module()
+        names = {}
+        for comp in node.generators:
+            new_names = _get_evaluated_names(comp.target, comp.iter, module,
+                                             '.__iter__().next()', node.lineno)
+            names.update(new_names)
+        return rope.base.pyscopes.TemporaryScope(scope.pycore, scope, names)
+
+    def _Tuple(self, node):
+        objects = []
+        if len(node.elts) < 4:
+            for stmt in node.elts:
+                pyobject = self._get_object_for_node(stmt)
+                objects.append(pyobject)
+        else:
+            objects.append(self._get_object_for_node(node.elts[0]))
+        self.result = rope.base.pynames.UnboundName(
+            pyobject=rope.base.builtins.get_tuple(*objects))
+
+    def _get_object_for_node(self, stmt):
+        pyname = eval_node(self.scope, stmt)
+        pyobject = None
+        if pyname is not None:
+            pyobject = pyname.get_object()
+        return pyobject
+
+    def _get_primary_and_object_for_node(self, stmt):
+        primary, pyname = eval_node2(self.scope, stmt)
+        pyobject = None
+        if pyname is not None:
+            pyobject = pyname.get_object()
+        return primary, pyobject
+
+    def _Subscript(self, node):
+        if isinstance(node.slice, ast.Index):
+            self._call_function(node.value, '__getitem__',
+                                [node.slice.value])
+        elif isinstance(node.slice, ast.Slice):
+            self._call_function(node.value, '__getitem__',
+                                [node.slice])
+
+    def _Slice(self, node):
+        self.result = self._get_builtin_name('slice')
+
+    def _call_function(self, node, function_name, other_args=None):
+        pyname = eval_node(self.scope, node)
+        if pyname is not None:
+            pyobject = pyname.get_object()
+        else:
+            return
+        if function_name in pyobject:
+            called = pyobject[function_name].get_object()
+            if not called or \
+                    not isinstance(called, pyobjects.AbstractFunction):
+                return
+            args = [node]
+            if other_args:
+                args += other_args
+            arguments_ = arguments.Arguments(args, self.scope)
+            self.result = rope.base.pynames.UnboundName(
+                pyobject=called.get_returned_object(arguments_))
+
+    def _Lambda(self, node):
+        self.result = rope.base.pynames.UnboundName(
+            pyobject=rope.base.builtins.Lambda(node, self.scope))
+
+
+def _get_evaluated_names(targets, assigned, module, evaluation, lineno):
+    result = {}
+    for name, levels in astutils.get_name_levels(targets):
+        assignment = rope.base.pynames.AssignmentValue(assigned, levels,
+                                                       evaluation)
+        # XXX: this module should not access `rope.base.pynamesdef`!
+        pyname = rope.base.pynamesdef.AssignedName(lineno, module)
+        pyname.assignments.append(assignment)
+        result[name] = pyname
+    return result
diff --git a/venv/Lib/site-packages/rope/base/exceptions.py b/venv/Lib/site-packages/rope/base/exceptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..d161c89ed688cd463434c6882566f12299853cf4
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/exceptions.py
@@ -0,0 +1,61 @@
+class RopeError(Exception):
+    """Base exception for rope"""
+
+
+class ResourceNotFoundError(RopeError):
+    """Resource not found exception"""
+
+
+class RefactoringError(RopeError):
+    """Errors for performing a refactoring"""
+
+
+class InterruptedTaskError(RopeError):
+    """The task has been interrupted"""
+
+
+class HistoryError(RopeError):
+    """Errors for history undo/redo operations"""
+
+
+class ModuleNotFoundError(RopeError):
+    """Module not found exception"""
+
+
+class AttributeNotFoundError(RopeError):
+    """Attribute not found exception"""
+
+
+class NameNotFoundError(RopeError):
+    """Name not found exception"""
+
+
+class BadIdentifierError(RopeError):
+    """The name cannot be resolved"""
+
+
+class ModuleSyntaxError(RopeError):
+    """Module has syntax errors
+
+    The `filename` and `lineno` fields indicate where the error has
+    occurred.
+
+    """
+
+    def __init__(self, filename, lineno, message):
+        self.filename = filename
+        self.lineno = lineno
+        self.message_ = message
+        super(ModuleSyntaxError, self).__init__(
+            'Syntax error in file <%s> line <%s>: %s' %
+            (filename, lineno, message))
+
+
+class ModuleDecodeError(RopeError):
+    """Cannot decode module"""
+
+    def __init__(self, filename, message):
+        self.filename = filename
+        self.message_ = message
+        super(ModuleDecodeError, self).__init__(
+            'Cannot decode file <%s>: %s' % (filename, message))
diff --git a/venv/Lib/site-packages/rope/base/fscommands.py b/venv/Lib/site-packages/rope/base/fscommands.py
new file mode 100644
index 0000000000000000000000000000000000000000..3564ed919c9cfb40b50806b43940c8f8240d4135
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/fscommands.py
@@ -0,0 +1,288 @@
+"""Project file system commands.
+
+This modules implements file system operations used by rope.  Different
+version control systems can be supported by implementing the interface
+provided by `FileSystemCommands` class.  See `SubversionCommands` and
+`MercurialCommands` for example.
+
+"""
+import os
+import shutil
+import subprocess
+
+import rope.base.utils.pycompat as pycompat
+
+try:
+    unicode
+except NameError:
+    unicode = str
+
+def create_fscommands(root):
+    dirlist = os.listdir(root)
+    commands = {'.hg': MercurialCommands,
+                '.svn': SubversionCommands,
+                '.git': GITCommands,
+                '_svn': SubversionCommands,
+                '_darcs': DarcsCommands}
+    for key in commands:
+        if key in dirlist:
+            try:
+                return commands[key](root)
+            except (ImportError, OSError):
+                pass
+    return FileSystemCommands()
+
+
+class FileSystemCommands(object):
+
+    def create_file(self, path):
+        open(path, 'w').close()
+
+    def create_folder(self, path):
+        os.mkdir(path)
+
+    def move(self, path, new_location):
+        shutil.move(path, new_location)
+
+    def remove(self, path):
+        if os.path.isfile(path):
+            os.remove(path)
+        else:
+            shutil.rmtree(path)
+
+    def write(self, path, data):
+        file_ = open(path, 'wb')
+        try:
+            file_.write(data)
+        finally:
+            file_.close()
+
+
+class SubversionCommands(object):
+
+    def __init__(self, *args):
+        self.normal_actions = FileSystemCommands()
+        import pysvn
+        self.client = pysvn.Client()
+
+    def create_file(self, path):
+        self.normal_actions.create_file(path)
+        self.client.add(path, force=True)
+
+    def create_folder(self, path):
+        self.normal_actions.create_folder(path)
+        self.client.add(path, force=True)
+
+    def move(self, path, new_location):
+        self.client.move(path, new_location, force=True)
+
+    def remove(self, path):
+        self.client.remove(path, force=True)
+
+    def write(self, path, data):
+        self.normal_actions.write(path, data)
+
+
+class MercurialCommands(object):
+
+    def __init__(self, root):
+        self.hg = self._import_mercurial()
+        self.normal_actions = FileSystemCommands()
+        try:
+            self.ui = self.hg.ui.ui(
+                verbose=False, debug=False, quiet=True,
+                interactive=False, traceback=False, report_untrusted=False)
+        except:
+            self.ui = self.hg.ui.ui()
+            self.ui.setconfig('ui', 'interactive', 'no')
+            self.ui.setconfig('ui', 'debug', 'no')
+            self.ui.setconfig('ui', 'traceback', 'no')
+            self.ui.setconfig('ui', 'verbose', 'no')
+            self.ui.setconfig('ui', 'report_untrusted', 'no')
+            self.ui.setconfig('ui', 'quiet', 'yes')
+
+        self.repo = self.hg.hg.repository(self.ui, root)
+
+    def _import_mercurial(self):
+        import mercurial.commands
+        import mercurial.hg
+        import mercurial.ui
+        return mercurial
+
+    def create_file(self, path):
+        self.normal_actions.create_file(path)
+        self.hg.commands.add(self.ui, self.repo, path)
+
+    def create_folder(self, path):
+        self.normal_actions.create_folder(path)
+
+    def move(self, path, new_location):
+        self.hg.commands.rename(self.ui, self.repo, path,
+                                new_location, after=False)
+
+    def remove(self, path):
+        self.hg.commands.remove(self.ui, self.repo, path)
+
+    def write(self, path, data):
+        self.normal_actions.write(path, data)
+
+
+class GITCommands(object):
+
+    def __init__(self, root):
+        self.root = root
+        self._do(['version'])
+        self.normal_actions = FileSystemCommands()
+
+    def create_file(self, path):
+        self.normal_actions.create_file(path)
+        self._do(['add', self._in_dir(path)])
+
+    def create_folder(self, path):
+        self.normal_actions.create_folder(path)
+
+    def move(self, path, new_location):
+        self._do(['mv', self._in_dir(path), self._in_dir(new_location)])
+
+    def remove(self, path):
+        self._do(['rm', self._in_dir(path)])
+
+    def write(self, path, data):
+        # XXX: should we use ``git add``?
+        self.normal_actions.write(path, data)
+
+    def _do(self, args):
+        _execute(['git'] + args, cwd=self.root)
+
+    def _in_dir(self, path):
+        if path.startswith(self.root):
+            return path[len(self.root) + 1:]
+        return self.root
+
+
+class DarcsCommands(object):
+
+    def __init__(self, root):
+        self.root = root
+        self.normal_actions = FileSystemCommands()
+
+    def create_file(self, path):
+        self.normal_actions.create_file(path)
+        self._do(['add', path])
+
+    def create_folder(self, path):
+        self.normal_actions.create_folder(path)
+        self._do(['add', path])
+
+    def move(self, path, new_location):
+        self._do(['mv', path, new_location])
+
+    def remove(self, path):
+        self.normal_actions.remove(path)
+
+    def write(self, path, data):
+        self.normal_actions.write(path, data)
+
+    def _do(self, args):
+        _execute(['darcs'] + args, cwd=self.root)
+
+
+def _execute(args, cwd=None):
+    process = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE)
+    process.wait()
+    return process.returncode
+
+
+def unicode_to_file_data(contents, encoding=None):
+    if not isinstance(contents, unicode):
+        return contents
+    if encoding is None:
+        encoding = read_str_coding(contents)
+    if encoding is not None:
+        return contents.encode(encoding)
+    try:
+        return contents.encode()
+    except UnicodeEncodeError:
+        return contents.encode('utf-8')
+
+
+def file_data_to_unicode(data, encoding=None):
+    result = _decode_data(data, encoding)
+    if '\r' in result:
+        result = result.replace('\r\n', '\n').replace('\r', '\n')
+    return result
+
+
+def _decode_data(data, encoding):
+    if isinstance(data, unicode):
+        return data
+    if encoding is None:
+        encoding = read_str_coding(data)
+    if encoding is None:
+        # there is no encoding tip, we need to guess.
+        # PEP263 says that "encoding not explicitly defined" means it is ascii,
+        # but we will use utf8 instead since utf8 fully covers ascii and btw is
+        # the only non-latin sane encoding.
+        encoding = 'utf-8'
+    try:
+        return data.decode(encoding)
+    except (UnicodeError, LookupError):
+        # fallback to latin1: it should never fail
+        return data.decode('latin1')
+
+
+def read_file_coding(path):
+    file = open(path, 'b')
+    count = 0
+    result = []
+    while True:
+        current = file.read(10)
+        if not current:
+            break
+        count += current.count('\n')
+        result.append(current)
+    file.close()
+    return _find_coding(''.join(result))
+
+
+def read_str_coding(source):
+    if type(source) == bytes:
+        newline = b'\n'
+    else:
+        newline = '\n'
+    #try:
+    #    source = source.decode("utf-8")
+    #except AttributeError:
+    #    pass
+    try:
+        first = source.index(newline) + 1
+        second = source.index(newline, first) + 1
+    except ValueError:
+        second = len(source)
+    return _find_coding(source[:second])
+
+
+def _find_coding(text):
+    if isinstance(text, pycompat.str):
+        text = text.encode('utf-8')
+    coding = b'coding'
+    to_chr = chr if pycompat.PY3 else lambda x: x
+    try:
+        start = text.index(coding) + len(coding)
+        if text[start] not in b'=:':
+            return
+        start += 1
+        while start < len(text) and to_chr(text[start]).isspace():
+            start += 1
+        end = start
+        while end < len(text):
+            c = text[end]
+            if not to_chr(c).isalnum() and c not in b'-_':
+                break
+            end += 1
+        result = text[start:end]
+        if isinstance(result, bytes):
+            result = result.decode('utf-8')
+        return result
+    except ValueError:
+        pass
diff --git a/venv/Lib/site-packages/rope/base/history.py b/venv/Lib/site-packages/rope/base/history.py
new file mode 100644
index 0000000000000000000000000000000000000000..d3c523d310c41b42740253818ce4f94f04e6b988
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/history.py
@@ -0,0 +1,235 @@
+from rope.base import exceptions, change, taskhandle
+
+
+class History(object):
+    """A class that holds project history"""
+
+    def __init__(self, project, maxundos=None):
+        self.project = project
+        self._undo_list = []
+        self._redo_list = []
+        self._maxundos = maxundos
+        self._load_history()
+        self.project.data_files.add_write_hook(self.write)
+        self.current_change = None
+
+    def _load_history(self):
+        if self.save:
+            result = self.project.data_files.read_data(
+                'history', compress=self.compress, import_=True)
+            if result is not None:
+                to_change = change.DataToChange(self.project)
+                for data in result[0]:
+                    self._undo_list.append(to_change(data))
+                for data in result[1]:
+                    self._redo_list.append(to_change(data))
+
+    def do(self, changes, task_handle=taskhandle.NullTaskHandle()):
+        """Perform the change and add it to the `self.undo_list`
+
+        Note that uninteresting changes (changes to ignored files)
+        will not be appended to `self.undo_list`.
+
+        """
+        try:
+            self.current_change = changes
+            changes.do(change.create_job_set(task_handle, changes))
+        finally:
+            self.current_change = None
+        if self._is_change_interesting(changes):
+            self.undo_list.append(changes)
+            self._remove_extra_items()
+        del self.redo_list[:]
+
+    def _remove_extra_items(self):
+        if len(self.undo_list) > self.max_undos:
+            del self.undo_list[0:len(self.undo_list) - self.max_undos]
+
+    def _is_change_interesting(self, changes):
+        for resource in changes.get_changed_resources():
+            if not self.project.is_ignored(resource):
+                return True
+        return False
+
+    def undo(self, change=None, drop=False,
+             task_handle=taskhandle.NullTaskHandle()):
+        """Redo done changes from the history
+
+        When `change` is `None`, the last done change will be undone.
+        If change is not `None` it should be an item from
+        `self.undo_list`; this change and all changes that depend on
+        it will be undone.  In both cases the list of undone changes
+        will be returned.
+
+        If `drop` is `True`, the undone change will not be appended to
+        the redo list.
+
+        """
+        if not self._undo_list:
+            raise exceptions.HistoryError('Undo list is empty')
+        if change is None:
+            change = self.undo_list[-1]
+        dependencies = self._find_dependencies(self.undo_list, change)
+        self._move_front(self.undo_list, dependencies)
+        self._perform_undos(len(dependencies), task_handle)
+        result = self.redo_list[-len(dependencies):]
+        if drop:
+            del self.redo_list[-len(dependencies):]
+        return result
+
+    def redo(self, change=None, task_handle=taskhandle.NullTaskHandle()):
+        """Redo undone changes from the history
+
+        When `change` is `None`, the last undone change will be
+        redone.  If change is not `None` it should be an item from
+        `self.redo_list`; this change and all changes that depend on
+        it will be redone.  In both cases the list of redone changes
+        will be returned.
+
+        """
+        if not self.redo_list:
+            raise exceptions.HistoryError('Redo list is empty')
+        if change is None:
+            change = self.redo_list[-1]
+        dependencies = self._find_dependencies(self.redo_list, change)
+        self._move_front(self.redo_list, dependencies)
+        self._perform_redos(len(dependencies), task_handle)
+        return self.undo_list[-len(dependencies):]
+
+    def _move_front(self, change_list, changes):
+        for change in changes:
+            change_list.remove(change)
+            change_list.append(change)
+
+    def _find_dependencies(self, change_list, change):
+        index = change_list.index(change)
+        return _FindChangeDependencies(change_list[index:])()
+
+    def _perform_undos(self, count, task_handle):
+        for i in range(count):
+            self.current_change = self.undo_list[-1]
+            try:
+                job_set = change.create_job_set(task_handle,
+                                                self.current_change)
+                self.current_change.undo(job_set)
+            finally:
+                self.current_change = None
+            self.redo_list.append(self.undo_list.pop())
+
+    def _perform_redos(self, count, task_handle):
+        for i in range(count):
+            self.current_change = self.redo_list[-1]
+            try:
+                job_set = change.create_job_set(task_handle,
+                                                self.current_change)
+                self.current_change.do(job_set)
+            finally:
+                self.current_change = None
+            self.undo_list.append(self.redo_list.pop())
+
+    def contents_before_current_change(self, file):
+        if self.current_change is None:
+            return None
+        result = self._search_for_change_contents([self.current_change], file)
+        if result is not None:
+            return result
+        if file.exists() and not file.is_folder():
+            return file.read()
+        else:
+            return None
+
+    def _search_for_change_contents(self, change_list, file):
+        for change_ in reversed(change_list):
+            if isinstance(change_, change.ChangeSet):
+                result = self._search_for_change_contents(change_.changes,
+                                                          file)
+                if result is not None:
+                    return result
+            if isinstance(change_, change.ChangeContents) and \
+               change_.resource == file:
+                return change_.old_contents
+
+    def write(self):
+        if self.save:
+            data = []
+            to_data = change.ChangeToData()
+            self._remove_extra_items()
+            data.append([to_data(change_) for change_ in self.undo_list])
+            data.append([to_data(change_) for change_ in self.redo_list])
+            self.project.data_files.write_data('history', data,
+                                               compress=self.compress)
+
+    def get_file_undo_list(self, resource):
+        result = []
+        for change in self.undo_list:
+            if resource in change.get_changed_resources():
+                result.append(change)
+        return result
+
+    def __str__(self):
+        return 'History holds %s changes in memory' % \
+               (len(self.undo_list) + len(self.redo_list))
+
+    undo_list = property(lambda self: self._undo_list)
+    redo_list = property(lambda self: self._redo_list)
+
+    @property
+    def tobe_undone(self):
+        """The last done change if available, `None` otherwise"""
+        if self.undo_list:
+            return self.undo_list[-1]
+
+    @property
+    def tobe_redone(self):
+        """The last undone change if available, `None` otherwise"""
+        if self.redo_list:
+            return self.redo_list[-1]
+
+    @property
+    def max_undos(self):
+        if self._maxundos is None:
+            return self.project.prefs.get('max_history_items', 100)
+        else:
+            return self._maxundos
+
+    @property
+    def save(self):
+        return self.project.prefs.get('save_history', False)
+
+    @property
+    def compress(self):
+        return self.project.prefs.get('compress_history', False)
+
+    def clear(self):
+        """Forget all undo and redo information"""
+        del self.undo_list[:]
+        del self.redo_list[:]
+
+
+class _FindChangeDependencies(object):
+
+    def __init__(self, change_list):
+        self.change = change_list[0]
+        self.change_list = change_list
+        self.changed_resources = set(self.change.get_changed_resources())
+
+    def __call__(self):
+        result = [self.change]
+        for change in self.change_list[1:]:
+            if self._depends_on(change, result):
+                result.append(change)
+                self.changed_resources.update(change.get_changed_resources())
+        return result
+
+    def _depends_on(self, changes, result):
+        for resource in changes.get_changed_resources():
+            if resource is None:
+                continue
+            if resource in self.changed_resources:
+                return True
+            for changed in self.changed_resources:
+                if resource.is_folder() and resource.contains(changed):
+                    return True
+                if changed.is_folder() and changed.contains(resource):
+                    return True
+        return False
diff --git a/venv/Lib/site-packages/rope/base/libutils.py b/venv/Lib/site-packages/rope/base/libutils.py
new file mode 100644
index 0000000000000000000000000000000000000000..4037f183f576c23876daf62eba8c9a4644c625f2
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/libutils.py
@@ -0,0 +1,122 @@
+"""A few useful functions for using rope as a library"""
+import os.path
+
+import rope.base.project
+import rope.base.pycore
+from rope.base import pyobjectsdef
+from rope.base import utils
+from rope.base import taskhandle
+
+
+def path_to_resource(project, path, type=None):
+    """Get the resource at path
+
+    You only need to specify `type` if `path` does not exist.  It can
+    be either 'file' or 'folder'.  If the type is `None` it is assumed
+    that the resource already exists.
+
+    Note that this function uses `Project.get_resource()`,
+    `Project.get_file()`, and `Project.get_folder()` methods.
+
+    """
+    project_path = path_relative_to_project_root(project, path)
+    if project_path is None:
+        project_path = rope.base.project._realpath(path)
+        project = rope.base.project.get_no_project()
+    if type is None:
+        return project.get_resource(project_path)
+    if type == 'file':
+        return project.get_file(project_path)
+    if type == 'folder':
+        return project.get_folder(project_path)
+    return None
+
+
+def path_relative_to_project_root(project, path):
+    return relative(project.address, path)
+
+@utils.deprecated()
+def relative(root, path):
+    root = rope.base.project._realpath(root).replace(os.path.sep, '/')
+    path = rope.base.project._realpath(path).replace(os.path.sep, '/')
+    if path == root:
+        return ''
+    if path.startswith(root + '/'):
+        return path[len(root) + 1:]
+
+
+def report_change(project, path, old_content):
+    """Report that the contents of file at `path` was changed
+
+    The new contents of file is retrieved by reading the file.
+
+    """
+    resource = path_to_resource(project, path)
+    if resource is None:
+        return
+    for observer in list(project.observers):
+        observer.resource_changed(resource)
+    if project.pycore.automatic_soa:
+        rope.base.pycore.perform_soa_on_changed_scopes(project, resource,
+                                                       old_content)
+
+
+def analyze_module(project, resource):
+    """Perform static object analysis on a python file in the project
+
+    Note that this might be really time consuming.
+    """
+    project.pycore.analyze_module(resource)
+
+
+def analyze_modules(project, task_handle=taskhandle.NullTaskHandle()):
+    """Perform static object analysis on all python files in the project
+
+    Note that this might be really time consuming.
+    """
+    resources = project.get_python_files()
+    job_set = task_handle.create_jobset('Analyzing Modules', len(resources))
+    for resource in resources:
+        job_set.started_job(resource.path)
+        analyze_module(project, resource)
+        job_set.finished_job()
+
+
+def get_string_module(project, code, resource=None, force_errors=False):
+    """Returns a `PyObject` object for the given code
+
+    If `force_errors` is `True`, `exceptions.ModuleSyntaxError` is
+    raised if module has syntax errors.  This overrides
+    ``ignore_syntax_errors`` project config.
+
+    """
+    return pyobjectsdef.PyModule(project.pycore, code, resource,
+                                 force_errors=force_errors)
+
+
+def get_string_scope(project, code, resource=None):
+    """Returns a `Scope` object for the given code"""
+    return get_string_module(project, code, resource).get_scope()
+
+
+def is_python_file(project, resource):
+    return project.pycore.is_python_file(resource)
+
+
+def modname(resource):
+    if resource.is_folder():
+        module_name = resource.name
+        source_folder = resource.parent
+    elif resource.name == '__init__.py':
+        module_name = resource.parent.name
+        source_folder = resource.parent.parent
+    else:
+        module_name = resource.name[:-3]
+        source_folder = resource.parent
+
+    while source_folder != source_folder.parent and \
+            source_folder.has_child('__init__.py'):
+        module_name = source_folder.name + '.' + module_name
+        source_folder = source_folder.parent
+
+    return module_name
diff --git a/venv/Lib/site-packages/rope/base/oi/__init__.py b/venv/Lib/site-packages/rope/base/oi/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b1a1525c088b696e674fcb7b623ff44456cda92
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/__init__.py
@@ -0,0 +1,38 @@
+"""Rope object analysis and inference package
+
+Rope makes some simplifying assumptions about a python program.  It
+assumes that a program only performs assignments and function calls.
+Tracking assignments is simple and `PyName` objects handle that.  The
+main problem is function calls.  Rope uses these two approaches for
+obtaining call information:
+
+* Static object analysis: `rope.base.pycore.PyCore.analyze_module()`
+
+  It can analyze modules to obtain information about functions.  This
+  is done by analyzing function calls in a module or scope.  Currently
+  SOA analyzes the scopes that are changed while saving or when the
+  user asks to analyze a module.  That is mainly because static
+  analysis is time-consuming.
+
+* Dynamic object analysis: `rope.base.pycore.PyCore.run_module()`
+
+  When you run a module or your testsuite, when DOA is enabled, it
+  collects information about parameters passed to and objects returned
+  from functions.  The main problem with this approach is that it is
+  quite slow; Not when looking up the information but when collecting
+  them.
+
+An instance of `rope.base.oi.objectinfo.ObjectInfoManager` can be used
+for accessing these information.  It saves the data in a
+`rope.base.oi.objectdb.ObjectDB` internally.
+
+Now if our objectdb does not know anything about a function and we
+need the value returned by it, static object inference, SOI, comes
+into play.  It analyzes function body and tries to infer the object
+that is returned from it (we usually need the returned value for the
+given parameter objects).
+
+Rope might collect and store information for other `PyName`\s, too.
+For instance rope stores the object builtin containers hold.
+
+"""
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f62221bfb6b424667362885df73926300237aa10
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/doa.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/doa.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3fe5c7e1d324803c8b72ca240fc4aacd4f9c2400
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/doa.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/memorydb.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/memorydb.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2073b12a58e9dff30576161fcad676d4d3ac2502
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/memorydb.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/objectdb.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/objectdb.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d8a7c499b2bca10b97242a8463002fe2bfda89af
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/objectdb.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/objectinfo.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/objectinfo.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1b943658349e5946fce325d3463be69dcef32cfb
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/objectinfo.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/runmod.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/runmod.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..585e8ead65877d59648dc24b7d51b941639b9696
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/runmod.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/soa.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/soa.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ddadf0462b2beb9c42f4bc9a53d6128a73e72d4a
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/soa.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/soi.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/soi.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5043e5157f22b71651b61d80c975ec4ff3c7f420
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/soi.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/__pycache__/transform.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/__pycache__/transform.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..64d7b022935a2fb4bdcc6b90a6ab9f6ba714abb7
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/__pycache__/transform.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/doa.py b/venv/Lib/site-packages/rope/base/oi/doa.py
new file mode 100644
index 0000000000000000000000000000000000000000..63ebc50ea762b6469996fa38dc5f0893650a966e
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/doa.py
@@ -0,0 +1,222 @@
+import base64
+import hashlib
+import hmac
+try:
+    import cPickle as pickle
+except ImportError:
+    import pickle
+import marshal
+import os
+import socket
+import subprocess
+import sys
+import tempfile
+import threading
+
+
+def _compat_compare_digest(a, b):
+    """Implementation of hmac.compare_digest for python < 2.7.7.
+
+    This function uses an approach designed to prevent timing analysis by
+    avoiding content-based short circuiting behaviour, making it appropriate
+    for cryptography.
+    """
+    if len(a) != len(b):
+        return False
+    # Computes the bitwise difference of all characters in the two strings
+    # before returning whether or not they are equal.
+    difference = 0
+    for (a_char, b_char) in zip(a, b):
+        difference |= ord(a_char) ^ ord(b_char)
+    return difference == 0
+
+try:
+    from hmac import compare_digest
+except ImportError:
+    compare_digest = _compat_compare_digest
+
+
+class PythonFileRunner(object):
+    """A class for running python project files"""
+
+    def __init__(self, pycore, file_, args=None, stdin=None,
+                 stdout=None, analyze_data=None):
+        self.pycore = pycore
+        self.file = file_
+        self.analyze_data = analyze_data
+        self.observers = []
+        self.args = args
+        self.stdin = stdin
+        self.stdout = stdout
+
+    def run(self):
+        """Execute the process"""
+        env = dict(os.environ)
+        file_path = self.file.real_path
+        path_folders = self.pycore.project.get_source_folders() + \
+            self.pycore.project.get_python_path_folders()
+        env['PYTHONPATH'] = os.pathsep.join(folder.real_path
+                                            for folder in path_folders)
+        runmod_path = self.pycore.project.find_module('rope.base.oi.runmod').real_path
+        self.receiver = None
+        self._init_data_receiving()
+        send_info = '-'
+        if self.receiver:
+            send_info = self.receiver.get_send_info()
+        args = [sys.executable, runmod_path, send_info,
+                self.pycore.project.address, self.file.real_path]
+        if self.analyze_data is None:
+            del args[1:4]
+        if self.args is not None:
+            args.extend(self.args)
+        self.process = subprocess.Popen(
+            executable=sys.executable, args=args, env=env,
+            cwd=os.path.split(file_path)[0], stdin=self.stdin,
+            stdout=self.stdout, stderr=self.stdout, close_fds=os.name != 'nt')
+
+    def _init_data_receiving(self):
+        if self.analyze_data is None:
+            return
+        # Disabling FIFO data transfer due to blocking when running
+        # unittests in the GUI.
+        # XXX: Handle FIFO data transfer for `rope.ui.testview`
+        if True or os.name == 'nt':
+            self.receiver = _SocketReceiver()
+        else:
+            self.receiver = _FIFOReceiver()
+        self.receiving_thread = threading.Thread(
+            target=self._receive_information)
+        self.receiving_thread.setDaemon(True)
+        self.receiving_thread.start()
+
+    def _receive_information(self):
+        #temp = open('/dev/shm/info', 'wb')
+        for data in self.receiver.receive_data():
+            self.analyze_data(data)
+            #temp.write(str(data) + '\n')
+        #temp.close()
+        for observer in self.observers:
+            observer()
+
+    def wait_process(self):
+        """Wait for the process to finish"""
+        self.process.wait()
+        if self.analyze_data:
+            self.receiving_thread.join()
+
+    def kill_process(self):
+        """Stop the process"""
+        if self.process.poll() is not None:
+            return
+        try:
+            if hasattr(self.process, 'terminate'):
+                self.process.terminate()
+            elif os.name != 'nt':
+                os.kill(self.process.pid, 9)
+            else:
+                import ctypes
+                handle = int(self.process._handle)
+                ctypes.windll.kernel32.TerminateProcess(handle, -1)
+        except OSError:
+            pass
+
+    def add_finishing_observer(self, observer):
+        """Notify this observer when execution finishes"""
+        self.observers.append(observer)
+
+
+class _MessageReceiver(object):
+
+    def receive_data(self):
+        pass
+
+    def get_send_info(self):
+        pass
+
+
+class _SocketReceiver(_MessageReceiver):
+
+    def __init__(self):
+        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.data_port = 3037
+        self.key = os.urandom(32)
+
+        while self.data_port < 4000:
+            try:
+                self.server_socket.bind(('localhost', self.data_port))
+                break
+            except socket.error:
+                self.data_port += 1
+        self.server_socket.listen(1)
+
+    def get_send_info(self):
+        return '%d:%s' % (self.data_port,
+                          base64.b64encode(self.key).decode('utf-8'))
+
+    def receive_data(self):
+        conn, addr = self.server_socket.accept()
+        self.server_socket.close()
+        my_file = conn.makefile('rb')
+        while True:
+            # Received messages must meet the following criteria:
+            # 1. Must be contained on a single line.
+            # 2. Must be prefixed with a base64 encoded sha256 message digest 
+            #    of the base64 encoded pickle data.
+            # 3. Message digest must be computed using the correct key.
+            #
+            # Any messages received that do not meet these criteria will never
+            # be unpickled and will be dropped silently.
+            try:
+                buf = my_file.readline()
+                if len(buf) == 0:
+                    break
+
+                try:
+                    digest_end = buf.index(b':')
+                    buf_digest = base64.b64decode(buf[:digest_end])
+                    buf_data = buf[digest_end + 1:-1]
+                    decoded_buf_data = base64.b64decode(buf_data)
+                except:
+                    # Corrupted data; the payload cannot be trusted and just has
+                    # to be dropped. See CVE-2014-3539.
+                    continue
+
+                digest = hmac.new(self.key, buf_data, hashlib.sha256).digest()
+                if not compare_digest(buf_digest, digest):
+                    # Signature mismatch; the payload cannot be trusted and just
+                    # has to be dropped. See CVE-2014-3539.
+                    continue
+
+                yield pickle.loads(decoded_buf_data)
+            except EOFError:
+                break
+        my_file.close()
+        conn.close()
+
+
+class _FIFOReceiver(_MessageReceiver):
+
+    def __init__(self):
+        # XXX: this is insecure and might cause race conditions
+        self.file_name = self._get_file_name()
+        os.mkfifo(self.file_name)
+
+    def _get_file_name(self):
+        prefix = tempfile.gettempdir() + '/__rope_'
+        i = 0
+        while os.path.exists(prefix + str(i).rjust(4, '0')):
+            i += 1
+        return prefix + str(i).rjust(4, '0')
+
+    def get_send_info(self):
+        return self.file_name
+
+    def receive_data(self):
+        my_file = open(self.file_name, 'rb')
+        while True:
+            try:
+                yield marshal.load(my_file)
+            except EOFError:
+                break
+        my_file.close()
+        os.remove(self.file_name)
diff --git a/venv/Lib/site-packages/rope/base/oi/memorydb.py b/venv/Lib/site-packages/rope/base/oi/memorydb.py
new file mode 100644
index 0000000000000000000000000000000000000000..01c814ce460afc8463a9e5aa26e9ddaefd5f3755
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/memorydb.py
@@ -0,0 +1,127 @@
+from rope.base.oi import objectdb
+
+
+class MemoryDB(objectdb.FileDict):
+
+    def __init__(self, project, persist=None):
+        self.project = project
+        self._persist = persist
+        self.files = self
+        self._load_files()
+        self.project.data_files.add_write_hook(self.write)
+
+    def _load_files(self):
+        self._files = {}
+        if self.persist:
+            result = self.project.data_files.read_data(
+                'objectdb', compress=self.compress, import_=True)
+            if result is not None:
+                self._files = result
+
+    def keys(self):
+        return self._files.keys()
+
+    def __iter__(self):
+        for f in self._files:
+            yield f
+
+    def __len__(self):
+        return len(self._files)
+
+    def __setitem__(self):
+        raise NotImplementedError()
+
+    def __contains__(self, key):
+        return key in self._files
+
+    def __getitem__(self, key):
+        return FileInfo(self._files[key])
+
+    def create(self, path):
+        self._files[path] = {}
+
+    def rename(self, file, newfile):
+        if file not in self._files:
+            return
+        self._files[newfile] = self._files[file]
+        del self[file]
+
+    def __delitem__(self, file):
+        del self._files[file]
+
+    def write(self):
+        if self.persist:
+            self.project.data_files.write_data('objectdb', self._files,
+                                               self.compress)
+
+    @property
+    def compress(self):
+        return self.project.prefs.get('compress_objectdb', False)
+
+    @property
+    def persist(self):
+        if self._persist is not None:
+            return self._persist
+        else:
+            return self.project.prefs.get('save_objectdb', False)
+
+
+class FileInfo(objectdb.FileInfo):
+
+    def __init__(self, scopes):
+        self.scopes = scopes
+
+    def create_scope(self, key):
+        self.scopes[key] = ScopeInfo()
+
+    def keys(self):
+        return self.scopes.keys()
+
+    def __contains__(self, key):
+        return key in self.scopes
+
+    def __getitem__(self, key):
+        return self.scopes[key]
+
+    def __delitem__(self, key):
+        del self.scopes[key]
+
+    def __iter__(self):
+        for s in self.scopes:
+            yield s
+
+    def __len__(self):
+        return len(self.scopes)
+
+    def __setitem__(self):
+        raise NotImplementedError()
+
+
+
+class ScopeInfo(objectdb.ScopeInfo):
+
+    def __init__(self):
+        self.call_info = {}
+        self.per_name = {}
+
+    def get_per_name(self, name):
+        return self.per_name.get(name, None)
+
+    def save_per_name(self, name, value):
+        self.per_name[name] = value
+
+    def get_returned(self, parameters):
+        return self.call_info.get(parameters, None)
+
+    def get_call_infos(self):
+        for args, returned in self.call_info.items():
+            yield objectdb.CallInfo(args, returned)
+
+    def add_call(self, parameters, returned):
+        self.call_info[parameters] = returned
+
+    def __getstate__(self):
+        return (self.call_info, self.per_name)
+
+    def __setstate__(self, data):
+        self.call_info, self.per_name = data
diff --git a/venv/Lib/site-packages/rope/base/oi/objectdb.py b/venv/Lib/site-packages/rope/base/oi/objectdb.py
new file mode 100644
index 0000000000000000000000000000000000000000..61f2711dd4e0a3d559798ed5e0471f56b54faff5
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/objectdb.py
@@ -0,0 +1,179 @@
+from __future__ import print_function
+try:
+    from collections import MutableMapping
+except ImportError:
+    from UserDict import DictMixin as MutableMapping
+
+
+class ObjectDB(object):
+
+    def __init__(self, db, validation):
+        self.db = db
+        self.validation = validation
+        self.observers = []
+        self.files = db.files
+
+    def validate_files(self):
+        for file in list(self.files):
+            if not self.validation.is_file_valid(file):
+                del self.files[file]
+                self._file_removed(file)
+
+    def validate_file(self, file):
+        if file not in self.files:
+            return
+        for key in list(self.files[file]):
+            if not self.validation.is_scope_valid(file, key):
+                del self.files[file][key]
+
+    def file_moved(self, file, newfile):
+        if file not in self.files:
+            return
+        self.files.rename(file, newfile)
+        self._file_removed(file)
+        self._file_added(newfile)
+
+    def get_files(self):
+        return self.files.keys()
+
+    def get_returned(self, path, key, args):
+        scope_info = self._get_scope_info(path, key, readonly=True)
+        result = scope_info.get_returned(args)
+        if self.validation.is_value_valid(result):
+            return result
+
+    def get_pername(self, path, key, name):
+        scope_info = self._get_scope_info(path, key, readonly=True)
+        result = scope_info.get_per_name(name)
+        if self.validation.is_value_valid(result):
+            return result
+
+    def get_callinfos(self, path, key):
+        scope_info = self._get_scope_info(path, key, readonly=True)
+        return scope_info.get_call_infos()
+
+    def add_callinfo(self, path, key, args, returned):
+        scope_info = self._get_scope_info(path, key, readonly=False)
+        old_returned = scope_info.get_returned(args)
+        if self.validation.is_more_valid(returned, old_returned):
+            scope_info.add_call(args, returned)
+
+    def add_pername(self, path, key, name, value):
+        scope_info = self._get_scope_info(path, key, readonly=False)
+        old_value = scope_info.get_per_name(name)
+        if self.validation.is_more_valid(value, old_value):
+            scope_info.save_per_name(name, value)
+
+    def add_file_list_observer(self, observer):
+        self.observers.append(observer)
+
+    def write(self):
+        self.db.write()
+
+    def _get_scope_info(self, path, key, readonly=True):
+        if path not in self.files:
+            if readonly:
+                return _NullScopeInfo()
+            self.files.create(path)
+            self._file_added(path)
+        if key not in self.files[path]:
+            if readonly:
+                return _NullScopeInfo()
+            self.files[path].create_scope(key)
+        result = self.files[path][key]
+        if isinstance(result, dict):
+            print(self.files, self.files[path], self.files[path][key])
+        return result
+
+    def _file_removed(self, path):
+        for observer in self.observers:
+            observer.removed(path)
+
+    def _file_added(self, path):
+        for observer in self.observers:
+            observer.added(path)
+
+    def __str__(self):
+        scope_count = 0
+        for file_dict in self.files.values():
+            scope_count += len(file_dict)
+        return 'ObjectDB holds %s file and %s scope infos' % \
+               (len(self.files), scope_count)
+
+
+class _NullScopeInfo(object):
+
+    def __init__(self, error_on_write=True):
+        self.error_on_write = error_on_write
+
+    def get_per_name(self, name):
+        pass
+
+    def save_per_name(self, name, value):
+        if self.error_on_write:
+            raise NotImplementedError()
+
+    def get_returned(self, parameters):
+        pass
+
+    def get_call_infos(self):
+        return []
+
+    def add_call(self, parameters, returned):
+        if self.error_on_write:
+            raise NotImplementedError()
+
+
+class FileInfo(MutableMapping):
+
+    def create_scope(self, key):
+        pass
+
+
+class FileDict(MutableMapping):
+
+    def create(self, key):
+        pass
+
+    def rename(self, key, new_key):
+        pass
+
+
+class ScopeInfo(object):
+
+    def get_per_name(self, name):
+        pass
+
+    def save_per_name(self, name, value):
+        pass
+
+    def get_returned(self, parameters):
+        pass
+
+    def get_call_infos(self):
+        pass
+
+    def add_call(self, parameters, returned):
+        pass
+
+
+class CallInfo(object):
+
+    def __init__(self, args, returned):
+        self.args = args
+        self.returned = returned
+
+    def get_parameters(self):
+        return self.args
+
+    def get_returned(self):
+        return self.returned
+
+
+class FileListObserver(object):
+
+    def added(self, path):
+        pass
+
+    def removed(self, path):
+        pass
diff --git a/venv/Lib/site-packages/rope/base/oi/objectinfo.py b/venv/Lib/site-packages/rope/base/oi/objectinfo.py
new file mode 100644
index 0000000000000000000000000000000000000000..f86d72e0b5cc26f2432aa678f7e5144451f5e8fa
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/objectinfo.py
@@ -0,0 +1,232 @@
+import warnings
+
+from rope.base import exceptions, resourceobserver
+from rope.base.oi import objectdb, memorydb, transform
+
+
+class ObjectInfoManager(object):
+    """Stores object information
+
+    It uses an instance of `objectdb.ObjectDB` for storing
+    information.
+
+    """
+
+    def __init__(self, project):
+        self.project = project
+        self.to_textual = transform.PyObjectToTextual(project)
+        self.to_pyobject = transform.TextualToPyObject(project)
+        self.doi_to_pyobject = transform.DOITextualToPyObject(project)
+        self._init_objectdb()
+        if project.prefs.get('validate_objectdb', False):
+            self._init_validation()
+
+    def _init_objectdb(self):
+        dbtype = self.project.get_prefs().get('objectdb_type', None)
+        persist = None
+        if dbtype is not None:
+            warnings.warn(
+                '"objectdb_type" project config is deprecated;\n'
+                'Use "save_objectdb" instead in your project '
+                'config file.\n(".ropeproject/config.py" by default)\n',
+                DeprecationWarning)
+            if dbtype != 'memory' and self.project.ropefolder is not None:
+                persist = True
+        self.validation = TextualValidation(self.to_pyobject)
+        db = memorydb.MemoryDB(self.project, persist=persist)
+        self.objectdb = objectdb.ObjectDB(db, self.validation)
+
+    def _init_validation(self):
+        self.objectdb.validate_files()
+        observer = resourceobserver.ResourceObserver(
+            changed=self._resource_changed, moved=self._resource_moved,
+            removed=self._resource_moved)
+        files = []
+        for path in self.objectdb.get_files():
+            resource = self.to_pyobject.path_to_resource(path)
+            if resource is not None and resource.project == self.project:
+                files.append(resource)
+        self.observer = resourceobserver.FilteredResourceObserver(observer,
+                                                                  files)
+        self.objectdb.add_file_list_observer(_FileListObserver(self))
+        self.project.add_observer(self.observer)
+
+    def _resource_changed(self, resource):
+        try:
+            self.objectdb.validate_file(
+                self.to_textual.resource_to_path(resource))
+        except exceptions.ModuleSyntaxError:
+            pass
+
+    def _resource_moved(self, resource, new_resource=None):
+        self.observer.remove_resource(resource)
+        if new_resource is not None:
+            old = self.to_textual.resource_to_path(resource)
+            new = self.to_textual.resource_to_path(new_resource)
+            self.objectdb.file_moved(old, new)
+            self.observer.add_resource(new_resource)
+
+    def get_returned(self, pyobject, args):
+        result = self.get_exact_returned(pyobject, args)
+        if result is not None:
+            return result
+        path, key = self._get_scope(pyobject)
+        if path is None:
+            return None
+        for call_info in self.objectdb.get_callinfos(path, key):
+            returned = call_info.get_returned()
+            if returned and returned[0] not in ('unknown', 'none'):
+                result = returned
+                break
+            if result is None:
+                result = returned
+        if result is not None:
+            return self.to_pyobject(result)
+
+    def get_exact_returned(self, pyobject, args):
+        path, key = self._get_scope(pyobject)
+        if path is not None:
+            returned = self.objectdb.get_returned(
+                path, key, self._args_to_textual(pyobject, args))
+            if returned is not None:
+                return self.to_pyobject(returned)
+
+    def _args_to_textual(self, pyfunction, args):
+        parameters = list(pyfunction.get_param_names(special_args=False))
+        arguments = args.get_arguments(parameters)[:len(parameters)]
+        textual_args = tuple([self.to_textual(arg)
+                              for arg in arguments])
+        return textual_args
+
+    def get_parameter_objects(self, pyobject):
+        path, key = self._get_scope(pyobject)
+        if path is None:
+            return None
+        arg_count = len(pyobject.get_param_names(special_args=False))
+        unknowns = arg_count
+        parameters = [None] * arg_count
+        for call_info in self.objectdb.get_callinfos(path, key):
+            args = call_info.get_parameters()
+            for index, arg in enumerate(args[:arg_count]):
+                old = parameters[index]
+                if self.validation.is_more_valid(arg, old):
+                    parameters[index] = arg
+                    if self.validation.is_value_valid(arg):
+                        unknowns -= 1
+            if unknowns == 0:
+                break
+        if unknowns < arg_count:
+            return [self.to_pyobject(parameter)
+                    for parameter in parameters]
+
+    def get_passed_objects(self, pyfunction, parameter_index):
+        path, key = self._get_scope(pyfunction)
+        if path is None:
+            return []
+        result = []
+        for call_info in self.objectdb.get_callinfos(path, key):
+            args = call_info.get_parameters()
+            if len(args) > parameter_index:
+                parameter = self.to_pyobject(args[parameter_index])
+                if parameter is not None:
+                    result.append(parameter)
+        return result
+
+    def doa_data_received(self, data):
+        def doi_to_normal(textual):
+            pyobject = self.doi_to_pyobject(textual)
+            return self.to_textual(pyobject)
+        function = doi_to_normal(data[0])
+        args = tuple([doi_to_normal(textual) for textual in data[1]])
+        returned = doi_to_normal(data[2])
+        if function[0] == 'defined' and len(function) == 3:
+            self._save_data(function, args, returned)
+
+    def function_called(self, pyfunction, params, returned=None):
+        function_text = self.to_textual(pyfunction)
+        params_text = tuple([self.to_textual(param)
+                             for param in params])
+        returned_text = ('unknown',)
+        if returned is not None:
+            returned_text = self.to_textual(returned)
+        self._save_data(function_text, params_text, returned_text)
+
+    def save_per_name(self, scope, name, data):
+        path, key = self._get_scope(scope.pyobject)
+        if path is not None:
+            self.objectdb.add_pername(path, key, name, self.to_textual(data))
+
+    def get_per_name(self, scope, name):
+        path, key = self._get_scope(scope.pyobject)
+        if path is not None:
+            result = self.objectdb.get_pername(path, key, name)
+            if result is not None:
+                return self.to_pyobject(result)
+
+    def _save_data(self, function, args, returned=('unknown',)):
+        self.objectdb.add_callinfo(function[1], function[2], args, returned)
+
+    def _get_scope(self, pyobject):
+        resource = pyobject.get_module().get_resource()
+        if resource is None:
+            return None, None
+        textual = self.to_textual(pyobject)
+        if textual[0] == 'defined':
+            path = textual[1]
+            if len(textual) == 3:
+                key = textual[2]
+            else:
+                key = ''
+            return path, key
+        return None, None
+
+    def sync(self):
+        self.objectdb.sync()
+
+    def __str__(self):
+        return str(self.objectdb)
+
+
+class TextualValidation(object):
+
+    def __init__(self, to_pyobject):
+        self.to_pyobject = to_pyobject
+
+    def is_value_valid(self, value):
+        # ???: Should none and unknown be considered valid?
+        if value is None or value[0] in ('none', 'unknown'):
+            return False
+        return self.to_pyobject(value) is not None
+
+    def is_more_valid(self, new, old):
+        if old is None:
+            return True
+        return new[0] not in ('unknown', 'none')
+
+    def is_file_valid(self, path):
+        return self.to_pyobject.path_to_resource(path) is not None
+
+    def is_scope_valid(self, path, key):
+        if key == '':
+            textual = ('defined', path)
+        else:
+            textual = ('defined', path, key)
+        return self.to_pyobject(textual) is not None
+
+
+class _FileListObserver(object):
+
+    def __init__(self, object_info):
+        self.object_info = object_info
+        self.observer = self.object_info.observer
+        self.to_pyobject = self.object_info.to_pyobject
+
+    def removed(self, path):
+        resource = self.to_pyobject.path_to_resource(path)
+        if resource is not None:
+            self.observer.remove_resource(resource)
+
+    def added(self, path):
+        resource = self.to_pyobject.path_to_resource(path)
+        if resource is not None:
+            self.observer.add_resource(resource)
diff --git a/venv/Lib/site-packages/rope/base/oi/runmod.py b/venv/Lib/site-packages/rope/base/oi/runmod.py
new file mode 100644
index 0000000000000000000000000000000000000000..055d9ae86021b0c96189d3f5e5cbbe35b21f82b8
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/runmod.py
@@ -0,0 +1,230 @@
+def __rope_start_everything():
+    import os
+    import sys
+    import socket
+    try:
+        import cPickle as pickle
+    except ImportError:
+        import pickle
+    import marshal
+    import inspect
+    import types
+    import threading
+    import rope.base.utils.pycompat as pycompat
+    import base64
+    import hashlib
+    import hmac
+
+    class _MessageSender(object):
+
+        def send_data(self, data):
+            pass
+
+    class _SocketSender(_MessageSender):
+
+        def __init__(self, port, key):
+            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            s.connect(('127.0.0.1', port))
+            self.my_file = s.makefile('wb')
+            self.key = base64.b64decode(key)
+
+        def send_data(self, data):
+            if not self.my_file.closed:
+                pickled_data = base64.b64encode(
+                    pickle.dumps(data, pickle.HIGHEST_PROTOCOL))
+                dgst = hmac.new(self.key, pickled_data, hashlib.sha256).digest()
+                self.my_file.write(base64.b64encode(dgst) + b':' +
+                                   pickled_data + b'\n')
+        def close(self):
+            self.my_file.close()
+
+    class _FileSender(_MessageSender):
+
+        def __init__(self, file_name):
+            self.my_file = open(file_name, 'wb')
+
+        def send_data(self, data):
+            if not self.my_file.closed:
+                marshal.dump(data, self.my_file)
+
+        def close(self):
+            self.my_file.close()
+
+    def _cached(func):
+        cache = {}
+
+        def newfunc(self, arg):
+            if arg in cache:
+                return cache[arg]
+            result = func(self, arg)
+            cache[arg] = result
+            return result
+        return newfunc
+
+    class _FunctionCallDataSender(object):
+
+        def __init__(self, send_info, project_root):
+            self.project_root = project_root
+            if send_info[0].isdigit():
+                port, key = send_info.split(':', 1)
+                self.sender = _SocketSender(int(port), key)
+            else:
+                self.sender = _FileSender(send_info)
+
+            def global_trace(frame, event, arg):
+                # HACK: Ignoring out->in calls
+                # This might lose some information
+                if self._is_an_interesting_call(frame):
+                    return self.on_function_call
+            sys.settrace(global_trace)
+            threading.settrace(global_trace)
+
+        def on_function_call(self, frame, event, arg):
+            if event != 'return':
+                return
+            args = []
+            returned = ('unknown',)
+            code = frame.f_code
+            for argname in code.co_varnames[:code.co_argcount]:
+                try:
+                    argvalue = self._object_to_persisted_form(
+                        frame.f_locals[argname])
+                    args.append(argvalue)
+                except (TypeError, AttributeError):
+                    args.append(('unknown',))
+            try:
+                returned = self._object_to_persisted_form(arg)
+            except (TypeError, AttributeError):
+                pass
+            try:
+                data = (self._object_to_persisted_form(frame.f_code),
+                        tuple(args), returned)
+                self.sender.send_data(data)
+            except (TypeError):
+                pass
+            return self.on_function_call
+
+        def _is_an_interesting_call(self, frame):
+            #if frame.f_code.co_name in ['?', '<module>']:
+            #    return False
+            #return not frame.f_back or
+            #    not self._is_code_inside_project(frame.f_back.f_code)
+            if not self._is_code_inside_project(frame.f_code) and \
+               (not frame.f_back or
+                    not self._is_code_inside_project(frame.f_back.f_code)):
+                return False
+            return True
+
+        def _is_code_inside_project(self, code):
+            source = self._path(code.co_filename)
+            return source is not None and os.path.exists(source) and \
+                _realpath(source).startswith(self.project_root)
+
+        @_cached
+        def _get_persisted_code(self, object_):
+            source = self._path(object_.co_filename)
+            if not os.path.exists(source):
+                raise TypeError('no source')
+            return ('defined', _realpath(source), str(object_.co_firstlineno))
+
+        @_cached
+        def _get_persisted_class(self, object_):
+            try:
+                return ('defined', _realpath(inspect.getsourcefile(object_)),
+                        object_.__name__)
+            except (TypeError, AttributeError):
+                return ('unknown',)
+
+        def _get_persisted_builtin(self, object_):
+            if isinstance(object_, pycompat.string_types):
+                return ('builtin', 'str')
+            if isinstance(object_, list):
+                holding = None
+                if len(object_) > 0:
+                    holding = object_[0]
+                return ('builtin', 'list',
+                        self._object_to_persisted_form(holding))
+            if isinstance(object_, dict):
+                keys = None
+                values = None
+                if len(object_) > 0:
+                    # @todo - fix it properly, why is __locals__ being
+                    # duplicated ?
+                    keys = [key for key in object_.keys() if key != '__locals__'][0]
+                    values = object_[keys]
+                return ('builtin', 'dict',
+                        self._object_to_persisted_form(keys),
+                        self._object_to_persisted_form(values))
+            if isinstance(object_, tuple):
+                objects = []
+                if len(object_) < 3:
+                    for holding in object_:
+                        objects.append(self._object_to_persisted_form(holding))
+                else:
+                    objects.append(self._object_to_persisted_form(object_[0]))
+                return tuple(['builtin', 'tuple'] + objects)
+            if isinstance(object_, set):
+                holding = None
+                if len(object_) > 0:
+                    for o in object_:
+                        holding = o
+                        break
+                return ('builtin', 'set',
+                        self._object_to_persisted_form(holding))
+            return ('unknown',)
+
+        def _object_to_persisted_form(self, object_):
+            if object_ is None:
+                return ('none',)
+            if isinstance(object_, types.CodeType):
+                return self._get_persisted_code(object_)
+            if isinstance(object_, types.FunctionType):
+                return self._get_persisted_code(object_.__code__)
+            if isinstance(object_, types.MethodType):
+                return self._get_persisted_code(object_.__func__.__code__)
+            if isinstance(object_, types.ModuleType):
+                return self._get_persisted_module(object_)
+            if isinstance(object_, pycompat.string_types + (list, dict, tuple, set)):
+                return self._get_persisted_builtin(object_)
+            if isinstance(object_, type):
+                return self._get_persisted_class(object_)
+            return ('instance', self._get_persisted_class(type(object_)))
+
+        @_cached
+        def _get_persisted_module(self, object_):
+            path = self._path(object_.__file__)
+            if path and os.path.exists(path):
+                return ('defined', _realpath(path))
+            return ('unknown',)
+
+        def _path(self, path):
+            if path.endswith('.pyc'):
+                path = path[:-1]
+            if path.endswith('.py'):
+                return path
+
+        def close(self):
+            self.sender.close()
+            sys.settrace(None)
+
+    def _realpath(path):
+        return os.path.realpath(os.path.abspath(os.path.expanduser(path)))
+
+    send_info = sys.argv[1]
+    project_root = sys.argv[2]
+    file_to_run = sys.argv[3]
+    run_globals = globals()
+    run_globals.update({'__name__': '__main__',
+                        '__builtins__': __builtins__,
+                        '__file__': file_to_run})
+
+    if send_info != '-':
+        data_sender = _FunctionCallDataSender(send_info, project_root)
+    del sys.argv[1:4]
+    pycompat.execfile(file_to_run, run_globals)
+    if send_info != '-':
+        data_sender.close()
+
+
+if __name__ == '__main__':
+    __rope_start_everything()
diff --git a/venv/Lib/site-packages/rope/base/oi/soa.py b/venv/Lib/site-packages/rope/base/oi/soa.py
new file mode 100644
index 0000000000000000000000000000000000000000..a34b970ea2f599189ad959f7a97ad6e4a6ec8275
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/soa.py
@@ -0,0 +1,139 @@
+import rope.base.ast
+import rope.base.oi.soi
+import rope.base.pynames
+from rope.base import pyobjects, evaluate, astutils, arguments
+
+
+def analyze_module(pycore, pymodule, should_analyze,
+                   search_subscopes, followed_calls):
+    """Analyze `pymodule` for static object inference
+
+    Analyzes scopes for collecting object information.  The analysis
+    starts from inner scopes.
+
+    """
+    _analyze_node(pycore, pymodule, should_analyze,
+                  search_subscopes, followed_calls)
+
+
+def _analyze_node(pycore, pydefined, should_analyze,
+                  search_subscopes, followed_calls):
+    if search_subscopes(pydefined):
+        for scope in pydefined.get_scope().get_scopes():
+            _analyze_node(pycore, scope.pyobject, should_analyze,
+                          search_subscopes, followed_calls)
+    if should_analyze(pydefined):
+        new_followed_calls = max(0, followed_calls - 1)
+        return_true = lambda pydefined: True
+        return_false = lambda pydefined: False
+
+        def _follow(pyfunction):
+            _analyze_node(pycore, pyfunction, return_true,
+                          return_false, new_followed_calls)
+
+        if not followed_calls:
+            _follow = None
+        visitor = SOAVisitor(pycore, pydefined, _follow)
+        for child in rope.base.ast.get_child_nodes(pydefined.get_ast()):
+            rope.base.ast.walk(child, visitor)
+
+
+class SOAVisitor(object):
+
+    def __init__(self, pycore, pydefined, follow_callback=None):
+        self.pycore = pycore
+        self.pymodule = pydefined.get_module()
+        self.scope = pydefined.get_scope()
+        self.follow = follow_callback
+
+    def _FunctionDef(self, node):
+        pass
+
+    def _ClassDef(self, node):
+        pass
+
+    def _Call(self, node):
+        for child in rope.base.ast.get_child_nodes(node):
+            rope.base.ast.walk(child, self)
+        primary, pyname = evaluate.eval_node2(self.scope, node.func)
+        if pyname is None:
+            return
+        pyfunction = pyname.get_object()
+        if isinstance(pyfunction, pyobjects.AbstractFunction):
+            args = arguments.create_arguments(primary, pyfunction,
+                                              node, self.scope)
+        elif isinstance(pyfunction, pyobjects.PyClass):
+            pyclass = pyfunction
+            if '__init__' in pyfunction:
+                pyfunction = pyfunction['__init__'].get_object()
+            pyname = rope.base.pynames.UnboundName(pyobjects.PyObject(pyclass))
+            args = self._args_with_self(primary, pyname, pyfunction, node)
+        elif '__call__' in pyfunction:
+            pyfunction = pyfunction['__call__'].get_object()
+            args = self._args_with_self(primary, pyname, pyfunction, node)
+        else:
+            return
+        self._call(pyfunction, args)
+
+    def _args_with_self(self, primary, self_pyname, pyfunction, node):
+        base_args = arguments.create_arguments(primary, pyfunction,
+                                               node, self.scope)
+        return arguments.MixedArguments(self_pyname, base_args, self.scope)
+
+    def _call(self, pyfunction, args):
+        if isinstance(pyfunction, pyobjects.PyFunction):
+            if self.follow is not None:
+                before = self._parameter_objects(pyfunction)
+            self.pycore.object_info.function_called(
+                pyfunction, args.get_arguments(pyfunction.get_param_names()))
+            pyfunction._set_parameter_pyobjects(None)
+            if self.follow is not None:
+                after = self._parameter_objects(pyfunction)
+                if after != before:
+                    self.follow(pyfunction)
+        # XXX: Maybe we should not call every builtin function
+        if isinstance(pyfunction, rope.base.builtins.BuiltinFunction):
+            pyfunction.get_returned_object(args)
+
+    def _parameter_objects(self, pyfunction):
+        result = []
+        for i in range(len(pyfunction.get_param_names(False))):
+            result.append(pyfunction.get_parameter(i))
+        return result
+
+    def _Assign(self, node):
+        for child in rope.base.ast.get_child_nodes(node):
+            rope.base.ast.walk(child, self)
+        visitor = _SOAAssignVisitor()
+        nodes = []
+        for child in node.targets:
+            rope.base.ast.walk(child, visitor)
+            nodes.extend(visitor.nodes)
+        for subscript, levels in nodes:
+            instance = evaluate.eval_node(self.scope, subscript.value)
+            args_pynames = []
+            args_pynames.append(evaluate.eval_node(self.scope,
+                                                   subscript.slice.value))
+            value = rope.base.oi.soi._infer_assignment(
+                rope.base.pynames.AssignmentValue(node.value, levels),
+                self.pymodule)
+            args_pynames.append(rope.base.pynames.UnboundName(value))
+            if instance is not None and value is not None:
+                pyobject = instance.get_object()
+                if '__setitem__' in pyobject:
+                    pyfunction = pyobject['__setitem__'].get_object()
+                    args = arguments.ObjectArguments([instance] + args_pynames)
+                    self._call(pyfunction, args)
+                # IDEA: handle `__setslice__`, too
+
+
+class _SOAAssignVisitor(astutils._NodeNameCollector):
+
+    def __init__(self):
+        super(_SOAAssignVisitor, self).__init__()
+        self.nodes = []
+
+    def _added(self, node, levels):
+        if isinstance(node, rope.base.ast.Subscript) and \
+           isinstance(node.slice, rope.base.ast.Index):
+            self.nodes.append((node, levels))
diff --git a/venv/Lib/site-packages/rope/base/oi/soi.py b/venv/Lib/site-packages/rope/base/oi/soi.py
new file mode 100644
index 0000000000000000000000000000000000000000..c05aba94b1a3c266870ac2af34d0c773430fb3c1
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/soi.py
@@ -0,0 +1,222 @@
+"""A module for inferring objects
+
+For more information see the documentation in `rope.base.oi`
+package.
+
+"""
+import rope.base.builtins
+import rope.base.pynames
+import rope.base.pyobjects
+from rope.base import evaluate, utils, arguments
+from rope.base.oi.type_hinting.factory import get_type_hinting_factory
+
+
+_ignore_inferred = utils.ignore_exception(
+    rope.base.pyobjects.IsBeingInferredError)
+
+
+@_ignore_inferred
+def infer_returned_object(pyfunction, args):
+    """Infer the `PyObject` this `PyFunction` returns after calling"""
+    object_info = pyfunction.pycore.object_info
+    result = object_info.get_exact_returned(pyfunction, args)
+    if result is not None:
+        return result
+    result = _infer_returned(pyfunction, args)
+    if result is not None:
+        if args and pyfunction.get_module().get_resource() is not None:
+            params = args.get_arguments(
+                pyfunction.get_param_names(special_args=False))
+            object_info.function_called(pyfunction, params, result)
+        return result
+    result = object_info.get_returned(pyfunction, args)
+    if result is not None:
+        return result
+    hint_return = get_type_hinting_factory(pyfunction.pycore.project).make_return_provider()
+    type_ = hint_return(pyfunction)
+    if type_ is not None:
+        return rope.base.pyobjects.PyObject(type_)
+
+
+@_ignore_inferred
+def infer_parameter_objects(pyfunction):
+    """Infer the `PyObject`\s of parameters of this `PyFunction`"""
+    object_info = pyfunction.pycore.object_info
+    result = object_info.get_parameter_objects(pyfunction)
+    if result is None:
+        result = _parameter_objects(pyfunction)
+    _handle_first_parameter(pyfunction, result)
+    return result
+
+
+def _handle_first_parameter(pyobject, parameters):
+    kind = pyobject.get_kind()
+    if parameters is None or kind not in ['method', 'classmethod']:
+        pass
+    if not parameters:
+        if not pyobject.get_param_names(special_args=False):
+            return
+        parameters.append(rope.base.pyobjects.get_unknown())
+    if kind == 'method':
+        parameters[0] = rope.base.pyobjects.PyObject(pyobject.parent)
+    if kind == 'classmethod':
+        parameters[0] = pyobject.parent
+
+
+@_ignore_inferred
+def infer_assigned_object(pyname):
+    if not pyname.assignments:
+        return
+    for assignment in reversed(pyname.assignments):
+        result = _infer_assignment(assignment, pyname.module)
+        if isinstance(result, rope.base.builtins.BuiltinUnknown) and result.get_name() == 'NotImplementedType':
+            break
+        elif result == rope.base.pyobjects.get_unknown():
+            break
+        elif result is not None:
+            return result
+
+    hint_assignment = get_type_hinting_factory(pyname.module.pycore.project).make_assignment_provider()
+    hinting_result = hint_assignment(pyname)
+    if hinting_result is not None:
+        return rope.base.pyobjects.PyObject(hinting_result)
+    return result
+
+
+def get_passed_objects(pyfunction, parameter_index):
+    object_info = pyfunction.pycore.object_info
+    result = object_info.get_passed_objects(pyfunction,
+                                            parameter_index)
+    if not result:
+        statically_inferred = _parameter_objects(pyfunction)
+        if len(statically_inferred) > parameter_index:
+            result.append(statically_inferred[parameter_index])
+    return result
+
+
+def _infer_returned(pyobject, args):
+    if args:
+        # HACK: Setting parameter objects manually
+        # This is not thread safe and might cause problems if `args`
+        # does not come from a good call site
+        pyobject.get_scope().invalidate_data()
+        pyobject._set_parameter_pyobjects(
+            args.get_arguments(pyobject.get_param_names(special_args=False)))
+    scope = pyobject.get_scope()
+    if not scope._get_returned_asts():
+        return
+    maxtries = 3
+    for returned_node in reversed(scope._get_returned_asts()[-maxtries:]):
+        try:
+            resulting_pyname = evaluate.eval_node(scope, returned_node)
+            if resulting_pyname is None:
+                continue
+            pyobject = resulting_pyname.get_object()
+            if pyobject == rope.base.pyobjects.get_unknown():
+                continue
+            if not scope._is_generator():
+                return pyobject
+            else:
+                return rope.base.builtins.get_generator(pyobject)
+        except rope.base.pyobjects.IsBeingInferredError:
+            pass
+
+
+def _parameter_objects(pyobject):
+    result = []
+    params = pyobject.get_param_names(special_args=False)
+    hint_param = get_type_hinting_factory(pyobject.pycore.project).make_param_provider()
+    for name in params:
+        type_ = hint_param(pyobject, name)
+        if type_ is not None:
+            result.append(rope.base.pyobjects.PyObject(type_))
+        else:
+            result.append(rope.base.pyobjects.get_unknown())
+    return result
+
+# handling `rope.base.pynames.AssignmentValue`
+
+
+@_ignore_inferred
+def _infer_assignment(assignment, pymodule):
+    result = _follow_pyname(assignment, pymodule)
+    if result is None:
+        return None
+    pyname, pyobject = result
+    pyobject = _follow_evaluations(assignment, pyname, pyobject)
+    if pyobject is None:
+        return None
+    return _follow_levels(assignment, pyobject)
+
+
+def _follow_levels(assignment, pyobject):
+    for index in assignment.levels:
+        if isinstance(pyobject.get_type(), rope.base.builtins.Tuple):
+            holdings = pyobject.get_type().get_holding_objects()
+            if holdings:
+                pyobject = holdings[min(len(holdings) - 1, index)]
+            else:
+                pyobject = None
+        elif isinstance(pyobject.get_type(), rope.base.builtins.List):
+            pyobject = pyobject.get_type().holding
+        else:
+            pyobject = None
+        if pyobject is None:
+            break
+    return pyobject
+
+
+@_ignore_inferred
+def _follow_pyname(assignment, pymodule, lineno=None):
+    assign_node = assignment.ast_node
+    if lineno is None:
+        lineno = _get_lineno_for_node(assign_node)
+    holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+    pyname = evaluate.eval_node(holding_scope, assign_node)
+    if pyname is not None:
+        result = pyname.get_object()
+        if isinstance(result.get_type(), rope.base.builtins.Property) and \
+           holding_scope.get_kind() == 'Class':
+            arg = rope.base.pynames.UnboundName(
+                rope.base.pyobjects.PyObject(holding_scope.pyobject))
+            return pyname, result.get_type().get_property_object(
+                arguments.ObjectArguments([arg]))
+        return pyname, result
+
+
+@_ignore_inferred
+def _follow_evaluations(assignment, pyname, pyobject):
+    new_pyname = pyname
+    tokens = assignment.evaluation.split('.')
+    for token in tokens:
+        call = token.endswith('()')
+        if call:
+            token = token[:-2]
+        if token:
+            pyname = new_pyname
+            new_pyname = _get_attribute(pyobject, token)
+            if new_pyname is not None:
+                pyobject = new_pyname.get_object()
+        if pyobject is not None and call:
+            if isinstance(pyobject, rope.base.pyobjects.AbstractFunction):
+                args = arguments.ObjectArguments([pyname])
+                pyobject = pyobject.get_returned_object(args)
+            else:
+                pyobject = None
+        if pyobject is None:
+            break
+    if pyobject is not None and assignment.assign_type:
+        return rope.base.pyobjects.PyObject(pyobject)
+    return pyobject
+
+
+def _get_lineno_for_node(assign_node):
+    if hasattr(assign_node, 'lineno') and \
+       assign_node.lineno is not None:
+        return assign_node.lineno
+    return 1
+
+
+def _get_attribute(pyobject, name):
+    if pyobject is not None and name in pyobject:
+        return pyobject[name]
diff --git a/venv/Lib/site-packages/rope/base/oi/transform.py b/venv/Lib/site-packages/rope/base/oi/transform.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa29c373d5cb34e24994ed2e43c86f0a080276a0
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/transform.py
@@ -0,0 +1,285 @@
+"""Provides classes for persisting `PyObject`\s"""
+import os
+import re
+
+import rope.base.builtins
+from rope.base import exceptions
+
+
+class PyObjectToTextual(object):
+    """For transforming `PyObject` to textual form
+
+    This can be used for storing `PyObjects` in files.  Use
+    `TextualToPyObject` for converting back.
+
+    """
+
+    def __init__(self, project):
+        self.project = project
+
+    def transform(self, pyobject):
+        """Transform a `PyObject` to textual form"""
+        if pyobject is None:
+            return ('none',)
+        object_type = type(pyobject)
+        try:
+            method = getattr(self, object_type.__name__ + '_to_textual')
+            return method(pyobject)
+        except AttributeError:
+            return ('unknown',)
+
+    def __call__(self, pyobject):
+        return self.transform(pyobject)
+
+    def PyObject_to_textual(self, pyobject):
+        if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass):
+            result = self.transform(pyobject.get_type())
+            if result[0] == 'defined':
+                return ('instance', result)
+            return result
+        return ('unknown',)
+
+    def PyFunction_to_textual(self, pyobject):
+        return self._defined_to_textual(pyobject)
+
+    def PyClass_to_textual(self, pyobject):
+        return self._defined_to_textual(pyobject)
+
+    def _defined_to_textual(self, pyobject):
+        address = []
+        while pyobject.parent is not None:
+            address.insert(0, pyobject.get_name())
+            pyobject = pyobject.parent
+        return ('defined', self._get_pymodule_path(pyobject.get_module()),
+                '.'.join(address))
+
+    def PyModule_to_textual(self, pyobject):
+        return ('defined', self._get_pymodule_path(pyobject))
+
+    def PyPackage_to_textual(self, pyobject):
+        return ('defined', self._get_pymodule_path(pyobject))
+
+    def List_to_textual(self, pyobject):
+        return ('builtin', 'list', self.transform(pyobject.holding))
+
+    def Dict_to_textual(self, pyobject):
+        return ('builtin', 'dict', self.transform(pyobject.keys),
+                self.transform(pyobject.values))
+
+    def Tuple_to_textual(self, pyobject):
+        objects = [self.transform(holding)
+                   for holding in pyobject.get_holding_objects()]
+        return tuple(['builtin', 'tuple'] + objects)
+
+    def Set_to_textual(self, pyobject):
+        return ('builtin', 'set', self.transform(pyobject.holding))
+
+    def Iterator_to_textual(self, pyobject):
+        return ('builtin', 'iter', self.transform(pyobject.holding))
+
+    def Generator_to_textual(self, pyobject):
+        return ('builtin', 'generator', self.transform(pyobject.holding))
+
+    def Str_to_textual(self, pyobject):
+        return ('builtin', 'str')
+
+    def File_to_textual(self, pyobject):
+        return ('builtin', 'file')
+
+    def BuiltinFunction_to_textual(self, pyobject):
+        return ('builtin', 'function', pyobject.get_name())
+
+    def _get_pymodule_path(self, pymodule):
+        return self.resource_to_path(pymodule.get_resource())
+
+    def resource_to_path(self, resource):
+        if resource.project == self.project:
+            return resource.path
+        else:
+            return resource.real_path
+
+
+class TextualToPyObject(object):
+    """For transforming textual form to `PyObject`"""
+
+    def __init__(self, project, allow_in_project_absolutes=False):
+        self.project = project
+
+    def __call__(self, textual):
+        return self.transform(textual)
+
+    def transform(self, textual):
+        """Transform an object from textual form to `PyObject`"""
+        if textual is None:
+            return None
+        type = textual[0]
+        try:
+            method = getattr(self, type + '_to_pyobject')
+            return method(textual)
+        except AttributeError:
+            return None
+
+    def builtin_to_pyobject(self, textual):
+        method = getattr(self, 'builtin_%s_to_pyobject' % textual[1], None)
+        if method is not None:
+            return method(textual)
+
+    def builtin_str_to_pyobject(self, textual):
+        return rope.base.builtins.get_str()
+
+    def builtin_list_to_pyobject(self, textual):
+        holding = self.transform(textual[2])
+        return rope.base.builtins.get_list(holding)
+
+    def builtin_dict_to_pyobject(self, textual):
+        keys = self.transform(textual[2])
+        values = self.transform(textual[3])
+        return rope.base.builtins.get_dict(keys, values)
+
+    def builtin_tuple_to_pyobject(self, textual):
+        objects = []
+        for holding in textual[2:]:
+            objects.append(self.transform(holding))
+        return rope.base.builtins.get_tuple(*objects)
+
+    def builtin_set_to_pyobject(self, textual):
+        holding = self.transform(textual[2])
+        return rope.base.builtins.get_set(holding)
+
+    def builtin_iter_to_pyobject(self, textual):
+        holding = self.transform(textual[2])
+        return rope.base.builtins.get_iterator(holding)
+
+    def builtin_generator_to_pyobject(self, textual):
+        holding = self.transform(textual[2])
+        return rope.base.builtins.get_generator(holding)
+
+    def builtin_file_to_pyobject(self, textual):
+        return rope.base.builtins.get_file()
+
+    def builtin_function_to_pyobject(self, textual):
+        if textual[2] in rope.base.builtins.builtins:
+            return rope.base.builtins.builtins[textual[2]].get_object()
+
+    def unknown_to_pyobject(self, textual):
+        return None
+
+    def none_to_pyobject(self, textual):
+        return None
+
+    def _module_to_pyobject(self, textual):
+        path = textual[1]
+        return self._get_pymodule(path)
+
+    def _hierarchical_defined_to_pyobject(self, textual):
+        path = textual[1]
+        names = textual[2].split('.')
+        pymodule = self._get_pymodule(path)
+        pyobject = pymodule
+        for name in names:
+            if pyobject is None:
+                return None
+            if isinstance(pyobject, rope.base.pyobjects.PyDefinedObject):
+                try:
+                    pyobject = pyobject.get_scope()[name].get_object()
+                except exceptions.NameNotFoundError:
+                    return None
+            else:
+                return None
+        return pyobject
+
+    def defined_to_pyobject(self, textual):
+        if len(textual) == 2 or textual[2] == '':
+            return self._module_to_pyobject(textual)
+        else:
+            return self._hierarchical_defined_to_pyobject(textual)
+
+    def instance_to_pyobject(self, textual):
+        type = self.transform(textual[1])
+        if type is not None:
+            return rope.base.pyobjects.PyObject(type)
+
+    def _get_pymodule(self, path):
+        resource = self.path_to_resource(path)
+        if resource is not None:
+            return self.project.get_pymodule(resource)
+
+    def path_to_resource(self, path):
+        try:
+            root = self.project.address
+            if not os.path.isabs(path):
+                return self.project.get_resource(path)
+            if path == root or path.startswith(root + os.sep):
+                # INFO: This is a project file; should not be absolute
+                return None
+            import rope.base.project
+            return rope.base.project.get_no_project().get_resource(path)
+        except exceptions.ResourceNotFoundError:
+            return None
+
+
+class DOITextualToPyObject(TextualToPyObject):
+    """For transforming textual form to `PyObject`
+
+    The textual form DOI uses is different from rope's standard
+    textual form.  The reason is that we cannot find the needed
+    information by analyzing live objects.  This class can be
+    used to transform DOI textual form to `PyObject` and later
+    we can convert it to standard textual form using
+    `TextualToPyObject` class.
+
+    """
+
+    def _function_to_pyobject(self, textual):
+        path = textual[1]
+        lineno = int(textual[2])
+        pymodule = self._get_pymodule(path)
+        if pymodule is not None:
+            scope = pymodule.get_scope()
+            inner_scope = scope.get_inner_scope_for_line(lineno)
+            return inner_scope.pyobject
+
+    def _class_to_pyobject(self, textual):
+        path, name = textual[1:]
+        pymodule = self._get_pymodule(path)
+        if pymodule is None:
+            return None
+        module_scope = pymodule.get_scope()
+        suspected = None
+        if name in module_scope.get_names():
+            suspected = module_scope[name].get_object()
+        if suspected is not None and \
+           isinstance(suspected, rope.base.pyobjects.PyClass):
+            return suspected
+        else:
+            lineno = self._find_occurrence(name,
+                                           pymodule.get_resource().read())
+            if lineno is not None:
+                inner_scope = module_scope.get_inner_scope_for_line(lineno)
+                return inner_scope.pyobject
+
+    def defined_to_pyobject(self, textual):
+        if len(textual) == 2:
+            return self._module_to_pyobject(textual)
+        else:
+            if textual[2].isdigit():
+                result = self._function_to_pyobject(textual)
+            else:
+                result = self._class_to_pyobject(textual)
+            if not isinstance(result, rope.base.pyobjects.PyModule):
+                return result
+
+    def _find_occurrence(self, name, source):
+        pattern = re.compile(r'^\s*class\s*' + name + r'\b')
+        lines = source.split('\n')
+        for i in range(len(lines)):
+            if pattern.match(lines[i]):
+                return i + 1
+
+    def path_to_resource(self, path):
+        import rope.base.libutils
+        relpath = rope.base.libutils.path_relative_to_project_root(
+            self.project, path)
+        if relpath is not None:
+            path = relpath
+        return super(DOITextualToPyObject, self).path_to_resource(path)
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/__init__.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6e8722b217f5ea068c434366a8418b743a804caf
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/evaluate.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/evaluate.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..36cc9741faeb3f0fad49440dccdd47f55b6477a5
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/evaluate.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/factory.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/factory.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7f170d75b0678dbb2b346a69179a8e6f16a4da35
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/factory.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/interfaces.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/interfaces.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..04347dc43926fde2656b4ade1c7cd37ada5d65d0
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/interfaces.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/utils.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/utils.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6d833c25fec6bba308066c2da255fab18f0c1804
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/__pycache__/utils.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/evaluate.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/evaluate.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b82eb07968e5a1d723f03c2d27fbd1b3bab6df0
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/evaluate.py
@@ -0,0 +1,353 @@
+# Based on super lightweight Simple Top-Down Parser from http://effbot.org/zone/simple-top-down-parsing.htm
+# and https://bitbucket.org/emacsway/sqlbuilder/src/default/sqlbuilder/smartsql/contrib/evaluate.py
+import re
+from rope.base.utils import pycompat
+from rope.base.oi.type_hinting import utils
+from rope.base import utils as base_utils
+
+
+class SymbolBase(object):
+
+    name = None  # node/token type name
+
+    def __init__(self):
+        self.value = None  # used by name and literals
+        self.first = None
+        self.second = None
+        self.third = None  # used by tree nodes
+
+    def nud(self, parser):
+        raise SyntaxError(
+            "Syntax error (%r)." % self.name
+        )
+
+    def led(self, left, parser):
+        raise SyntaxError(
+            "Unknown operator (%r)." % self.name
+        )
+
+    def evaluate(self, pyobject):
+        raise NotImplementedError(self.name, self)
+
+    def __repr__(self):
+        if self.name == '(name)':
+            return "(%s %s)" % (self.name[1:-1], self.value)
+        out = [repr(self.name), self.first, self.second, self.third]
+        out = [str(i) for i in out if i]
+        return '(' + ' '.join(out) + ')'
+
+
+class SymbolTable(object):
+
+    def multi(func):
+        def _inner(self, names, *a, **kw):
+            for name in names.split():
+                func(self, name, *a, **kw)
+        return _inner
+
+    def __init__(self):
+        self.symbol_table = {}
+
+    def get(self, name, default=None):
+        return self.symbol_table.get(name, default)
+
+    def __getitem__(self, name):
+        return self.symbol_table[name]
+
+    def __iter__(self):
+        return iter(self.symbol_table)
+
+    def symbol(self, name, bp=0):
+        try:
+            s = self.symbol_table[name]
+        except KeyError:
+
+            class S(SymbolBase):
+                pass
+
+            s = S
+            s.__name__ = "symbol-" + name  # for debugging
+            s.name = name
+            s.lbp = bp
+            self.symbol_table[name] = s
+        else:
+            s.lbp = max(bp, s.lbp)
+        return s
+
+    @multi
+    def infix(self, name, bp):
+        symbol = self.symbol(name, bp)
+
+        @method(symbol)
+        def led(self, left, parser):
+            self.first = left
+            self.second = parser.expression(bp)
+            return self
+
+    @multi
+    def infix_r(self, name, bp):
+        symbol = self.symbol(name, bp)
+
+        @method(symbol)
+        def led(self, left, parser):
+            self.first = left
+            self.second = parser.expression(bp - 0.1)
+            return self
+
+    def ternary(self, name, name2, bp):
+        symbol = self.symbol(name, bp)
+        symbol2 = self.symbol(name2)
+
+        @method(symbol)
+        def led(self, left, parser):
+            self.first = left
+            self.second = parser.expression(symbol2.lbp)
+            parser.advance(symbol2.name)
+            self.third = parser.expression(symbol2.lbp + 0.1)
+            return self
+
+    @multi
+    def prefix(self, name, bp):
+        symbol = self.symbol(name, bp)
+
+        @method(symbol)
+        def nud(self, parser):
+            self.first = parser.expression(bp)
+            return self
+
+    @multi
+    def postfix(self, name, bp):
+        symbol = self.symbol(name, bp)
+
+        @method(symbol)
+        def led(self, left, parser):
+            self.first = left
+            return self
+
+    multi = staticmethod(multi)  # Just for code checker
+
+symbol_table = SymbolTable()
+
+
+class Lexer(object):
+
+    _token_pattern = re.compile(r"""
+        \s*
+        (?:
+              (
+                    [,()\[\]|]
+                  | ->
+                  | (?<=\s)(?:or)\b
+              )  # operator
+            | ([a-zA-Z](?:\w|\.)*)  # name
+        )
+        """, re.U | re.S | re.X)
+
+    def __init__(self, symbol_table):
+        self.symbol_table = symbol_table
+
+    def tokenize(self, program):
+        for name, value in self._tokenize_expr(program):
+            symbol = symbol_table.get(value)
+            if symbol:
+                s = symbol()
+            elif name == "(name)":
+                symbol = symbol_table[name]
+                s = symbol()
+                s.value = value
+            else:
+                raise SyntaxError("Unknown operator ({0}). Possible operators are {1!r}".format(
+                    value, list(self.symbol_table)
+                ))
+
+            yield s
+
+    def _tokenize_expr(self, program):
+        if isinstance(program, bytes):
+            program = program.decode('utf-8')
+        # import pprint; pprint.pprint(self._token_pattern.findall(program))
+        for operator, name in self._token_pattern.findall(program):
+            if operator:
+                yield '(operator)', operator
+            elif name:
+                yield '(name)', name
+            else:
+                raise SyntaxError
+        yield '(end)', '(end)'
+
+
+class Parser(object):
+
+    token = None
+    next = None
+
+    def __init__(self, lexer):
+        self.lexer = lexer
+
+    def parse(self, program):
+        generator = self.lexer.tokenize(program)
+        try:
+            self.next = generator.__next__  # PY3
+        except AttributeError:
+            self.next = generator.next
+        self.token = self.next()
+        return self.expression()
+
+    def expression(self, rbp=0):
+        t = self.token
+        self.token = self.next()
+        left = t.nud(self)
+        while rbp < self.token.lbp:
+            t = self.token
+            self.token = self.next()
+            left = t.led(left, self)
+        return left
+
+    def advance(self, name=None):
+        if name and self.token.name != name:
+            raise SyntaxError("Expected {0!r} but found {1!r}".format(name, self.token.name))
+        self.token = self.next()
+
+
+def method(s):
+    assert issubclass(s, SymbolBase)
+
+    def bind(fn):
+        setattr(s, fn.__name__, fn)
+        return fn
+
+    return bind
+
+symbol, infix, infix_r, prefix, postfix, ternary = (
+    symbol_table.symbol, symbol_table.infix, symbol_table.infix_r, symbol_table.prefix,
+    symbol_table.postfix, symbol_table.ternary
+)
+
+symbol('(', 270)
+symbol(')')
+symbol('[', 250)  # Parameters
+symbol(']')
+symbol('->', 230)
+infix('|', 170)
+infix('or', 170)
+symbol(',')
+
+symbol('(name)')
+symbol('(end)')
+
+
+@method(symbol('(name)'))
+def nud(self, parser):
+    return self
+
+
+@method(symbol('(name)'))
+def evaluate(self, pyobject):
+    return utils.resolve_type(self.value, pyobject)
+
+
+# Parametrized objects
+@method(symbol('['))
+def led(self, left, parser):
+    self.first = left
+    self.second = []
+    if parser.token.name != ']':
+        while 1:
+            if parser.token.name == ']':
+                break
+            self.second.append(parser.expression())
+            if parser.token.name != ',':
+                break
+            parser.advance(',')
+    parser.advance(']')
+    return self
+
+
+@method(symbol('['))
+def evaluate(self, pyobject):
+    return utils.parametrize_type(
+        self.first.evaluate(pyobject),
+        *[i.evaluate(pyobject) for i in self.second]
+    )
+
+
+# Anonymous Function Calls
+@method(symbol('('))
+def nud(self, parser):
+    self.second = []
+    if parser.token.name != ')':
+        while 1:
+            self.second.append(parser.expression())
+            if parser.token.name != ',':
+                break
+            parser.advance(',')
+    parser.advance(')')
+    parser.advance('->')
+    self.third = parser.expression(symbol('->').lbp + 0.1)
+    return self
+
+
+# Function Calls
+@method(symbol('('))
+def led(self, left, parser):
+    self.first = left
+    self.second = []
+    if parser.token.name != ')':
+        while 1:
+            self.second.append(parser.expression())
+            if parser.token.name != ',':
+                break
+            parser.advance(',')
+    parser.advance(')')
+    parser.advance('->')
+    self.third = parser.expression(symbol('->').lbp + 0.1)
+    return self
+
+
+@method(symbol('('))
+def evaluate(self, pyobject):
+    # TODO: Implement me
+    raise NotImplementedError
+
+
+@method(symbol('or'))
+@method(symbol('|'))
+def evaluate(self, pyobject):
+    # TODO: Implement me
+    raise  NotImplementedError
+
+
+class Compiler(object):
+
+    parser_factory = Parser
+    lexer_factory = Lexer
+    symbol_table = symbol_table
+
+    def _make_parser(self):
+        return self.parser_factory(self.lexer_factory(self.symbol_table))
+
+    @base_utils.cached(500)
+    def __call__(self, program):
+        """
+        :type program: str
+        :rtype: rope.base.oi.type_hinting.evaluate.SymbolBase
+        """
+        return self._make_parser().parse(program)
+
+compile = Compiler()
+
+
+class Evaluator(object):
+
+    compile = compile
+
+    def __call__(self, program, pyobject):
+        """Evaluates the program string or AST
+
+        :type program: str or rope.base.oi.type_hinting.evaluate.SymbolBase
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        ast = self.compile(program) if isinstance(program, pycompat.string_types) else program
+        return ast.evaluate(pyobject)
+
+evaluate = Evaluator()
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/factory.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/factory.py
new file mode 100644
index 0000000000000000000000000000000000000000..644d12c0325a00c7e41f7da2b8efaed72368f031
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/factory.py
@@ -0,0 +1,70 @@
+from rope.base.oi.type_hinting import interfaces
+from rope.base.oi.type_hinting.providers import (
+    composite, inheritance, docstrings, numpydocstrings, pep0484_type_comments
+)
+from rope.base.oi.type_hinting.resolvers import composite as composite_resolvers, types
+from rope.base import utils
+
+
+class TypeHintingFactory(interfaces.ITypeHintingFactory):
+
+    @utils.saveit
+    def make_param_provider(self):
+        providers = [
+            docstrings.ParamProvider(docstrings.DocstringParamParser(), self.make_resolver()),
+            docstrings.ParamProvider(numpydocstrings.NumPyDocstringParamParser(), self.make_resolver()),
+        ]
+        return inheritance.ParamProvider(composite.ParamProvider(*providers))
+
+    @utils.saveit
+    def make_return_provider(self):
+        providers = [
+            docstrings.ReturnProvider(docstrings.DocstringReturnParser(), self.make_resolver()),
+        ]
+        return inheritance.ReturnProvider(composite.ReturnProvider(*providers))
+
+    @utils.saveit
+    def make_assignment_provider(self):
+        providers = [
+            pep0484_type_comments.AssignmentProvider(self.make_resolver()),
+            docstrings.AssignmentProvider(docstrings.DocstringParamParser(), self.make_resolver()),
+            docstrings.AssignmentProvider(numpydocstrings.NumPyDocstringParamParser(), self.make_resolver()),
+        ]
+        return inheritance.AssignmentProvider(composite.AssignmentProvider(*providers))
+
+    @utils.saveit
+    def make_resolver(self):
+        """
+        :rtype: rope.base.oi.type_hinting.resolvers.interfaces.IResolver
+        """
+        resolvers = [
+            types.Resolver(),
+        ]
+        return composite_resolvers.Resolver(*resolvers)
+
+
+default_type_hinting_factory = TypeHintingFactory()
+
+
+class TypeHintingFactoryAccessor(object):
+
+    def __call__(self, project):
+        """
+        :type project: rope.base.project.Project
+        :rtype: rope.base.oi.type_hinting.interfaces.ITypeHintingFactory
+        """
+        factory_location = project.get_prefs().get(
+            'type_hinting_factory',
+            'rope.base.oi.type_hinting.factory.default_type_hinting_factory'
+        )
+        return self._get_factory(factory_location)
+
+    @utils.cached(10)
+    def _get_factory(self, factory_location):
+        """
+        :type factory_location: str
+        :rtype: rope.base.oi.type_hinting.interfaces.ITypeHintingFactory
+        """
+        return utils.resolve(factory_location)
+
+get_type_hinting_factory = TypeHintingFactoryAccessor()
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/interfaces.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/interfaces.py
new file mode 100644
index 0000000000000000000000000000000000000000..fc5568f32d53778757e335046cb05c36adf6652c
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/interfaces.py
@@ -0,0 +1,25 @@
+class ITypeHintingFactory(object):
+
+    def make_param_provider(self):
+        """
+        :rtype: rope.base.oi.type_hinting.providers.interfaces.IParamProvider
+        """
+        raise NotImplementedError
+
+    def make_return_provider(self):
+        """
+        :rtype: rope.base.oi.type_hinting.providers.interfaces.IReturnProvider
+        """
+        raise NotImplementedError
+
+    def make_assignment_provider(self):
+        """
+        :rtype: rope.base.oi.type_hinting.providers.interfaces.IAssignmentProvider
+        """
+        raise NotImplementedError
+
+    def make_resolver(self):
+        """
+        :rtype: rope.base.oi.type_hinting.resolvers.interfaces.IResolver
+        """
+        raise NotImplementedError
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__init__.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9fc6ccb5f6ef3f478885f46057b1bea9f2fb2940
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/composite.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/composite.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3f546796991bde41ebfbeeb2379bcc3fc68403ef
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/composite.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/docstrings.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/docstrings.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e08180ce9bc486dbd42ab9b11f6f9213fd989140
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/docstrings.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/inheritance.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/inheritance.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cf370bdc9b26a23422f2869efd3ca35eecc8ec44
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/inheritance.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/interfaces.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/interfaces.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..76b3d9d26425ad43a237f67123ca7f4940103b24
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/interfaces.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/numpydocstrings.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/numpydocstrings.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e0020fbb08ec117b265b10305d69edb860ae9aae
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/numpydocstrings.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/pep0484_type_comments.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/pep0484_type_comments.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5c327621b8975e2fb4a9c82fe8abce57393749fa
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/__pycache__/pep0484_type_comments.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/composite.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/composite.py
new file mode 100644
index 0000000000000000000000000000000000000000..34a9fae7b5fd212925ea3acd72fda9f9450d005c
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/composite.py
@@ -0,0 +1,59 @@
+from rope.base.oi.type_hinting.providers import interfaces
+
+
+class ParamProvider(interfaces.IParamProvider):
+
+    def __init__(self, *delegates):
+        """
+        :type delegates: list[rope.base.oi.type_hinting.providers.interfaces.IParamProvider]
+        """
+        self._delegates = delegates
+
+    def __call__(self, pyfunc, param_name):
+        """
+        :type pyfunc: rope.base.pyobjectsdef.PyFunction
+        :type param_name: str
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        for delegate in self._delegates:
+            result = delegate(pyfunc, param_name)
+            if result:
+                return result
+
+
+class ReturnProvider(interfaces.IReturnProvider):
+
+    def __init__(self, *delegates):
+        """
+        :type delegates: list[rope.base.oi.type_hinting.providers.interfaces.IReturnProvider]
+        """
+        self._delegates = delegates
+
+    def __call__(self, pyfunc):
+        """
+        :type pyfunc: rope.base.pyobjectsdef.PyFunction
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        for delegate in self._delegates:
+            result = delegate(pyfunc)
+            if result:
+                return result
+
+
+class AssignmentProvider(interfaces.IAssignmentProvider):
+
+    def __init__(self, *delegates):
+        """
+        :type delegates: list[rope.base.oi.type_hinting.providers.interfaces.IAssignmentProvider]
+        """
+        self._delegates = delegates
+
+    def __call__(self, pyname):
+        """
+        :type pyname: rope.base.pynamesdef.AssignedName
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        for delegate in self._delegates:
+            result = delegate(pyname)
+            if result:
+                return result
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/docstrings.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/docstrings.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d52e6fbfa93bf559238b1af7e46e36743f36310
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/docstrings.py
@@ -0,0 +1,193 @@
+"""
+Hinting the type using docstring of class/function.
+
+It's an irreplaceable thing if you are using Dependency Injection with passive class:
+http://www.martinfowler.com/articles/injection.html
+
+Some code extracted (or based on code) from:
+https://github.com/davidhalter/jedi/blob/b489019f5bd5750051122b94cc767df47751ecb7/jedi/evaluate/docstrings.py
+Thanks to @davidhalter for this utils under MIT License.
+
+Similar solutions:
+
+    - https://www.jetbrains.com/pycharm/help/type-hinting-in-pycharm.html
+    - https://www.python.org/dev/peps/pep-0484/#type-comments
+    - http://www.pydev.org/manual_adv_type_hints.html
+    - https://jedi.readthedocs.org/en/latest/docs/features.html#type-hinting
+
+Discussions:
+
+    - https://groups.google.com/d/topic/rope-dev/JlAzmZ83K1M/discussion
+    - https://groups.google.com/d/topic/rope-dev/LCFNN98vckI/discussion
+
+"""
+import re
+
+from rope.base.oi.type_hinting import utils
+from rope.base.oi.type_hinting.providers import interfaces
+
+
+class ParamProvider(interfaces.IParamProvider):
+
+    def __init__(self, docstring_parser, resolver):
+        """
+        :type docstring_parser: rope.base.oi.type_hinting.providers.docstrings.IParamParser
+        :type resolver: rope.base.oi.type_hinting.resolvers.interfaces.IResolver
+        """
+        self._parse_docstring = docstring_parser
+        self._resolve = resolver
+
+    def __call__(self, pyfunc, param_name):
+        """
+        :type pyfunc: rope.base.pyobjectsdef.PyFunction
+        :type param_name: str
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        type_strs = self._parse_docstring(pyfunc.get_doc(), param_name)
+        if type_strs:
+            return self._resolve(type_strs[0], pyfunc)
+
+
+class ReturnProvider(interfaces.IReturnProvider):
+
+    def __init__(self, docstring_parser, resolver):
+        """
+        :type docstring_parser: rope.base.oi.type_hinting.providers.docstrings.IReturnParser
+        :type resolver: rope.base.oi.type_hinting.resolvers.interfaces.IResolver
+        """
+        self._parse_docstring = docstring_parser
+        self._resolve = resolver
+
+    def __call__(self, pyfunc):
+        """
+        :type pyfunc: rope.base.pyobjectsdef.PyFunction
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        type_strs = self._parse_docstring(pyfunc.get_doc())
+        if type_strs:
+            return self._resolve(type_strs[0], pyfunc)
+
+
+class AssignmentProvider(interfaces.IAssignmentProvider):
+
+    def __init__(self, docstring_parser, resolver):
+        """
+        :type docstring_parser: rope.base.oi.type_hinting.providers.docstrings.IParamParser
+        :type resolver: rope.base.oi.type_hinting.resolvers.interfaces.IResolver
+        """
+        self._parse_docstring = docstring_parser
+        self._resolve = resolver
+
+    def __call__(self, pyname):
+        """
+        :type pyname: rope.base.pynamesdef.AssignedName
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        try:
+            pyclass, attr_name = utils.get_class_with_attr_name(pyname)
+        except TypeError:
+            return
+        else:
+            type_strs = self._parse_docstring(pyclass.get_doc(), attr_name)
+            if type_strs:
+                return self._resolve(type_strs[0], pyclass)
+
+
+class IParamParser(object):
+
+    def __call__(self, docstring, param_name):
+        """
+        :type docstring: str
+        :type param_name: str
+        """
+
+
+class IReturnParser(object):
+
+    def __call__(self, docstring):
+        """
+        :type docstring: str
+        """
+
+
+class DocstringParamParser(IParamParser):
+
+    DOCSTRING_PARAM_PATTERNS = [
+        r'\s*:type\s+%s:\s*([^\n]+)',  # Sphinx
+        r'\s*:param\s+(\w+)\s+%s:[^\n]+',  # Sphinx param with type
+        r'\s*@type\s+%s:\s*([^\n]+)',  # Epydoc
+    ]
+
+    def __init__(self):
+        self._strip_rst_role = RSTRoleStrip()
+
+    def __call__(self, docstring, param_name):
+        """Search `docstring` for type(-s) of `param_name`.
+
+        >>> DocstringParamParser()(':type param: int', 'param')
+        ['int']
+        >>> DocstringParamParser()('@type param: int', 'param')
+        ['int']
+        >>> DocstringParamParser()(':type param: :class:`threading.Thread`', 'param')
+        ['threading.Thread']
+        >>> bool(DocstringParamParser()('no document', 'param'))
+        False
+        >>> DocstringParamParser()(':param int param: some description', 'param')
+        ['int']
+        """
+        if not docstring:
+            return []
+        patterns = [re.compile(p % re.escape(param_name))
+                    for p in self.DOCSTRING_PARAM_PATTERNS]
+        for pattern in patterns:
+            match = pattern.search(docstring)
+            if match:
+                return [self._strip_rst_role(match.group(1))]
+
+        return []
+
+
+class DocstringReturnParser(IReturnParser):
+
+    DOCSTRING_RETURN_PATTERNS = [
+        re.compile(r'\s*:rtype:\s*([^\n]+)', re.M),  # Sphinx
+        re.compile(r'\s*@rtype:\s*([^\n]+)', re.M),  # Epydoc
+    ]
+
+    def __init__(self):
+        self._strip_rst_role = RSTRoleStrip()
+
+    def __call__(self, docstring):
+        if not docstring:
+            return []
+        for p in self.DOCSTRING_RETURN_PATTERNS:
+            match = p.search(docstring)
+            if match:
+                return [self._strip_rst_role(match.group(1))]
+        return []
+
+
+class RSTRoleStrip(object):
+
+    RST_ROLE_PATTERN = re.compile(r':[^`]+:`([^`]+)`')
+
+    def __call__(self, type_str):
+        """
+        Strip off the part looks like a ReST role in `type_str`.
+
+        >>> RSTRoleStrip()(':class:`ClassName`')  # strip off :class:
+        'ClassName'
+        >>> RSTRoleStrip()(':py:obj:`module.Object`')  # works with domain
+        'module.Object'
+        >>> RSTRoleStrip()('ClassName')  # do nothing when not ReST role
+        'ClassName'
+
+        See also:
+        http://sphinx-doc.org/domains.html#cross-referencing-python-objects
+
+        """
+        match = self.RST_ROLE_PATTERN.match(type_str)
+        if match:
+            return match.group(1)
+        else:
+            return type_str
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/inheritance.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/inheritance.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbefc43b8968ace9e9db30e389438fbbb3615702
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/inheritance.py
@@ -0,0 +1,66 @@
+from rope.base.oi.type_hinting import utils
+from rope.base.oi.type_hinting.providers import interfaces
+
+
+class ParamProvider(interfaces.IParamProvider):
+
+    def __init__(self, delegate):
+        """
+        :type delegate: rope.base.oi.type_hinting.providers.interfaces.IParamProvider
+        """
+        self._delegate = delegate
+
+    def __call__(self, pyfunc, param_name):
+        """
+        :type pyfunc: rope.base.pyobjectsdef.PyFunction
+        :type param_name: str
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        superfunc = pyfunc
+        while superfunc:
+            result = self._delegate(superfunc, param_name)
+            if result:
+                return result
+            superfunc = utils.get_super_func(superfunc)
+
+
+class ReturnProvider(interfaces.IReturnProvider):
+
+    def __init__(self, delegate):
+        """
+        :type delegate: rope.base.oi.type_hinting.providers.interfaces.IReturnProvider
+        """
+        self._delegate = delegate
+
+    def __call__(self, pyfunc):
+        """
+        :type pyfunc: rope.base.pyobjectsdef.PyFunction
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        superfunc = pyfunc
+        while superfunc:
+            result = self._delegate(superfunc)
+            if result:
+                return result
+            superfunc = utils.get_super_func(superfunc)
+
+
+class AssignmentProvider(interfaces.IAssignmentProvider):
+
+    def __init__(self, delegate):
+        """
+        :type delegate: rope.base.oi.type_hinting.providers.interfaces.IAssignmentProvider
+        """
+        self._delegate = delegate
+
+    def __call__(self, pyname):
+        """
+        :type pyname: rope.base.pynamesdef.AssignedName
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        super_pyname = pyname
+        while super_pyname:
+            result = self._delegate(super_pyname)
+            if result:
+                return result
+            super_pyname = utils.get_super_assignment(super_pyname)
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/interfaces.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/interfaces.py
new file mode 100644
index 0000000000000000000000000000000000000000..595cf82ca4c5ea855b070d48bbbe08a09939d5fe
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/interfaces.py
@@ -0,0 +1,37 @@
+class IParamProvider(object):
+
+    def __call__(self, pyfunc, param_name):
+        """
+        :type pyfunc: rope.base.pyobjectsdef.PyFunction
+        :type param_name: str
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        raise NotImplementedError
+
+
+class IReturnProvider(object):
+    """
+    :type resolve: rope.base.oi.type_hinting.resolvers.interfaces.IResolver
+    """
+    resolve = None
+
+    def __call__(self, pyfunc):
+        """
+        :type pyfunc: rope.base.pyobjectsdef.PyFunction
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        raise NotImplementedError
+
+
+class IAssignmentProvider(object):
+    """
+    :type resolve: rope.base.oi.type_hinting.resolvers.interfaces.IResolver
+    """
+    resolve = None
+
+    def __call__(self, pyname):
+        """
+        :type pyname: rope.base.pynamesdef.AssignedName
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        raise NotImplementedError
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/numpydocstrings.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/numpydocstrings.py
new file mode 100644
index 0000000000000000000000000000000000000000..74c05900a9f9ac438ce987b7e8fedc91697cf73a
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/numpydocstrings.py
@@ -0,0 +1,43 @@
+"""
+Some code extracted (or based on code) from:
+https://github.com/davidhalter/jedi/blob/b489019f5bd5750051122b94cc767df47751ecb7/jedi/evaluate/docstrings.py
+Thanks to @davidhalter for this utils under MIT License.
+"""
+import re
+from ast import literal_eval
+from rope.base.oi.type_hinting.providers import docstrings
+
+try:
+    from numpydoc.docscrape import NumpyDocString
+except ImportError:
+    NumpyDocString = None
+
+
+class NumPyDocstringParamParser(docstrings.IParamParser):
+
+    def __call__(self, docstring, param_name):
+        """Search `docstring` (in numpydoc format) for type(-s) of `param_name`."""
+        if not docstring:
+          return []
+        params = NumpyDocString(docstring)._parsed_data['Parameters']
+        for p_name, p_type, p_descr in params:
+            if p_name == param_name:
+                m = re.match('([^,]+(,[^,]+)*?)(,[ ]*optional)?$', p_type)
+                if m:
+                    p_type = m.group(1)
+
+                if p_type.startswith('{'):
+                    types = set(type(x).__name__ for x in literal_eval(p_type))
+                    return list(types)
+                else:
+                    return [p_type]
+        return []
+
+
+class _DummyParamParser(docstrings.IParamParser):
+    def __call__(self, docstring, param_name):
+        return []
+
+
+if not NumpyDocString:
+    NumPyDocstringParamParser = _DummyParamParser
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/pep0484_type_comments.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/pep0484_type_comments.py
new file mode 100644
index 0000000000000000000000000000000000000000..357d5906a5d2dd893e9d556d897b2dc73da54602
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/providers/pep0484_type_comments.py
@@ -0,0 +1,42 @@
+import re
+from rope.base.oi.type_hinting import utils
+from rope.base.oi.type_hinting.providers import interfaces
+
+
+class AssignmentProvider(interfaces.IAssignmentProvider):
+
+    def __init__(self, resolver):
+        """
+        :type resolver: rope.base.oi.type_hinting.resolvers.interfaces.IResolver
+        """
+        self._resolve = resolver
+
+    PEP0484_TYPE_COMMENT_PATTERNS = (
+        re.compile(r'type:\s*([^\n]+)'),
+    )
+
+    def __call__(self, pyname):
+        """
+        :type pyname: rope.base.pynamesdef.AssignedName
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        from rope.base.oi.soi import _get_lineno_for_node
+        lineno = _get_lineno_for_node(pyname.assignments[0].ast_node)
+        holding_scope = pyname.module.get_scope().get_inner_scope_for_line(lineno)
+        line = holding_scope._get_global_scope()._scope_finder.lines.get_line(lineno)
+        if '#' in line:
+            type_strs = self._search_type_in_type_comment(line.split('#', 1)[1])
+            if type_strs:
+                return self._resolve(type_strs[0], holding_scope.pyobject)
+
+    def _search_type_in_type_comment(self, code):
+        """ For more info see:
+        https://www.python.org/dev/peps/pep-0484/#type-comments
+
+        >>> AssignmentProvider()._search_type_in_type_comment('type: int')
+        ['int']
+        """
+        for p in self.PEP0484_TYPE_COMMENT_PATTERNS:
+            match = p.search(code)
+            if match:
+                return [match.group(1)]
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__init__.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7db9c7e001edb92b319be99f2bba9150b5fd5acb
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/composite.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/composite.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..83dc1c7f9c3000ae2f2dcd19bbe1706d89a6f573
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/composite.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/interfaces.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/interfaces.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..149839607b61820f2631ff8e1c9c6f8aa4a031d3
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/interfaces.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/types.cpython-37.pyc b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/types.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..eba5a9092e38ccc768c20464983b4c824e3b8ebb
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/__pycache__/types.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/composite.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/composite.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e331e48bafaf05978f7857e7d827da8bddb06fb
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/composite.py
@@ -0,0 +1,22 @@
+from rope.base.oi.type_hinting.resolvers import interfaces
+
+
+class Resolver(interfaces.IResolver):
+
+    def __init__(self, *delegates):
+        """
+        :type delegates: list[rope.base.oi.type_hinting.resolvers.interfaces.IResolver]
+        """
+        self._delegates = delegates
+
+    def __call__(self, hint, pyobject):
+        """
+        :param hint: For example "List[int]" or "(Foo, Bar) -> Baz" or simple "Foo"
+        :type hint: str
+        :type pyobject: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        for delegate in self._delegates:
+            result = delegate(hint, pyobject)
+            if result:
+                return result
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/interfaces.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/interfaces.py
new file mode 100644
index 0000000000000000000000000000000000000000..cfcff3d99ebda30b64512fb191bbacc3064dd50b
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/interfaces.py
@@ -0,0 +1,10 @@
+class IResolver(object):
+
+    def __call__(self, hint, pyobject):
+        """
+        :param hint: For example "List[int]" or "(Foo, Bar) -> Baz" or simple "Foo"
+        :type hint: str
+        :type pyobject: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        raise NotImplementedError
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/types.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/types.py
new file mode 100644
index 0000000000000000000000000000000000000000..252696a65a9e17cf0103d52ae25ec7cb42db4d69
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/resolvers/types.py
@@ -0,0 +1,16 @@
+from rope.base.oi.type_hinting import evaluate
+from rope.base.oi.type_hinting.resolvers import interfaces
+
+
+class Resolver(interfaces.IResolver):
+    def __call__(self, hint, pyobject):
+        """
+        :param hint: For example "List[int]" or "(Foo, Bar) -> Baz" or simple "Foo"
+        :type hint: str
+        :type pyobject: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        try:
+            return evaluate.evaluate(hint, pyobject)
+        except (Exception):
+            pass
diff --git a/venv/Lib/site-packages/rope/base/oi/type_hinting/utils.py b/venv/Lib/site-packages/rope/base/oi/type_hinting/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..aec82ac05132b7698d48c1bfef15e29254939bec
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/oi/type_hinting/utils.py
@@ -0,0 +1,136 @@
+import rope.base.builtins
+import rope.base.utils as base_utils
+from rope.base.evaluate import ScopeNameFinder
+from rope.base.exceptions import AttributeNotFoundError
+from rope.base.pyobjects import PyClass, PyFunction
+from rope.base.utils import pycompat
+
+
+def get_super_func(pyfunc):
+
+    if not isinstance(pyfunc.parent, PyClass):
+        return
+
+    for cls in get_mro(pyfunc.parent)[1:]:
+        try:
+            superfunc = cls.get_attribute(pyfunc.get_name()).get_object()
+        except AttributeNotFoundError:
+            pass
+        else:
+            if isinstance(superfunc, PyFunction):
+                return superfunc
+
+
+def get_super_assignment(pyname):
+    """
+    :type pyname: rope.base.pynamesdef.AssignedName
+    :type: rope.base.pynamesdef.AssignedName
+    """
+    try:
+        pyclass, attr_name = get_class_with_attr_name(pyname)
+    except TypeError:
+        return
+    else:
+        for super_pyclass in get_mro(pyclass)[1:]:
+            if attr_name in super_pyclass:
+                return super_pyclass[attr_name]
+
+
+def get_class_with_attr_name(pyname):
+    """
+    :type pyname: rope.base.pynamesdef.AssignedName
+    :return: rope.base.pyobjectsdef.PyClass, str
+    :rtype: tuple
+    """
+    lineno = get_lineno_for_node(pyname.assignments[0].ast_node)
+    holding_scope = pyname.module.get_scope().get_inner_scope_for_line(lineno)
+    pyobject = holding_scope.pyobject
+    if isinstance(pyobject, PyClass):
+        pyclass = pyobject
+    elif (isinstance(pyobject, PyFunction) and
+          isinstance(pyobject.parent, PyClass)):
+        pyclass = pyobject.parent
+    else:
+        return
+    for name, attr in pyclass.get_attributes().items():
+        if attr is pyname:
+            return (pyclass, name)
+
+
+def get_lineno_for_node(assign_node):
+    if hasattr(assign_node, 'lineno') and \
+       assign_node.lineno is not None:
+        return assign_node.lineno
+    return 1
+
+
+def get_mro(pyclass):
+    # FIXME: to use real mro() result
+    l = [pyclass]
+    for cls in l:
+        for super_cls in cls.get_superclasses():
+            if isinstance(super_cls, PyClass) and super_cls not in l:
+                l.append(super_cls)
+    return l
+
+
+def resolve_type(type_name, pyobject):
+    """
+    :type type_name: str
+    :type pyobject: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject
+    :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+    """
+    if '.' not in type_name:
+        try:
+            return pyobject.get_module().get_scope().get_name(type_name).get_object()
+        except Exception:
+            pass
+    else:
+        mod_name, attr_name = type_name.rsplit('.', 1)
+        try:
+            mod_finder = ScopeNameFinder(pyobject.get_module())
+            mod = mod_finder._find_module(mod_name).get_object()
+            return mod.get_attribute(attr_name).get_object()
+        except Exception:
+            pass
+
+
+class ParametrizeType(object):
+
+    _supported_mapping = {
+        'builtins.list': 'rope.base.builtins.get_list',
+        'builtins.tuple': 'rope.base.builtins.get_tuple',
+        'builtins.set': 'rope.base.builtins.get_set',
+        'builtins.dict': 'rope.base.builtins.get_dict',
+        '_collections_abc.Iterable': 'rope.base.builtins.get_iterator',
+        '_collections_abc.Iterator': 'rope.base.builtins.get_iterator',
+        'collections.abc.Iterable': 'rope.base.builtins.get_iterator',  # Python3.3
+        'collections.abc.Iterator': 'rope.base.builtins.get_iterator',  # Python3.3
+    }
+    if pycompat.PY2:
+        _supported_mapping = dict((
+            (k.replace('builtins.', '__builtin__.').replace('_collections_abc.', '_abcoll.'), v)
+            for k, v in _supported_mapping.items()
+        ))
+
+    def __call__(self, pyobject, *args, **kwargs):
+        """
+        :type pyobject: rope.base.pyobjects.PyObject
+        :rtype: rope.base.pyobjects.PyDefinedObject | rope.base.pyobjects.PyObject or None
+        """
+        type_factory = self._get_type_factory(pyobject)
+        if type_factory:
+            parametrized_type = type_factory(*args, **kwargs)
+            if parametrized_type:
+                return parametrized_type
+        return pyobject
+
+    def _get_type_factory(self, pyobject):
+        type_str = '{0}.{1}'.format(
+            pyobject.get_module().get_name(),
+            pyobject.get_name(),
+        )
+        if type_str in self._supported_mapping:
+            return base_utils.resolve(self._supported_mapping[type_str])
+
+parametrize_type = ParametrizeType()
diff --git a/venv/Lib/site-packages/rope/base/prefs.py b/venv/Lib/site-packages/rope/base/prefs.py
new file mode 100644
index 0000000000000000000000000000000000000000..2ab45dac541d9ef4150b81dcc65b7af08db770ca
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/prefs.py
@@ -0,0 +1,41 @@
+class Prefs(object):
+
+    def __init__(self):
+        self.prefs = {}
+        self.callbacks = {}
+
+    def set(self, key, value):
+        """Set the value of `key` preference to `value`."""
+        if key in self.callbacks:
+            self.callbacks[key](value)
+        else:
+            self.prefs[key] = value
+
+    def add(self, key, value):
+        """Add an entry to a list preference
+
+        Add `value` to the list of entries for the `key` preference.
+
+        """
+        if not key in self.prefs:
+            self.prefs[key] = []
+        self.prefs[key].append(value)
+
+    def get(self, key, default=None):
+        """Get the value of the key preference"""
+        return self.prefs.get(key, default)
+
+    def add_callback(self, key, callback):
+        """Add `key` preference with `callback` function
+
+        Whenever `key` is set the callback is called with the
+        given `value` as parameter.
+
+        """
+        self.callbacks[key] = callback
+
+    def __setitem__(self, key, value):
+        self.set(key, value)
+
+    def __getitem__(self, key):
+        return self.get(key)
diff --git a/venv/Lib/site-packages/rope/base/project.py b/venv/Lib/site-packages/rope/base/project.py
new file mode 100644
index 0000000000000000000000000000000000000000..2502b3ea2f447548d97dd09a35a1e3e85f04e485
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/project.py
@@ -0,0 +1,491 @@
+import os
+import shutil
+import sys
+import warnings
+
+import rope.base.fscommands
+import rope.base.resourceobserver as resourceobserver
+import rope.base.utils.pycompat as pycompat
+from rope.base import exceptions, taskhandle, prefs, history, pycore, utils
+from rope.base.exceptions import ModuleNotFoundError
+from rope.base.resources import File, Folder, _ResourceMatcher
+
+try:
+    import cPickle as pickle
+except ImportError:
+    import pickle
+
+
+class _Project(object):
+
+    def __init__(self, fscommands):
+        self.observers = []
+        self.fscommands = fscommands
+        self.prefs = prefs.Prefs()
+        self.data_files = _DataFiles(self)
+        self._custom_source_folders = []
+
+    def get_resource(self, resource_name):
+        """Get a resource in a project.
+
+        `resource_name` is the path of a resource in a project.  It is
+        the path of a resource relative to project root.  Project root
+        folder address is an empty string.  If the resource does not
+        exist a `exceptions.ResourceNotFound` exception would be
+        raised.  Use `get_file()` and `get_folder()` when you need to
+        get nonexistent `Resource`\s.
+
+        """
+        path = self._get_resource_path(resource_name)
+        if not os.path.exists(path):
+            raise exceptions.ResourceNotFoundError(
+                'Resource <%s> does not exist' % resource_name)
+        elif os.path.isfile(path):
+            return File(self, resource_name)
+        elif os.path.isdir(path):
+            return Folder(self, resource_name)
+        else:
+            raise exceptions.ResourceNotFoundError('Unknown resource '
+                                                   + resource_name)
+
+    def get_module(self, name, folder=None):
+        """Returns a `PyObject` if the module was found."""
+        # check if this is a builtin module
+        pymod = self.pycore.builtin_module(name)
+        if pymod is not None:
+            return pymod
+        module = self.find_module(name, folder)
+        if module is None:
+            raise ModuleNotFoundError('Module %s not found' % name)
+        return self.pycore.resource_to_pyobject(module)
+
+    def get_python_path_folders(self):
+        result = []
+        for src in self.prefs.get('python_path', []) + sys.path:
+            try:
+                src_folder = get_no_project().get_resource(src)
+                result.append(src_folder)
+            except exceptions.ResourceNotFoundError:
+                pass
+        return result
+
+    # INFO: It was decided not to cache source folders, since:
+    #  - Does not take much time when the root folder contains
+    #    packages, that is most of the time
+    #  - We need a separate resource observer; `self.observer`
+    #    does not get notified about module and folder creations
+    def get_source_folders(self):
+        """Returns project source folders"""
+        if self.root is None:
+            return []
+        result = list(self._custom_source_folders)
+        result.extend(self.pycore._find_source_folders(self.root))
+        return result
+
+    def validate(self, folder):
+        """Validate files and folders contained in this folder
+
+        It validates all of the files and folders contained in this
+        folder if some observers are interested in them.
+
+        """
+        for observer in list(self.observers):
+            observer.validate(folder)
+
+    def add_observer(self, observer):
+        """Register a `ResourceObserver`
+
+        See `FilteredResourceObserver`.
+        """
+        self.observers.append(observer)
+
+    def remove_observer(self, observer):
+        """Remove a registered `ResourceObserver`"""
+        if observer in self.observers:
+            self.observers.remove(observer)
+
+    def do(self, changes, task_handle=taskhandle.NullTaskHandle()):
+        """Apply the changes in a `ChangeSet`
+
+        Most of the time you call this function for committing the
+        changes for a refactoring.
+        """
+        self.history.do(changes, task_handle=task_handle)
+
+    def get_pymodule(self, resource, force_errors=False):
+        return self.pycore.resource_to_pyobject(resource, force_errors)
+
+    def get_pycore(self):
+        return self.pycore
+
+    def get_file(self, path):
+        """Get the file with `path` (it may not exist)"""
+        return File(self, path)
+
+    def get_folder(self, path):
+        """Get the folder with `path` (it may not exist)"""
+        return Folder(self, path)
+
+    def get_prefs(self):
+        return self.prefs
+
+    def get_relative_module(self, name, folder, level):
+        module = self.find_relative_module(name, folder, level)
+        if module is None:
+            raise ModuleNotFoundError('Module %s not found' % name)
+        return self.pycore.resource_to_pyobject(module)
+
+    def find_module(self, modname, folder=None):
+        """Returns a resource corresponding to the given module
+
+        returns None if it can not be found
+        """
+        for src in self.get_source_folders():
+            module = _find_module_in_folder(src, modname)
+            if module is not None:
+                return module
+        for src in self.get_python_path_folders():
+            module = _find_module_in_folder(src, modname)
+            if module is not None:
+                return module
+        if folder is not None:
+            module = _find_module_in_folder(folder, modname)
+            if module is not None:
+                return module
+        return None
+
+    def find_relative_module(self, modname, folder, level):
+        for i in range(level - 1):
+            folder = folder.parent
+        if modname == '':
+            return folder
+        else:
+            return _find_module_in_folder(folder, modname)
+
+    def is_ignored(self, resource):
+        return False
+
+    def _get_resource_path(self, name):
+        pass
+
+    @property
+    @utils.saveit
+    def history(self):
+        return history.History(self)
+
+    @property
+    @utils.saveit
+    def pycore(self):
+        return pycore.PyCore(self)
+
+    def close(self):
+        warnings.warn('Cannot close a NoProject',
+                      DeprecationWarning, stacklevel=2)
+
+    ropefolder = None
+
+
+class Project(_Project):
+    """A Project containing files and folders"""
+
+    def __init__(self, projectroot, fscommands=None,
+                 ropefolder='.ropeproject', **prefs):
+        """A rope project
+
+        :parameters:
+            - `projectroot`: The address of the root folder of the project
+            - `fscommands`: Implements the file system operations used
+              by rope; have a look at `rope.base.fscommands`
+            - `ropefolder`: The name of the folder in which rope stores
+              project configurations and data.  Pass `None` for not using
+              such a folder at all.
+            - `prefs`: Specify project preferences.  These values
+              overwrite config file preferences.
+
+        """
+        if projectroot != '/':
+            projectroot = _realpath(projectroot).rstrip('/\\')
+        self._address = projectroot
+        self._ropefolder_name = ropefolder
+        if not os.path.exists(self._address):
+            os.mkdir(self._address)
+        elif not os.path.isdir(self._address):
+            raise exceptions.RopeError('Project root exists and'
+                                       ' is not a directory')
+        if fscommands is None:
+            fscommands = rope.base.fscommands.create_fscommands(self._address)
+        super(Project, self).__init__(fscommands)
+        self.ignored = _ResourceMatcher()
+        self.file_list = _FileListCacher(self)
+        self.prefs.add_callback('ignored_resources', self.ignored.set_patterns)
+        if ropefolder is not None:
+            self.prefs['ignored_resources'] = [ropefolder]
+        self._init_prefs(prefs)
+        self._init_source_folders()
+
+    @utils.deprecated('Delete once deprecated functions are gone')
+    def _init_source_folders(self):
+        for path in self.prefs.get('source_folders', []):
+            folder = self.get_resource(path)
+            self._custom_source_folders.append(folder)
+
+    def get_files(self):
+        return self.file_list.get_files()
+
+    def get_python_files(self):
+        """Returns all python files available in the project"""
+        return [resource for resource in self.get_files()
+                if self.pycore.is_python_file(resource)]
+
+    def _get_resource_path(self, name):
+        return os.path.join(self._address, *name.split('/'))
+
+    def _init_ropefolder(self):
+        if self.ropefolder is not None:
+            if not self.ropefolder.exists():
+                self._create_recursively(self.ropefolder)
+            if not self.ropefolder.has_child('config.py'):
+                config = self.ropefolder.create_file('config.py')
+                config.write(self._default_config())
+
+    def _create_recursively(self, folder):
+        if folder.parent != self.root and not folder.parent.exists():
+            self._create_recursively(folder.parent)
+        folder.create()
+
+    def _init_prefs(self, prefs):
+        run_globals = {}
+        if self.ropefolder is not None:
+            config = self.get_file(self.ropefolder.path + '/config.py')
+            run_globals.update({'__name__': '__main__',
+                                '__builtins__': __builtins__,
+                                '__file__': config.real_path})
+            if config.exists():
+                config = self.ropefolder.get_child('config.py')
+                pycompat.execfile(config.real_path, run_globals)
+            else:
+                exec(self._default_config(), run_globals)
+            if 'set_prefs' in run_globals:
+                run_globals['set_prefs'](self.prefs)
+        for key, value in prefs.items():
+            self.prefs[key] = value
+        self._init_other_parts()
+        self._init_ropefolder()
+        if 'project_opened' in run_globals:
+            run_globals['project_opened'](self)
+
+    def _default_config(self):
+        import rope.base.default_config
+        import inspect
+        return inspect.getsource(rope.base.default_config)
+
+    def _init_other_parts(self):
+        # Forcing the creation of `self.pycore` to register observers
+        self.pycore
+
+    def is_ignored(self, resource):
+        return self.ignored.does_match(resource)
+
+    def sync(self):
+        """Closes project open resources"""
+        self.close()
+
+    def close(self):
+        """Closes project open resources"""
+        self.data_files.write()
+
+    def set(self, key, value):
+        """Set the `key` preference to `value`"""
+        self.prefs.set(key, value)
+
+    @property
+    def ropefolder(self):
+        if self._ropefolder_name is not None:
+            return self.get_folder(self._ropefolder_name)
+
+    def validate(self, folder=None):
+        if folder is None:
+            folder = self.root
+        super(Project, self).validate(folder)
+
+    root = property(lambda self: self.get_resource(''))
+    address = property(lambda self: self._address)
+
+
+class NoProject(_Project):
+    """A null object for holding out of project files.
+
+    This class is singleton use `get_no_project` global function
+    """
+
+    def __init__(self):
+        fscommands = rope.base.fscommands.FileSystemCommands()
+        super(NoProject, self).__init__(fscommands)
+
+    def _get_resource_path(self, name):
+        real_name = name.replace('/', os.path.sep)
+        return _realpath(real_name)
+
+    def get_resource(self, name):
+        universal_name = _realpath(name).replace(os.path.sep, '/')
+        return super(NoProject, self).get_resource(universal_name)
+
+    def get_files(self):
+        return []
+
+    def get_python_files(self):
+        return []
+
+    _no_project = None
+
+
+def get_no_project():
+    if NoProject._no_project is None:
+        NoProject._no_project = NoProject()
+    return NoProject._no_project
+
+
+class _FileListCacher(object):
+
+    def __init__(self, project):
+        self.project = project
+        self.files = None
+        rawobserver = resourceobserver.ResourceObserver(
+            self._changed, self._invalid, self._invalid,
+            self._invalid, self._invalid)
+        self.project.add_observer(rawobserver)
+
+    def get_files(self):
+        if self.files is None:
+            self.files = set()
+            self._add_files(self.project.root)
+        return self.files
+
+    def _add_files(self, folder):
+        for child in folder.get_children():
+            if child.is_folder():
+                self._add_files(child)
+            elif not self.project.is_ignored(child):
+                self.files.add(child)
+
+    def _changed(self, resource):
+        if resource.is_folder():
+            self.files = None
+
+    def _invalid(self, resource, new_resource=None):
+        self.files = None
+
+
+class _DataFiles(object):
+
+    def __init__(self, project):
+        self.project = project
+        self.hooks = []
+
+    def read_data(self, name, compress=False, import_=False):
+        if self.project.ropefolder is None:
+            return None
+        compress = compress and self._can_compress()
+        opener = self._get_opener(compress)
+        file = self._get_file(name, compress)
+        if not compress and import_:
+            self._import_old_files(name)
+        if file.exists():
+            input = opener(file.real_path, 'rb')
+            try:
+                result = []
+                try:
+                    while True:
+                        result.append(pickle.load(input))
+                except EOFError:
+                    pass
+                if len(result) == 1:
+                    return result[0]
+                if len(result) > 1:
+                    return result
+            finally:
+                input.close()
+
+    def write_data(self, name, data, compress=False):
+        if self.project.ropefolder is not None:
+            compress = compress and self._can_compress()
+            file = self._get_file(name, compress)
+            opener = self._get_opener(compress)
+            output = opener(file.real_path, 'wb')
+            try:
+                pickle.dump(data, output, 2)
+            finally:
+                output.close()
+
+    def add_write_hook(self, hook):
+        self.hooks.append(hook)
+
+    def write(self):
+        for hook in self.hooks:
+            hook()
+
+    def _can_compress(self):
+        try:
+            import gzip  # noqa
+            return True
+        except ImportError:
+            return False
+
+    def _import_old_files(self, name):
+        old = self._get_file(name + '.pickle', False)
+        new = self._get_file(name, False)
+        if old.exists() and not new.exists():
+            shutil.move(old.real_path, new.real_path)
+
+    def _get_opener(self, compress):
+        if compress:
+            try:
+                import gzip
+                return gzip.open
+            except ImportError:
+                pass
+        return open
+
+    def _get_file(self, name, compress):
+        path = self.project.ropefolder.path + '/' + name
+        if compress:
+            path += '.gz'
+        return self.project.get_file(path)
+
+
+def _realpath(path):
+    """Return the real path of `path`
+
+    Is equivalent to ``realpath(abspath(expanduser(path)))``.
+
+    Of the particular notice is the hack dealing with the unfortunate
+    sitaution of running native-Windows python (os.name == 'nt') inside
+    of Cygwin (abspath starts with '/'), which apparently normal
+    os.path.realpath completely messes up.
+
+    """
+    # there is a bug in cygwin for os.path.abspath() for abs paths
+    if sys.platform == 'cygwin':
+        if path[1:3] == ':\\':
+            return path
+        elif path[1:3] == ':/':
+            path = "/cygdrive/" + path[0] + path[2:]
+        return os.path.abspath(os.path.expanduser(path))
+    return os.path.realpath(os.path.abspath(os.path.expanduser(path)))
+
+
+def _find_module_in_folder(folder, modname):
+    module = folder
+    packages = modname.split('.')
+    for pkg in packages[:-1]:
+        if module.is_folder() and module.has_child(pkg):
+            module = module.get_child(pkg)
+        else:
+            return None
+    if module.is_folder():
+        if module.has_child(packages[-1]) and \
+           module.get_child(packages[-1]).is_folder():
+            return module.get_child(packages[-1])
+        elif module.has_child(packages[-1] + '.py') and \
+                not module.get_child(packages[-1] + '.py').is_folder():
+            return module.get_child(packages[-1] + '.py')
diff --git a/venv/Lib/site-packages/rope/base/pycore.py b/venv/Lib/site-packages/rope/base/pycore.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4c1195a4d7ef5ee471655a4e5d97bb2b5836d3d
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/pycore.py
@@ -0,0 +1,346 @@
+import bisect
+import difflib
+import sys
+import warnings
+
+import rope.base.libutils
+import rope.base.resourceobserver
+import rope.base.resources
+import rope.base.oi.doa
+import rope.base.oi.objectinfo
+import rope.base.oi.soa
+from rope.base import builtins
+from rope.base import exceptions
+from rope.base import stdmods
+from rope.base import taskhandle
+from rope.base import utils
+from rope.base.exceptions import ModuleNotFoundError
+from rope.base.pyobjectsdef import PyModule, PyPackage
+
+
+class PyCore(object):
+
+    def __init__(self, project):
+        self.project = project
+        self._init_resource_observer()
+        self.cache_observers = []
+        self.module_cache = _ModuleCache(self)
+        self.extension_cache = _ExtensionCache(self)
+        self.object_info = rope.base.oi.objectinfo.ObjectInfoManager(project)
+        self._init_python_files()
+        self._init_automatic_soa()
+
+    def _init_python_files(self):
+        self.python_matcher = None
+        patterns = self.project.prefs.get('python_files', None)
+        if patterns is not None:
+            self.python_matcher = rope.base.resources._ResourceMatcher()
+            self.python_matcher.set_patterns(patterns)
+
+    def _init_resource_observer(self):
+        callback = self._invalidate_resource_cache
+        observer = rope.base.resourceobserver.ResourceObserver(
+            changed=callback, moved=callback, removed=callback)
+        self.observer = \
+            rope.base.resourceobserver.FilteredResourceObserver(observer)
+        self.project.add_observer(self.observer)
+
+    def _init_automatic_soa(self):
+        if not self.automatic_soa:
+            return
+        callback = self._file_changed_for_soa
+        observer = rope.base.resourceobserver.ResourceObserver(
+            changed=callback, moved=callback, removed=callback)
+        self.project.add_observer(observer)
+
+    @property
+    def automatic_soa(self):
+        auto_soa = self.project.prefs.get('automatic_soi', None)
+        return self.project.prefs.get('automatic_soa', auto_soa)
+
+    def _file_changed_for_soa(self, resource, new_resource=None):
+        old_contents = self.project.history.\
+            contents_before_current_change(resource)
+        if old_contents is not None:
+            perform_soa_on_changed_scopes(self.project, resource, old_contents)
+
+    def is_python_file(self, resource):
+        if resource.is_folder():
+            return False
+        if self.python_matcher is None:
+            return resource.name.endswith('.py')
+        return self.python_matcher.does_match(resource)
+
+    @utils.deprecated('Use `project.get_module` instead')
+    def get_module(self, name, folder=None):
+        """Returns a `PyObject` if the module was found."""
+        return self.project.get_module(name, folder)
+
+    def _builtin_submodules(self, modname):
+        result = {}
+        for extension in self.extension_modules:
+            if extension.startswith(modname + '.'):
+                name = extension[len(modname) + 1:]
+                if '.' not in name:
+                    result[name] = self.builtin_module(extension)
+        return result
+
+    def builtin_module(self, name):
+        return self.extension_cache.get_pymodule(name)
+
+    @utils.deprecated('Use `project.get_relative_module` instead')
+    def get_relative_module(self, name, folder, level):
+        return self.project.get_relative_module(name, folder, level)
+
+    @utils.deprecated('Use `libutils.get_string_module` instead')
+    def get_string_module(self, code, resource=None, force_errors=False):
+        """Returns a `PyObject` object for the given code
+
+        If `force_errors` is `True`, `exceptions.ModuleSyntaxError` is
+        raised if module has syntax errors.  This overrides
+        ``ignore_syntax_errors`` project config.
+
+        """
+        return PyModule(self, code, resource, force_errors=force_errors)
+
+    @utils.deprecated('Use `libutils.get_string_scope` instead')
+    def get_string_scope(self, code, resource=None):
+        """Returns a `Scope` object for the given code"""
+        return rope.base.libutils.get_string_scope(code, resource)
+
+    def _invalidate_resource_cache(self, resource, new_resource=None):
+        for observer in self.cache_observers:
+            observer(resource)
+
+    @utils.deprecated('Use `project.get_python_path_folders` instead')
+    def get_python_path_folders(self):
+        return self.project.get_python_path_folders()
+
+    @utils.deprecated('Use `project.find_module` instead')
+    def find_module(self, modname, folder=None):
+        """Returns a resource corresponding to the given module
+
+        returns None if it can not be found
+        """
+        return self.project.find_module(modname, folder)
+
+    @utils.deprecated('Use `project.find_relative_module` instead')
+    def find_relative_module(self, modname, folder, level):
+        return self.project.find_relative_module(modname, folder, level)
+
+    # INFO: It was decided not to cache source folders, since:
+    #  - Does not take much time when the root folder contains
+    #    packages, that is most of the time
+    #  - We need a separate resource observer; `self.observer`
+    #    does not get notified about module and folder creations
+    @utils.deprecated('Use `project.get_source_folders` instead')
+    def get_source_folders(self):
+        """Returns project source folders"""
+        return self.project.get_source_folders()
+
+    def resource_to_pyobject(self, resource, force_errors=False):
+        return self.module_cache.get_pymodule(resource, force_errors)
+
+    @utils.deprecated('Use `project.get_python_files` instead')
+    def get_python_files(self):
+        """Returns all python files available in the project"""
+        return self.project.get_python_files()
+
+    def _is_package(self, folder):
+        if folder.has_child('__init__.py') and \
+           not folder.get_child('__init__.py').is_folder():
+            return True
+        else:
+            return False
+
+    def _find_source_folders(self, folder):
+        for resource in folder.get_folders():
+            if self._is_package(resource):
+                return [folder]
+        result = []
+        for resource in folder.get_files():
+            if resource.name.endswith('.py'):
+                result.append(folder)
+                break
+        for resource in folder.get_folders():
+            result.extend(self._find_source_folders(resource))
+        return result
+
+    def run_module(self, resource, args=None, stdin=None, stdout=None):
+        """Run `resource` module
+
+        Returns a `rope.base.oi.doa.PythonFileRunner` object for
+        controlling the process.
+
+        """
+        perform_doa = self.project.prefs.get('perform_doi', True)
+        perform_doa = self.project.prefs.get('perform_doa', perform_doa)
+        receiver = self.object_info.doa_data_received
+        if not perform_doa:
+            receiver = None
+        runner = rope.base.oi.doa.PythonFileRunner(
+            self, resource, args, stdin, stdout, receiver)
+        runner.add_finishing_observer(self.module_cache.forget_all_data)
+        runner.run()
+        return runner
+
+    def analyze_module(self, resource, should_analyze=lambda py: True,
+                       search_subscopes=lambda py: True, followed_calls=None):
+        """Analyze `resource` module for static object inference
+
+        This function forces rope to analyze this module to collect
+        information about function calls.  `should_analyze` is a
+        function that is called with a `PyDefinedObject` argument.  If
+        it returns `True` the element is analyzed.  If it is `None` or
+        returns `False` the element is not analyzed.
+
+        `search_subscopes` is like `should_analyze`; The difference is
+        that if it returns `False` the sub-scopes are all ignored.
+        That is it is assumed that `should_analyze` returns `False`
+        for all of its subscopes.
+
+        `followed_calls` override the value of ``soa_followed_calls``
+        project config.
+        """
+        if followed_calls is None:
+            followed_calls = self.project.prefs.get('soa_followed_calls', 0)
+        pymodule = self.resource_to_pyobject(resource)
+        self.module_cache.forget_all_data()
+        rope.base.oi.soa.analyze_module(
+            self, pymodule, should_analyze, search_subscopes, followed_calls)
+
+    def get_classes(self, task_handle=taskhandle.NullTaskHandle()):
+        warnings.warn('`PyCore.get_classes()` is deprecated',
+                      DeprecationWarning, stacklevel=2)
+        return []
+
+    def __str__(self):
+        return str(self.module_cache) + str(self.object_info)
+
+    @utils.deprecated('Use `libutils.modname` instead')
+    def modname(self, resource):
+        return rope.base.libutils.modname(resource)
+
+    @property
+    @utils.cacheit
+    def extension_modules(self):
+        result = set(self.project.prefs.get('extension_modules', []))
+        if self.project.prefs.get('import_dynload_stdmods', False):
+            result.update(stdmods.dynload_modules())
+        return result
+
+
+class _ModuleCache(object):
+
+    def __init__(self, pycore):
+        self.pycore = pycore
+        self.module_map = {}
+        self.pycore.cache_observers.append(self._invalidate_resource)
+        self.observer = self.pycore.observer
+
+    def _invalidate_resource(self, resource):
+        if resource in self.module_map:
+            self.forget_all_data()
+            self.observer.remove_resource(resource)
+            del self.module_map[resource]
+
+    def get_pymodule(self, resource, force_errors=False):
+        if resource in self.module_map:
+            return self.module_map[resource]
+        if resource.is_folder():
+            result = PyPackage(self.pycore, resource,
+                               force_errors=force_errors)
+        else:
+            result = PyModule(self.pycore, resource=resource,
+                              force_errors=force_errors)
+            if result.has_errors:
+                return result
+        self.module_map[resource] = result
+        self.observer.add_resource(resource)
+        return result
+
+    def forget_all_data(self):
+        for pymodule in self.module_map.values():
+            pymodule._forget_concluded_data()
+
+    def __str__(self):
+        return 'PyCore caches %d PyModules\n' % len(self.module_map)
+
+
+class _ExtensionCache(object):
+
+    def __init__(self, pycore):
+        self.pycore = pycore
+        self.extensions = {}
+
+    def get_pymodule(self, name):
+        if name == '__builtin__':
+            return builtins.builtins
+        allowed = self.pycore.extension_modules
+        if name not in self.extensions and name in allowed:
+            self.extensions[name] = builtins.BuiltinModule(name, self.pycore)
+        return self.extensions.get(name)
+
+
+def perform_soa_on_changed_scopes(project, resource, old_contents):
+    pycore = project.pycore
+    if resource.exists() and pycore.is_python_file(resource):
+        try:
+            new_contents = resource.read()
+            # detecting changes in new_contents relative to old_contents
+            detector = _TextChangeDetector(new_contents, old_contents)
+
+            def search_subscopes(pydefined):
+                scope = pydefined.get_scope()
+                return detector.is_changed(scope.get_start(), scope.get_end())
+
+            def should_analyze(pydefined):
+                scope = pydefined.get_scope()
+                start = scope.get_start()
+                end = scope.get_end()
+                return detector.consume_changes(start, end)
+            pycore.analyze_module(resource, should_analyze, search_subscopes)
+        except exceptions.ModuleSyntaxError:
+            pass
+
+
+class _TextChangeDetector(object):
+
+    def __init__(self, old, new):
+        self.old = old
+        self.new = new
+        self._set_diffs()
+
+    def _set_diffs(self):
+        differ = difflib.Differ()
+        self.lines = []
+        lineno = 0
+        for line in differ.compare(self.old.splitlines(True),
+                                   self.new.splitlines(True)):
+            if line.startswith(' '):
+                lineno += 1
+            elif line.startswith('-'):
+                lineno += 1
+                self.lines.append(lineno)
+
+    def is_changed(self, start, end):
+        """Tell whether any of start till end lines have changed
+
+        The end points are inclusive and indices start from 1.
+        """
+        left, right = self._get_changed(start, end)
+        if left < right:
+            return True
+        return False
+
+    def consume_changes(self, start, end):
+        """Clear the changed status of lines from start till end"""
+        left, right = self._get_changed(start, end)
+        if left < right:
+            del self.lines[left:right]
+        return left < right
+
+    def _get_changed(self, start, end):
+        left = bisect.bisect_left(self.lines, start)
+        right = bisect.bisect_right(self.lines, end)
+        return left, right
diff --git a/venv/Lib/site-packages/rope/base/pynames.py b/venv/Lib/site-packages/rope/base/pynames.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d489814a35c8a592156711244ada9ee10484b45
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/pynames.py
@@ -0,0 +1,201 @@
+import rope.base.pyobjects
+from rope.base import exceptions, utils
+
+
+class PyName(object):
+    """References to `PyObject`\s inside python programs"""
+
+    def get_object(self):
+        """Return the `PyObject` object referenced by this `PyName`"""
+
+    def get_definition_location(self):
+        """Return a (module, lineno) tuple"""
+
+
+class DefinedName(PyName):
+
+    def __init__(self, pyobject):
+        self.pyobject = pyobject
+
+    def get_object(self):
+        return self.pyobject
+
+    def get_definition_location(self):
+        return (self.pyobject.get_module(), self.pyobject.get_ast().lineno)
+
+
+class AssignedName(PyName):
+    """Only a placeholder"""
+
+
+class UnboundName(PyName):
+
+    def __init__(self, pyobject=None):
+        self.pyobject = pyobject
+        if self.pyobject is None:
+            self.pyobject = rope.base.pyobjects.get_unknown()
+
+    def get_object(self):
+        return self.pyobject
+
+    def get_definition_location(self):
+        return (None, None)
+
+
+class AssignmentValue(object):
+    """An assigned expression"""
+
+    def __init__(self, ast_node, levels=None, evaluation='',
+                 assign_type=False):
+        """The `level` is `None` for simple assignments and is
+        a list of numbers for tuple assignments for example in::
+
+           a, (b, c) = x
+
+        The levels for for `a` is ``[0]``, for `b` is ``[1, 0]`` and for
+        `c` is ``[1, 1]``.
+
+        """
+        self.ast_node = ast_node
+        if levels is None:
+            self.levels = []
+        else:
+            self.levels = levels
+        self.evaluation = evaluation
+        self.assign_type = assign_type
+
+    def get_lineno(self):
+        return self.ast_node.lineno
+
+
+class EvaluatedName(PyName):
+    """A name whose object will be evaluated later"""
+
+    def __init__(self, callback, module=None, lineno=None):
+        self.module = module
+        self.lineno = lineno
+        self.callback = callback
+        self.pyobject = _Inferred(callback, _get_concluded_data(module))
+
+    def get_object(self):
+        return self.pyobject.get()
+
+    def get_definition_location(self):
+        return (self.module, self.lineno)
+
+    def invalidate(self):
+        """Forget the `PyObject` this `PyName` holds"""
+        self.pyobject.set(None)
+
+
+class ParameterName(PyName):
+    """Only a placeholder"""
+
+
+class ImportedModule(PyName):
+
+    def __init__(self, importing_module, module_name=None,
+                 level=0, resource=None):
+        self.importing_module = importing_module
+        self.module_name = module_name
+        self.level = level
+        self.resource = resource
+        self.pymodule = _get_concluded_data(self.importing_module)
+
+    def _current_folder(self):
+        resource = self.importing_module.get_module().get_resource()
+        if resource is None:
+            return None
+        return resource.parent
+
+    def _get_pymodule(self):
+        if self.pymodule.get() is None:
+            pycore = self.importing_module.pycore
+            if self.resource is not None:
+                self.pymodule.set(pycore.project.get_pymodule(self.resource))
+            elif self.module_name is not None:
+                try:
+                    if self.level == 0:
+                        pymodule = pycore.project.get_module(
+                            self.module_name, self._current_folder())
+                    else:
+                        pymodule = pycore.project.get_relative_module(
+                            self.module_name, self._current_folder(),
+                            self.level)
+                    self.pymodule.set(pymodule)
+                except exceptions.ModuleNotFoundError:
+                    pass
+        return self.pymodule.get()
+
+    def get_object(self):
+        if self._get_pymodule() is None:
+            return rope.base.pyobjects.get_unknown()
+        return self._get_pymodule()
+
+    def get_definition_location(self):
+        pymodule = self._get_pymodule()
+        if not isinstance(pymodule, rope.base.pyobjects.PyDefinedObject):
+            return (None, None)
+        return (pymodule.get_module(), 1)
+
+
+class ImportedName(PyName):
+
+    def __init__(self, imported_module, imported_name):
+        self.imported_module = imported_module
+        self.imported_name = imported_name
+
+    def _get_imported_pyname(self):
+        try:
+            result = self.imported_module.get_object()[self.imported_name]
+            if result != self:
+                return result
+        except exceptions.AttributeNotFoundError:
+            pass
+        return UnboundName()
+
+    @utils.prevent_recursion(rope.base.pyobjects.get_unknown)
+    def get_object(self):
+        return self._get_imported_pyname().get_object()
+
+    @utils.prevent_recursion(lambda: (None, None))
+    def get_definition_location(self):
+        return self._get_imported_pyname().get_definition_location()
+
+
+def _get_concluded_data(module):
+    if module is None:
+        return rope.base.pyobjects._ConcludedData()
+    return module._get_concluded_data()
+
+
+def _circular_inference():
+    raise rope.base.pyobjects.IsBeingInferredError(
+        'Circular Object Inference')
+
+
+class _Inferred(object):
+
+    def __init__(self, get_inferred, concluded=None):
+        self.get_inferred = get_inferred
+        self.concluded = concluded
+        if self.concluded is None:
+            self.temp = None
+
+    @utils.prevent_recursion(_circular_inference)
+    def get(self, *args, **kwds):
+        if self.concluded is None or self.concluded.get() is None:
+            self.set(self.get_inferred(*args, **kwds))
+        if self._get() is None:
+            self.set(rope.base.pyobjects.get_unknown())
+        return self._get()
+
+    def set(self, pyobject):
+        if self.concluded is not None:
+            self.concluded.set(pyobject)
+        self.temp = pyobject
+
+    def _get(self):
+        if self.concluded is not None:
+            return self.concluded.get()
+        return self.temp
diff --git a/venv/Lib/site-packages/rope/base/pynamesdef.py b/venv/Lib/site-packages/rope/base/pynamesdef.py
new file mode 100644
index 0000000000000000000000000000000000000000..6dba0a803762d9feb78644b048e2fc06a05c9e16
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/pynamesdef.py
@@ -0,0 +1,55 @@
+import rope.base.oi.soi
+from rope.base import pynames
+from rope.base.pynames import *
+
+
+class AssignedName(pynames.AssignedName):
+
+    def __init__(self, lineno=None, module=None, pyobject=None):
+        self.lineno = lineno
+        self.module = module
+        self.assignments = []
+        self.pyobject = _Inferred(self._get_inferred,
+                                  pynames._get_concluded_data(module))
+        self.pyobject.set(pyobject)
+
+    @utils.prevent_recursion(lambda: None)
+    def _get_inferred(self):
+        if self.module is not None:
+            return rope.base.oi.soi.infer_assigned_object(self)
+
+    def get_object(self):
+        return self.pyobject.get()
+
+    def get_definition_location(self):
+        """Returns a (module, lineno) tuple"""
+        if self.lineno is None and self.assignments:
+            self.lineno = self.assignments[0].get_lineno()
+        return (self.module, self.lineno)
+
+    def invalidate(self):
+        """Forget the `PyObject` this `PyName` holds"""
+        self.pyobject.set(None)
+
+
+class ParameterName(pynames.ParameterName):
+
+    def __init__(self, pyfunction, index):
+        self.pyfunction = pyfunction
+        self.index = index
+
+    def get_object(self):
+        result = self.pyfunction.get_parameter(self.index)
+        if result is None:
+            result = rope.base.pyobjects.get_unknown()
+        return result
+
+    def get_objects(self):
+        """Returns the list of objects passed as this parameter"""
+        return rope.base.oi.soi.get_passed_objects(
+            self.pyfunction, self.index)
+
+    def get_definition_location(self):
+        return (self.pyfunction.get_module(), self.pyfunction.get_ast().lineno)
+
+_Inferred = pynames._Inferred
diff --git a/venv/Lib/site-packages/rope/base/pyobjects.py b/venv/Lib/site-packages/rope/base/pyobjects.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd4d1c822245146f3c6fe0495e82a148ab0e8009
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/pyobjects.py
@@ -0,0 +1,311 @@
+from rope.base.fscommands import _decode_data
+from rope.base import ast, exceptions, utils
+
+
+class PyObject(object):
+
+    def __init__(self, type_):
+        if type_ is None:
+            type_ = self
+        self.type = type_
+
+    def get_attributes(self):
+        if self.type is self:
+            return {}
+        return self.type.get_attributes()
+
+    def get_attribute(self, name):
+        if name not in self.get_attributes():
+            raise exceptions.AttributeNotFoundError(
+                'Attribute %s not found' % name)
+        return self.get_attributes()[name]
+
+    def get_type(self):
+        return self.type
+
+    def __getitem__(self, key):
+        """The same as ``get_attribute(key)``"""
+        return self.get_attribute(key)
+
+    def __contains__(self, key):
+        """The same as ``key in self.get_attributes()``"""
+        return key in self.get_attributes()
+
+    def __eq__(self, obj):
+        """Check the equality of two `PyObject`\s
+
+        Currently it is assumed that instances (the direct instances
+        of `PyObject`, not the instances of its subclasses) are equal
+        if their types are equal.  For every other object like
+        defineds or builtins rope assumes objects are reference
+        objects and their identities should match.
+
+        """
+        if self.__class__ != obj.__class__:
+            return False
+        if type(self) == PyObject:
+            if self is not self.type:
+                return self.type == obj.type
+            else:
+                return self.type is obj.type
+        return self is obj
+
+    def __ne__(self, obj):
+        return not self.__eq__(obj)
+
+    def __hash__(self):
+        """See docs for `__eq__()` method"""
+        if type(self) == PyObject and self != self.type:
+            return hash(self.type) + 1
+        else:
+            return super(PyObject, self).__hash__()
+
+    def __iter__(self):
+        """The same as ``iter(self.get_attributes())``"""
+        return iter(self.get_attributes())
+
+    _types = None
+    _unknown = None
+
+    @staticmethod
+    def _get_base_type(name):
+        if PyObject._types is None:
+            PyObject._types = {}
+            base_type = PyObject(None)
+            PyObject._types['Type'] = base_type
+            PyObject._types['Module'] = PyObject(base_type)
+            PyObject._types['Function'] = PyObject(base_type)
+            PyObject._types['Unknown'] = PyObject(base_type)
+        return PyObject._types[name]
+
+
+def get_base_type(name):
+    """Return the base type with name `name`.
+
+    The base types are 'Type', 'Function', 'Module' and 'Unknown'.  It
+    was used to check the type of a `PyObject` but currently its use
+    is discouraged.  Use classes defined in this module instead.
+    For example instead of
+    ``pyobject.get_type() == get_base_type('Function')`` use
+    ``isinstance(pyobject, AbstractFunction)``.
+
+    You can use `AbstractClass` for classes, `AbstractFunction` for
+    functions, and `AbstractModule` for modules.  You can also use
+    `PyFunction` and `PyClass` for testing if an object is
+    defined somewhere and rope can access its source.  These classes
+    provide more methods.
+
+    """
+    return PyObject._get_base_type(name)
+
+
+def get_unknown():
+    """Return a pyobject whose type is unknown
+
+    Note that two unknown objects are equal.  So for example you can
+    write::
+
+      if pyname.get_object() == get_unknown():
+          print('cannot determine what this pyname holds')
+
+    Rope could have used `None` for indicating unknown objects but
+    we had to check that in many places.  So actually this method
+    returns a null object.
+
+    """
+    if PyObject._unknown is None:
+        PyObject._unknown = PyObject(get_base_type('Unknown'))
+    return PyObject._unknown
+
+
+class AbstractClass(PyObject):
+
+    def __init__(self):
+        super(AbstractClass, self).__init__(get_base_type('Type'))
+
+    def get_name(self):
+        pass
+
+    def get_doc(self):
+        pass
+
+    def get_superclasses(self):
+        return []
+
+
+class AbstractFunction(PyObject):
+
+    def __init__(self):
+        super(AbstractFunction, self).__init__(get_base_type('Function'))
+
+    def get_name(self):
+        pass
+
+    def get_doc(self):
+        pass
+
+    def get_param_names(self, special_args=True):
+        return []
+
+    def get_returned_object(self, args):
+        return get_unknown()
+
+
+class AbstractModule(PyObject):
+
+    def __init__(self, doc=None):
+        super(AbstractModule, self).__init__(get_base_type('Module'))
+
+    def get_doc(self):
+        pass
+
+    def get_resource(self):
+        pass
+
+
+class PyDefinedObject(object):
+    """Python defined names that rope can access their sources"""
+
+    def __init__(self, pycore, ast_node, parent):
+        self.pycore = pycore
+        self.ast_node = ast_node
+        self.scope = None
+        self.parent = parent
+        self.structural_attributes = None
+        self.concluded_attributes = self.get_module()._get_concluded_data()
+        self.attributes = self.get_module()._get_concluded_data()
+        self.defineds = None
+
+    visitor_class = None
+
+    @utils.prevent_recursion(lambda: {})
+    def _get_structural_attributes(self):
+        if self.structural_attributes is None:
+            self.structural_attributes = self._create_structural_attributes()
+        return self.structural_attributes
+
+    @utils.prevent_recursion(lambda: {})
+    def _get_concluded_attributes(self):
+        if self.concluded_attributes.get() is None:
+            self._get_structural_attributes()
+            self.concluded_attributes.set(self._create_concluded_attributes())
+        return self.concluded_attributes.get()
+
+    def get_attributes(self):
+        if self.attributes.get() is None:
+            result = dict(self._get_concluded_attributes())
+            result.update(self._get_structural_attributes())
+            self.attributes.set(result)
+        return self.attributes.get()
+
+    def get_attribute(self, name):
+        if name in self._get_structural_attributes():
+            return self._get_structural_attributes()[name]
+        if name in self._get_concluded_attributes():
+            return self._get_concluded_attributes()[name]
+        raise exceptions.AttributeNotFoundError('Attribute %s not found' %
+                                                name)
+
+    def get_scope(self):
+        if self.scope is None:
+            self.scope = self._create_scope()
+        return self.scope
+
+    def get_module(self):
+        current_object = self
+        while current_object.parent is not None:
+            current_object = current_object.parent
+        return current_object
+
+    def get_doc(self):
+        if len(self.get_ast().body) > 0:
+            expr = self.get_ast().body[0]
+            if isinstance(expr, ast.Expr) and \
+               isinstance(expr.value, ast.Str):
+                docstring = expr.value.s
+                coding = self.get_module().coding
+                return _decode_data(docstring, coding)
+
+    def _get_defined_objects(self):
+        if self.defineds is None:
+            self._get_structural_attributes()
+        return self.defineds
+
+    def _create_structural_attributes(self):
+        if self.visitor_class is None:
+            return {}
+        new_visitor = self.visitor_class(self.pycore, self)
+        for child in ast.get_child_nodes(self.ast_node):
+            ast.walk(child, new_visitor)
+        self.defineds = new_visitor.defineds
+        return new_visitor.names
+
+    def _create_concluded_attributes(self):
+        return {}
+
+    def get_ast(self):
+        return self.ast_node
+
+    def _create_scope(self):
+        pass
+
+
+class PyFunction(PyDefinedObject, AbstractFunction):
+    """Only a placeholder"""
+
+
+class PyClass(PyDefinedObject, AbstractClass):
+    """Only a placeholder"""
+
+
+class _ConcludedData(object):
+
+    def __init__(self):
+        self.data_ = None
+
+    def set(self, data):
+        self.data_ = data
+
+    def get(self):
+        return self.data_
+
+    data = property(get, set)
+
+    def _invalidate(self):
+        self.data = None
+
+    def __str__(self):
+        return '<' + str(self.data) + '>'
+
+
+class _PyModule(PyDefinedObject, AbstractModule):
+
+    def __init__(self, pycore, ast_node, resource):
+        self.resource = resource
+        self.concluded_data = []
+        AbstractModule.__init__(self)
+        PyDefinedObject.__init__(self, pycore, ast_node, None)
+
+    def _get_concluded_data(self):
+        new_data = _ConcludedData()
+        self.concluded_data.append(new_data)
+        return new_data
+
+    def _forget_concluded_data(self):
+        for data in self.concluded_data:
+            data._invalidate()
+
+    def get_resource(self):
+        return self.resource
+
+
+class PyModule(_PyModule):
+    """Only a placeholder"""
+
+
+class PyPackage(_PyModule):
+    """Only a placeholder"""
+
+
+class IsBeingInferredError(exceptions.RopeError):
+    pass
diff --git a/venv/Lib/site-packages/rope/base/pyobjectsdef.py b/venv/Lib/site-packages/rope/base/pyobjectsdef.py
new file mode 100644
index 0000000000000000000000000000000000000000..44fbeb3c232083afc9fc1abed550db5fd5278842
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/pyobjectsdef.py
@@ -0,0 +1,571 @@
+import rope.base.builtins
+import rope.base.codeanalyze
+import rope.base.evaluate
+import rope.base.libutils
+import rope.base.oi.soi
+import rope.base.pyscopes
+from rope.base import (pynamesdef as pynames, exceptions, ast,
+                       astutils, pyobjects, fscommands, arguments, utils)
+from rope.base.utils import pycompat
+
+try:
+    unicode
+except NameError:
+    unicode = str
+
+
+class PyFunction(pyobjects.PyFunction):
+
+    def __init__(self, pycore, ast_node, parent):
+        rope.base.pyobjects.AbstractFunction.__init__(self)
+        rope.base.pyobjects.PyDefinedObject.__init__(
+            self, pycore, ast_node, parent)
+        self.arguments = self.ast_node.args
+        self.parameter_pyobjects = pynames._Inferred(
+            self._infer_parameters, self.get_module()._get_concluded_data())
+        self.returned = pynames._Inferred(self._infer_returned)
+        self.parameter_pynames = None
+
+    def _create_structural_attributes(self):
+        return {}
+
+    def _create_concluded_attributes(self):
+        return {}
+
+    def _create_scope(self):
+        return rope.base.pyscopes.FunctionScope(self.pycore, self,
+                                                _FunctionVisitor)
+
+    def _infer_parameters(self):
+        pyobjects = rope.base.oi.soi.infer_parameter_objects(self)
+        self._handle_special_args(pyobjects)
+        return pyobjects
+
+    def _infer_returned(self, args=None):
+        return rope.base.oi.soi.infer_returned_object(self, args)
+
+    def _handle_special_args(self, pyobjects):
+        if len(pyobjects) == len(self.arguments.args):
+            if self.arguments.vararg:
+                pyobjects.append(rope.base.builtins.get_list())
+            if self.arguments.kwarg:
+                pyobjects.append(rope.base.builtins.get_dict())
+
+    def _set_parameter_pyobjects(self, pyobjects):
+        if pyobjects is not None:
+            self._handle_special_args(pyobjects)
+        self.parameter_pyobjects.set(pyobjects)
+
+    def get_parameters(self):
+        if self.parameter_pynames is None:
+            result = {}
+            for index, name in enumerate(self.get_param_names()):
+                # TODO: handle tuple parameters
+                result[name] = pynames.ParameterName(self, index)
+            self.parameter_pynames = result
+        return self.parameter_pynames
+
+    def get_parameter(self, index):
+        if index < len(self.parameter_pyobjects.get()):
+            return self.parameter_pyobjects.get()[index]
+
+    def get_returned_object(self, args):
+        return self.returned.get(args)
+
+    def get_name(self):
+        return self.get_ast().name
+
+    def get_param_names(self, special_args=True):
+        # TODO: handle tuple parameters
+        result = [pycompat.get_ast_arg_arg(node) for node in self.arguments.args
+                  if isinstance(node, pycompat.ast_arg_type)]
+        if special_args:
+            if self.arguments.vararg:
+                result.append(pycompat.get_ast_arg_arg(self.arguments.vararg))
+            if self.arguments.kwarg:
+                result.append(pycompat.get_ast_arg_arg(self.arguments.kwarg))
+        return result
+
+    def get_kind(self):
+        """Get function type
+
+        It returns one of 'function', 'method', 'staticmethod' or
+        'classmethod' strs.
+
+        """
+        scope = self.parent.get_scope()
+        if isinstance(self.parent, PyClass):
+            for decorator in self.decorators:
+                pyname = rope.base.evaluate.eval_node(scope, decorator)
+                if pyname == rope.base.builtins.builtins['staticmethod']:
+                    return 'staticmethod'
+                if pyname == rope.base.builtins.builtins['classmethod']:
+                    return 'classmethod'
+            return 'method'
+        return 'function'
+
+    @property
+    def decorators(self):
+        try:
+            return getattr(self.ast_node, 'decorator_list')
+        except AttributeError:
+            return getattr(self.ast_node, 'decorators', None)
+
+
+class PyClass(pyobjects.PyClass):
+
+    def __init__(self, pycore, ast_node, parent):
+        self.visitor_class = _ClassVisitor
+        rope.base.pyobjects.AbstractClass.__init__(self)
+        rope.base.pyobjects.PyDefinedObject.__init__(
+            self, pycore, ast_node, parent)
+        self.parent = parent
+        self._superclasses = self.get_module()._get_concluded_data()
+
+    def get_superclasses(self):
+        if self._superclasses.get() is None:
+            self._superclasses.set(self._get_bases())
+        return self._superclasses.get()
+
+    def get_name(self):
+        return self.get_ast().name
+
+    def _create_concluded_attributes(self):
+        result = {}
+        for base in reversed(self.get_superclasses()):
+            result.update(base.get_attributes())
+        return result
+
+    def _get_bases(self):
+        result = []
+        for base_name in self.ast_node.bases:
+            base = rope.base.evaluate.eval_node(self.parent.get_scope(),
+                                                base_name)
+            if base is not None and \
+                base.get_object().get_type() == \
+                    rope.base.pyobjects.get_base_type('Type'):
+                    result.append(base.get_object())
+        return result
+
+    def _create_scope(self):
+        return rope.base.pyscopes.ClassScope(self.pycore, self)
+
+
+class PyModule(pyobjects.PyModule):
+
+    def __init__(self, pycore, source=None,
+                 resource=None, force_errors=False):
+        ignore = pycore.project.prefs.get('ignore_syntax_errors', False)
+        syntax_errors = force_errors or not ignore
+        self.has_errors = False
+        try:
+            source, node = self._init_source(pycore, source, resource)
+        except exceptions.ModuleSyntaxError:
+            self.has_errors = True
+            if syntax_errors:
+                raise
+            else:
+                source = '\n'
+                node = ast.parse('\n')
+        self.source_code = source
+        self.star_imports = []
+        self.visitor_class = _GlobalVisitor
+        self.coding = fscommands.read_str_coding(self.source_code)
+        super(PyModule, self).__init__(pycore, node, resource)
+
+    def _init_source(self, pycore, source_code, resource):
+        filename = 'string'
+        if resource:
+            filename = resource.path
+        try:
+            if source_code is None:
+                source_bytes = resource.read_bytes()
+                source_code = fscommands.file_data_to_unicode(source_bytes)
+            else:
+                if isinstance(source_code, unicode):
+                    source_bytes = fscommands.unicode_to_file_data(source_code)
+                else:
+                    source_bytes = source_code
+            ast_node = ast.parse(source_bytes, filename=filename)
+        except SyntaxError as e:
+            raise exceptions.ModuleSyntaxError(filename, e.lineno, e.msg)
+        except UnicodeDecodeError as e:
+            raise exceptions.ModuleSyntaxError(filename, 1, '%s' % (e.reason))
+        return source_code, ast_node
+
+    @utils.prevent_recursion(lambda: {})
+    def _create_concluded_attributes(self):
+        result = {}
+        for star_import in self.star_imports:
+            result.update(star_import.get_names())
+        return result
+
+    def _create_scope(self):
+        return rope.base.pyscopes.GlobalScope(self.pycore, self)
+
+    @property
+    @utils.saveit
+    def lines(self):
+        """A `SourceLinesAdapter`"""
+        return rope.base.codeanalyze.SourceLinesAdapter(self.source_code)
+
+    @property
+    @utils.saveit
+    def logical_lines(self):
+        """A `LogicalLinesFinder`"""
+        return rope.base.codeanalyze.CachingLogicalLineFinder(self.lines)
+
+    def get_name(self):
+        return rope.base.libutils.modname(self.get_resource())
+
+class PyPackage(pyobjects.PyPackage):
+
+    def __init__(self, pycore, resource=None, force_errors=False):
+        self.resource = resource
+        init_dot_py = self._get_init_dot_py()
+        if init_dot_py is not None:
+            ast_node = pycore.project.get_pymodule(
+                init_dot_py, force_errors=force_errors).get_ast()
+        else:
+            ast_node = ast.parse('\n')
+        super(PyPackage, self).__init__(pycore, ast_node, resource)
+
+    def _create_structural_attributes(self):
+        result = {}
+        modname = rope.base.libutils.modname(self.resource)
+        extension_submodules = self.pycore._builtin_submodules(modname)
+        for name, module in extension_submodules.items():
+            result[name] = rope.base.builtins.BuiltinName(module)
+        if self.resource is None:
+            return result
+        for name, resource in self._get_child_resources().items():
+            result[name] = pynames.ImportedModule(self, resource=resource)
+        return result
+
+    def _create_concluded_attributes(self):
+        result = {}
+        init_dot_py = self._get_init_dot_py()
+        if init_dot_py:
+            init_object = self.pycore.project.get_pymodule(init_dot_py)
+            result.update(init_object.get_attributes())
+        return result
+
+    def _get_child_resources(self):
+        result = {}
+        for child in self.resource.get_children():
+            if child.is_folder():
+                result[child.name] = child
+            elif child.name.endswith('.py') and \
+                    child.name != '__init__.py':
+                name = child.name[:-3]
+                result[name] = child
+        return result
+
+    def _get_init_dot_py(self):
+        if self.resource is not None and \
+                self.resource.has_child('__init__.py'):
+            return self.resource.get_child('__init__.py')
+        else:
+            return None
+
+    def _create_scope(self):
+        return self.get_module().get_scope()
+
+    def get_module(self):
+        init_dot_py = self._get_init_dot_py()
+        if init_dot_py:
+            return self.pycore.project.get_pymodule(init_dot_py)
+        return self
+
+
+class _AssignVisitor(object):
+
+    def __init__(self, scope_visitor):
+        self.scope_visitor = scope_visitor
+        self.assigned_ast = None
+
+    def _Assign(self, node):
+        self.assigned_ast = node.value
+        for child_node in node.targets:
+            ast.walk(child_node, self)
+
+    def _assigned(self, name, assignment=None):
+        self.scope_visitor._assigned(name, assignment)
+
+    def _Name(self, node):
+        assignment = None
+        if self.assigned_ast is not None:
+            assignment = pynames.AssignmentValue(self.assigned_ast)
+        self._assigned(node.id, assignment)
+
+    def _Tuple(self, node):
+        names = astutils.get_name_levels(node)
+        for name, levels in names:
+            assignment = None
+            if self.assigned_ast is not None:
+                assignment = pynames.AssignmentValue(self.assigned_ast, levels)
+            self._assigned(name, assignment)
+
+    def _Attribute(self, node):
+        pass
+
+    def _Subscript(self, node):
+        pass
+
+    def _Slice(self, node):
+        pass
+
+
+class _ScopeVisitor(object):
+
+    def __init__(self, pycore, owner_object):
+        self.pycore = pycore
+        self.owner_object = owner_object
+        self.names = {}
+        self.defineds = []
+
+    def get_module(self):
+        if self.owner_object is not None:
+            return self.owner_object.get_module()
+        else:
+            return None
+
+    def _ClassDef(self, node):
+        pyclass = PyClass(self.pycore, node, self.owner_object)
+        self.names[node.name] = pynames.DefinedName(pyclass)
+        self.defineds.append(pyclass)
+
+    def _FunctionDef(self, node):
+        pyfunction = PyFunction(self.pycore, node, self.owner_object)
+        for decorator in pyfunction.decorators:
+            if isinstance(decorator, ast.Name) and decorator.id == 'property':
+                if isinstance(self, _ClassVisitor):
+                    type_ = rope.base.builtins.Property(pyfunction)
+                    arg = pynames.UnboundName(
+                        rope.base.pyobjects.PyObject(self.owner_object))
+
+                    def _eval(type_=type_, arg=arg):
+                        return type_.get_property_object(
+                            arguments.ObjectArguments([arg]))
+                    self.names[node.name] = pynames.EvaluatedName(
+                        _eval, module=self.get_module(), lineno=node.lineno)
+                    break
+        else:
+            self.names[node.name] = pynames.DefinedName(pyfunction)
+        self.defineds.append(pyfunction)
+
+    def _AsyncFunctionDef(self, node):
+        return self._FunctionDef(node)
+
+    def _Assign(self, node):
+        ast.walk(node, _AssignVisitor(self))
+
+    def _AugAssign(self, node):
+        pass
+
+    def _For(self, node):
+        names = self._update_evaluated(node.target, node.iter,  # noqa
+                                       '.__iter__().next()')
+        for child in node.body + node.orelse:
+            ast.walk(child, self)
+
+    def _AsyncFor(self, node):
+        return self._For(node)
+
+    def _assigned(self, name, assignment):
+        pyname = self.names.get(name, None)
+        if pyname is None:
+            pyname = pynames.AssignedName(module=self.get_module())
+        if isinstance(pyname, pynames.AssignedName):
+            if assignment is not None:
+                pyname.assignments.append(assignment)
+            self.names[name] = pyname
+
+    def _update_evaluated(self, targets, assigned,
+                          evaluation='', eval_type=False):
+        result = {}
+        if isinstance(targets, str):
+            assignment = pynames.AssignmentValue(assigned, [],
+                                                 evaluation, eval_type)
+            self._assigned(targets, assignment)
+        else:
+            names = astutils.get_name_levels(targets)
+            for name, levels in names:
+                assignment = pynames.AssignmentValue(assigned, levels,
+                                                     evaluation, eval_type)
+                self._assigned(name, assignment)
+        return result
+
+    def _With(self, node):
+        for item in pycompat.get_ast_with_items(node):
+            if item.optional_vars:
+                self._update_evaluated(item.optional_vars,
+                                       item.context_expr, '.__enter__()')
+        for child in node.body:
+            ast.walk(child, self)
+
+    def _AsyncWith(self, node):
+        return self._With(node)
+
+    def _excepthandler(self, node):
+        node_name_type = str if pycompat.PY3 else ast.Name
+        if node.name is not None and isinstance(node.name, node_name_type):
+            type_node = node.type
+            if isinstance(node.type, ast.Tuple) and type_node.elts:
+                type_node = type_node.elts[0]
+            self._update_evaluated(node.name, type_node, eval_type=True)
+
+        for child in node.body:
+            ast.walk(child, self)
+
+    def _ExceptHandler(self, node):
+        self._excepthandler(node)
+
+    def _Import(self, node):
+        for import_pair in node.names:
+            module_name = import_pair.name
+            alias = import_pair.asname
+            first_package = module_name.split('.')[0]
+            if alias is not None:
+                imported = pynames.ImportedModule(self.get_module(),
+                                                  module_name)
+                if not self._is_ignored_import(imported):
+                    self.names[alias] = imported
+            else:
+                imported = pynames.ImportedModule(self.get_module(),
+                                                  first_package)
+                if not self._is_ignored_import(imported):
+                    self.names[first_package] = imported
+
+    def _ImportFrom(self, node):
+        level = 0
+        if node.level:
+            level = node.level
+        imported_module = pynames.ImportedModule(self.get_module(),
+                                                 node.module, level)
+        if self._is_ignored_import(imported_module):
+            return
+        if len(node.names) == 1 and node.names[0].name == '*':
+            if isinstance(self.owner_object, PyModule):
+                self.owner_object.star_imports.append(
+                    StarImport(imported_module))
+        else:
+            for imported_name in node.names:
+                imported = imported_name.name
+                alias = imported_name.asname
+                if alias is not None:
+                    imported = alias
+                self.names[imported] = pynames.ImportedName(imported_module,
+                                                            imported_name.name)
+
+    def _is_ignored_import(self, imported_module):
+        if not self.pycore.project.prefs.get('ignore_bad_imports', False):
+            return False
+        return not isinstance(imported_module.get_object(),
+                              rope.base.pyobjects.AbstractModule)
+
+    def _Global(self, node):
+        module = self.get_module()
+        for name in node.names:
+            if module is not None:
+                try:
+                    pyname = module[name]
+                except exceptions.AttributeNotFoundError:
+                    pyname = pynames.AssignedName(node.lineno)
+            self.names[name] = pyname
+
+
+class _GlobalVisitor(_ScopeVisitor):
+
+    def __init__(self, pycore, owner_object):
+        super(_GlobalVisitor, self).__init__(pycore, owner_object)
+
+
+class _ClassVisitor(_ScopeVisitor):
+
+    def __init__(self, pycore, owner_object):
+        super(_ClassVisitor, self).__init__(pycore, owner_object)
+
+    def _FunctionDef(self, node):
+        _ScopeVisitor._FunctionDef(self, node)
+        if len(node.args.args) > 0:
+            first = node.args.args[0]
+            new_visitor = None
+            if isinstance(first, pycompat.ast_arg_type):
+                new_visitor = _ClassInitVisitor(self, pycompat.get_ast_arg_arg(first))
+            if new_visitor is not None:
+                for child in ast.get_child_nodes(node):
+                    ast.walk(child, new_visitor)
+
+
+class _FunctionVisitor(_ScopeVisitor):
+
+    def __init__(self, pycore, owner_object):
+        super(_FunctionVisitor, self).__init__(pycore, owner_object)
+        self.returned_asts = []
+        self.generator = False
+
+    def _Return(self, node):
+        if node.value is not None:
+            self.returned_asts.append(node.value)
+
+    def _Yield(self, node):
+        if node.value is not None:
+            self.returned_asts.append(node.value)
+        self.generator = True
+
+
+class _ClassInitVisitor(_AssignVisitor):
+
+    def __init__(self, scope_visitor, self_name):
+        super(_ClassInitVisitor, self).__init__(scope_visitor)
+        self.self_name = self_name
+
+    def _Attribute(self, node):
+        if not isinstance(node.ctx, ast.Store):
+            return
+        if isinstance(node.value, ast.Name) and \
+           node.value.id == self.self_name:
+            if node.attr not in self.scope_visitor.names:
+                self.scope_visitor.names[node.attr] = pynames.AssignedName(
+                    lineno=node.lineno, module=self.scope_visitor.get_module())
+            if self.assigned_ast is not None:
+                pyname = self.scope_visitor.names[node.attr]
+                if isinstance(pyname, pynames.AssignedName):
+                    pyname.assignments.append(
+                        pynames.AssignmentValue(self.assigned_ast))
+
+    def _Tuple(self, node):
+        if not isinstance(node.ctx, ast.Store):
+            return
+        for child in ast.get_child_nodes(node):
+            ast.walk(child, self)
+
+    def _Name(self, node):
+        pass
+
+    def _FunctionDef(self, node):
+        pass
+
+    def _ClassDef(self, node):
+        pass
+
+    def _For(self, node):
+        pass
+
+    def _With(self, node):
+        pass
+
+
+class StarImport(object):
+
+    def __init__(self, imported_module):
+        self.imported_module = imported_module
+
+    def get_names(self):
+        result = {}
+        imported = self.imported_module.get_object()
+        for name in imported:
+            if not name.startswith('_'):
+                result[name] = pynames.ImportedName(self.imported_module, name)
+        return result
diff --git a/venv/Lib/site-packages/rope/base/pyscopes.py b/venv/Lib/site-packages/rope/base/pyscopes.py
new file mode 100644
index 0000000000000000000000000000000000000000..0bed19a92912ccda603e3f470ca48154c417bb59
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/pyscopes.py
@@ -0,0 +1,314 @@
+import rope.base.builtins
+import rope.base.codeanalyze
+import rope.base.pynames
+from rope.base import ast, exceptions, utils
+
+
+class Scope(object):
+
+    def __init__(self, pycore, pyobject, parent_scope):
+        self.pycore = pycore
+        self.pyobject = pyobject
+        self.parent = parent_scope
+
+    def get_names(self):
+        """Return the names defined or imported in this scope"""
+        return self.pyobject.get_attributes()
+
+    def get_defined_names(self):
+        """Return the names defined in this scope"""
+        return self.pyobject._get_structural_attributes()
+
+    def get_name(self, name):
+        """Return name `PyName` defined in this scope"""
+        if name not in self.get_names():
+            raise exceptions.NameNotFoundError('name %s not found' % name)
+        return self.get_names()[name]
+
+    def __getitem__(self, key):
+        """The same as ``get_name(key)``"""
+        return self.get_name(key)
+
+    def __contains__(self, key):
+        """The same as ``key in self.get_names()``"""
+        return key in self.get_names()
+
+    @utils.saveit
+    def get_scopes(self):
+        """Return the subscopes of this scope
+
+        The returned scopes should be sorted by the order they appear.
+        """
+        return self._create_scopes()
+
+    def lookup(self, name):
+        if name in self.get_names():
+            return self.get_names()[name]
+        if self.parent is not None:
+            return self.parent._propagated_lookup(name)
+        return None
+
+    def get_propagated_names(self):
+        """Return the visible names of this scope
+
+        Return the names defined in this scope that are visible from
+        scopes containing this scope.  This method returns the same
+        dictionary returned by `get_names()` except for `ClassScope`
+        which returns an empty dict.
+        """
+        return self.get_names()
+
+    def _propagated_lookup(self, name):
+        if name in self.get_propagated_names():
+            return self.get_propagated_names()[name]
+        if self.parent is not None:
+            return self.parent._propagated_lookup(name)
+        return None
+
+    def _create_scopes(self):
+        return [pydefined.get_scope()
+                for pydefined in self.pyobject._get_defined_objects()]
+
+    def _get_global_scope(self):
+        current = self
+        while current.parent is not None:
+            current = current.parent
+        return current
+
+    def get_start(self):
+        return self.pyobject.get_ast().lineno
+
+    def get_body_start(self):
+        body = self.pyobject.get_ast().body
+        if body:
+            return body[0].lineno
+        return self.get_start()
+
+    def get_end(self):
+        pymodule = self._get_global_scope().pyobject
+        return pymodule.logical_lines.logical_line_in(self.logical_end)[1]
+
+    @utils.saveit
+    def get_logical_end(self):
+        global_scope = self._get_global_scope()
+        return global_scope._scope_finder.find_scope_end(self)
+
+    start = property(get_start)
+    end = property(get_end)
+    logical_end = property(get_logical_end)
+
+    def get_kind(self):
+        pass
+
+
+class GlobalScope(Scope):
+
+    def __init__(self, pycore, module):
+        super(GlobalScope, self).__init__(pycore, module, None)
+        self.names = module._get_concluded_data()
+
+    def get_start(self):
+        return 1
+
+    def get_kind(self):
+        return 'Module'
+
+    def get_name(self, name):
+        try:
+            return self.pyobject[name]
+        except exceptions.AttributeNotFoundError:
+            if name in self.builtin_names:
+                return self.builtin_names[name]
+            raise exceptions.NameNotFoundError('name %s not found' % name)
+
+    def get_names(self):
+        if self.names.get() is None:
+            result = dict(self.builtin_names)
+            result.update(super(GlobalScope, self).get_names())
+            self.names.set(result)
+        return self.names.get()
+
+    def get_inner_scope_for_line(self, lineno, indents=None):
+        return self._scope_finder.get_holding_scope(self, lineno, indents)
+
+    def get_inner_scope_for_offset(self, offset):
+        return self._scope_finder.get_holding_scope_for_offset(self, offset)
+
+    @property
+    @utils.saveit
+    def _scope_finder(self):
+        return _HoldingScopeFinder(self.pyobject)
+
+    @property
+    def builtin_names(self):
+        return rope.base.builtins.builtins.get_attributes()
+
+
+class FunctionScope(Scope):
+
+    def __init__(self, pycore, pyobject, visitor):
+        super(FunctionScope, self).__init__(pycore, pyobject,
+                                            pyobject.parent.get_scope())
+        self.names = None
+        self.returned_asts = None
+        self.is_generator = None
+        self.defineds = None
+        self.visitor = visitor
+
+    def _get_names(self):
+        if self.names is None:
+            self._visit_function()
+        return self.names
+
+    def _visit_function(self):
+        if self.names is None:
+            new_visitor = self.visitor(self.pycore, self.pyobject)
+            for n in ast.get_child_nodes(self.pyobject.get_ast()):
+                ast.walk(n, new_visitor)
+            self.names = new_visitor.names
+            self.names.update(self.pyobject.get_parameters())
+            self.returned_asts = new_visitor.returned_asts
+            self.is_generator = new_visitor.generator
+            self.defineds = new_visitor.defineds
+
+    def _get_returned_asts(self):
+        if self.names is None:
+            self._visit_function()
+        return self.returned_asts
+
+    def _is_generator(self):
+        if self.is_generator is None:
+            self._get_returned_asts()
+        return self.is_generator
+
+    def get_names(self):
+        return self._get_names()
+
+    def _create_scopes(self):
+        if self.defineds is None:
+            self._visit_function()
+        return [pydefined.get_scope() for pydefined in self.defineds]
+
+    def get_kind(self):
+        return 'Function'
+
+    def invalidate_data(self):
+        for pyname in self.get_names().values():
+            if isinstance(pyname, (rope.base.pynames.AssignedName,
+                                   rope.base.pynames.EvaluatedName)):
+                pyname.invalidate()
+
+
+class ClassScope(Scope):
+
+    def __init__(self, pycore, pyobject):
+        super(ClassScope, self).__init__(pycore, pyobject,
+                                         pyobject.parent.get_scope())
+
+    def get_kind(self):
+        return 'Class'
+
+    def get_propagated_names(self):
+        return {}
+
+
+class _HoldingScopeFinder(object):
+
+    def __init__(self, pymodule):
+        self.pymodule = pymodule
+
+    def get_indents(self, lineno):
+        return rope.base.codeanalyze.count_line_indents(
+            self.lines.get_line(lineno))
+
+    def _get_scope_indents(self, scope):
+        return self.get_indents(scope.get_start())
+
+    def get_holding_scope(self, module_scope, lineno, line_indents=None):
+        if line_indents is None:
+            line_indents = self.get_indents(lineno)
+        current_scope = module_scope
+        new_scope = current_scope
+        while new_scope is not None and \
+                (new_scope.get_kind() == 'Module' or
+                 self._get_scope_indents(new_scope) <= line_indents):
+            current_scope = new_scope
+            if current_scope.get_start() == lineno and \
+               current_scope.get_kind() != 'Module':
+                return current_scope
+            new_scope = None
+            for scope in current_scope.get_scopes():
+                if scope.get_start() <= lineno:
+                    if lineno <= scope.get_end():
+                        new_scope = scope
+                        break
+                else:
+                    break
+        return current_scope
+
+    def _is_empty_line(self, lineno):
+        line = self.lines.get_line(lineno)
+        return line.strip() == '' or line.lstrip().startswith('#')
+
+    def _get_body_indents(self, scope):
+        return self.get_indents(scope.get_body_start())
+
+    def get_holding_scope_for_offset(self, scope, offset):
+        return self.get_holding_scope(
+            scope, self.lines.get_line_number(offset))
+
+    def find_scope_end(self, scope):
+        if not scope.parent:
+            return self.lines.length()
+        end = scope.pyobject.get_ast().body[-1].lineno
+        scope_start = self.pymodule.logical_lines.logical_line_in(scope.start)
+        if scope_start[1] >= end:
+            # handling one-liners
+            body_indents = self._get_scope_indents(scope) + 4
+        else:
+            body_indents = self._get_body_indents(scope)
+        for l in self.logical_lines.generate_starts(
+                min(end + 1, self.lines.length()), self.lines.length() + 1):
+            if not self._is_empty_line(l):
+                if self.get_indents(l) < body_indents:
+                    return end
+                else:
+                    end = l
+        return end
+
+    @property
+    def lines(self):
+        return self.pymodule.lines
+
+    @property
+    def code(self):
+        return self.pymodule.source_code
+
+    @property
+    def logical_lines(self):
+        return self.pymodule.logical_lines
+
+
+class TemporaryScope(Scope):
+    """Currently used for list comprehensions and generator expressions
+
+    These scopes do not appear in the `get_scopes()` method of their
+    parent scopes.
+    """
+
+    def __init__(self, pycore, parent_scope, names):
+        super(TemporaryScope, self).__init__(
+            pycore, parent_scope.pyobject, parent_scope)
+        self.names = names
+
+    def get_names(self):
+        return self.names
+
+    def get_defined_names(self):
+        return self.names
+
+    def _create_scopes(self):
+        return []
+
+    def get_kind(self):
+        return 'Temporary'
diff --git a/venv/Lib/site-packages/rope/base/resourceobserver.py b/venv/Lib/site-packages/rope/base/resourceobserver.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c0937d5bbacb4f73a8eb59ba7e8141e072a8dcd
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/resourceobserver.py
@@ -0,0 +1,272 @@
+import os
+
+
+class ResourceObserver(object):
+    """Provides the interface for observing resources
+
+    `ResourceObserver`\s can be registered using `Project.
+    add_observer()`.  But most of the time `FilteredResourceObserver`
+    should be used.  `ResourceObserver`\s report all changes passed
+    to them and they don't report changes to all resources.  For
+    example if a folder is removed, it only calls `removed()` for that
+    folder and not its contents.  You can use
+    `FilteredResourceObserver` if you are interested in changes only
+    to a list of resources.  And you want changes to be reported on
+    individual resources.
+
+    """
+
+    def __init__(self, changed=None, moved=None, created=None,
+                 removed=None, validate=None):
+        self.changed = changed
+        self.moved = moved
+        self.created = created
+        self.removed = removed
+        self._validate = validate
+
+    def resource_changed(self, resource):
+        """It is called when the resource changes"""
+        if self.changed is not None:
+            self.changed(resource)
+
+    def resource_moved(self, resource, new_resource):
+        """It is called when a resource is moved"""
+        if self.moved is not None:
+            self.moved(resource, new_resource)
+
+    def resource_created(self, resource):
+        """Is called when a new resource is created"""
+        if self.created is not None:
+            self.created(resource)
+
+    def resource_removed(self, resource):
+        """Is called when a new resource is removed"""
+        if self.removed is not None:
+            self.removed(resource)
+
+    def validate(self, resource):
+        """Validate the existence of this resource and its children.
+
+        This function is called when rope need to update its resource
+        cache about the files that might have been changed or removed
+        by other processes.
+
+        """
+        if self._validate is not None:
+            self._validate(resource)
+
+
+class FilteredResourceObserver(object):
+    """A useful decorator for `ResourceObserver`
+
+    Most resource observers have a list of resources and are
+    interested only in changes to those files.  This class satisfies
+    this need.  It dispatches resource changed and removed messages.
+    It performs these tasks:
+
+    * Changes to files and folders are analyzed to check whether any
+      of the interesting resources are changed or not.  If they are,
+      it reports these changes to `resource_observer` passed to the
+      constructor.
+    * When a resource is removed it checks whether any of the
+      interesting resources are contained in that folder and reports
+      them to `resource_observer`.
+    * When validating a folder it validates all of the interesting
+      files in that folder.
+
+    Since most resource observers are interested in a list of
+    resources that change over time, `add_resource` and
+    `remove_resource` might be useful.
+
+    """
+
+    def __init__(self, resource_observer, initial_resources=None,
+                 timekeeper=None):
+        self.observer = resource_observer
+        self.resources = {}
+        if timekeeper is not None:
+            self.timekeeper = timekeeper
+        else:
+            self.timekeeper = ChangeIndicator()
+        if initial_resources is not None:
+            for resource in initial_resources:
+                self.add_resource(resource)
+
+    def add_resource(self, resource):
+        """Add a resource to the list of interesting resources"""
+        if resource.exists():
+            self.resources[resource] = self.timekeeper.get_indicator(resource)
+        else:
+            self.resources[resource] = None
+
+    def remove_resource(self, resource):
+        """Add a resource to the list of interesting resources"""
+        if resource in self.resources:
+            del self.resources[resource]
+
+    def clear_resources(self):
+        """Removes all registered resources"""
+        self.resources.clear()
+
+    def resource_changed(self, resource):
+        changes = _Changes()
+        self._update_changes_caused_by_changed(changes, resource)
+        self._perform_changes(changes)
+
+    def _update_changes_caused_by_changed(self, changes, changed):
+        if changed in self.resources:
+            changes.add_changed(changed)
+        if self._is_parent_changed(changed):
+            changes.add_changed(changed.parent)
+
+    def _update_changes_caused_by_moved(self, changes, resource,
+                                        new_resource=None):
+        if resource in self.resources:
+            changes.add_removed(resource, new_resource)
+        if new_resource in self.resources:
+            changes.add_created(new_resource)
+        if resource.is_folder():
+            for file in list(self.resources):
+                if resource.contains(file):
+                    new_file = self._calculate_new_resource(
+                        resource, new_resource, file)
+                    changes.add_removed(file, new_file)
+        if self._is_parent_changed(resource):
+            changes.add_changed(resource.parent)
+        if new_resource is not None:
+            if self._is_parent_changed(new_resource):
+                changes.add_changed(new_resource.parent)
+
+    def _is_parent_changed(self, child):
+        return child.parent in self.resources
+
+    def resource_moved(self, resource, new_resource):
+        changes = _Changes()
+        self._update_changes_caused_by_moved(changes, resource, new_resource)
+        self._perform_changes(changes)
+
+    def resource_created(self, resource):
+        changes = _Changes()
+        self._update_changes_caused_by_created(changes, resource)
+        self._perform_changes(changes)
+
+    def _update_changes_caused_by_created(self, changes, resource):
+        if resource in self.resources:
+            changes.add_created(resource)
+        if self._is_parent_changed(resource):
+            changes.add_changed(resource.parent)
+
+    def resource_removed(self, resource):
+        changes = _Changes()
+        self._update_changes_caused_by_moved(changes, resource)
+        self._perform_changes(changes)
+
+    def _perform_changes(self, changes):
+        for resource in changes.changes:
+            self.observer.resource_changed(resource)
+            self.resources[resource] = self.timekeeper.get_indicator(resource)
+        for resource, new_resource in changes.moves.items():
+            self.resources[resource] = None
+            if new_resource is not None:
+                self.observer.resource_moved(resource, new_resource)
+            else:
+                self.observer.resource_removed(resource)
+        for resource in changes.creations:
+            self.observer.resource_created(resource)
+            self.resources[resource] = self.timekeeper.get_indicator(resource)
+
+    def validate(self, resource):
+        changes = _Changes()
+        for file in self._search_resource_moves(resource):
+            if file in self.resources:
+                self._update_changes_caused_by_moved(changes, file)
+        for file in self._search_resource_changes(resource):
+            if file in self.resources:
+                self._update_changes_caused_by_changed(changes, file)
+        for file in self._search_resource_creations(resource):
+            if file in self.resources:
+                changes.add_created(file)
+        self._perform_changes(changes)
+
+    def _search_resource_creations(self, resource):
+        creations = set()
+        if resource in self.resources and resource.exists() and \
+           self.resources[resource] is None:
+            creations.add(resource)
+        if resource.is_folder():
+            for file in self.resources:
+                if file.exists() and resource.contains(file) and \
+                   self.resources[file] is None:
+                    creations.add(file)
+        return creations
+
+    def _search_resource_moves(self, resource):
+        all_moved = set()
+        if resource in self.resources and not resource.exists():
+            all_moved.add(resource)
+        if resource.is_folder():
+            for file in self.resources:
+                if resource.contains(file):
+                    if not file.exists():
+                        all_moved.add(file)
+        moved = set(all_moved)
+        for folder in [file for file in all_moved if file.is_folder()]:
+            if folder in moved:
+                for file in list(moved):
+                    if folder.contains(file):
+                        moved.remove(file)
+        return moved
+
+    def _search_resource_changes(self, resource):
+        changed = set()
+        if resource in self.resources and self._is_changed(resource):
+            changed.add(resource)
+        if resource.is_folder():
+            for file in self.resources:
+                if file.exists() and resource.contains(file):
+                    if self._is_changed(file):
+                        changed.add(file)
+        return changed
+
+    def _is_changed(self, resource):
+        if self.resources[resource] is None:
+            return False
+        return self.resources[resource] != \
+            self.timekeeper.get_indicator(resource)
+
+    def _calculate_new_resource(self, main, new_main, resource):
+        if new_main is None:
+            return None
+        diff = resource.path[len(main.path):]
+        return resource.project.get_resource(new_main.path + diff)
+
+
+class ChangeIndicator(object):
+
+    def get_indicator(self, resource):
+        """Return the modification time and size of a `Resource`."""
+        path = resource.real_path
+        # on dos, mtime does not change for a folder when files are added
+        if os.name != 'posix' and os.path.isdir(path):
+            return (os.path.getmtime(path),
+                    len(os.listdir(path)),
+                    os.path.getsize(path))
+        return (os.path.getmtime(path),
+                os.path.getsize(path))
+
+
+class _Changes(object):
+
+    def __init__(self):
+        self.changes = set()
+        self.creations = set()
+        self.moves = {}
+
+    def add_changed(self, resource):
+        self.changes.add(resource)
+
+    def add_removed(self, resource, new_resource=None):
+        self.moves[resource] = new_resource
+
+    def add_created(self, resource):
+        self.creations.add(resource)
diff --git a/venv/Lib/site-packages/rope/base/resources.py b/venv/Lib/site-packages/rope/base/resources.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f02779c3cfdd4a06d0b77ca2a0b7f464398cb10
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/resources.py
@@ -0,0 +1,247 @@
+"""Files and folders in a project are represented as resource objects.
+
+Files and folders are access through `Resource` objects. `Resource` has
+two subclasses: `File` and `Folder`. What we care about is that
+refactorings and `rope.base.change.Change`s use resources.
+
+There are two options to create a `Resource` for a path in a project.
+Note that in these examples `path` is the path to a file or folder
+relative to the project's root. A project's root folder is represented
+by an empty string.
+
+  1) Use the `rope.base.Project.get_resource()` method. E.g.:
+
+       myresource = myproject.get_resource(path)
+
+
+  2) Use the `rope.base.libutils` module. `libutils` has a function
+     named `path_to_resource()`. It takes a project and a path:
+
+       from rope.base import libutils
+
+       myresource = libutils.path_to_resource(myproject, path)
+
+Once we have a `Resource`, we can retrieve information from it, like
+getting the path relative to the project's root (via `path`), reading
+from and writing to the resource, moving the resource, etc.
+"""
+
+import os
+import re
+
+from rope.base import change
+from rope.base import exceptions
+from rope.base import fscommands
+
+
+class Resource(object):
+    """Represents files and folders in a project"""
+
+    def __init__(self, project, path):
+        self.project = project
+        self._path = path
+
+    def move(self, new_location):
+        """Move resource to `new_location`"""
+        self._perform_change(change.MoveResource(self, new_location),
+                             'Moving <%s> to <%s>' % (self.path, new_location))
+
+    def remove(self):
+        """Remove resource from the project"""
+        self._perform_change(change.RemoveResource(self),
+                             'Removing <%s>' % self.path)
+
+    def is_folder(self):
+        """Return true if the resource is a folder"""
+
+    def create(self):
+        """Create this resource"""
+
+    def exists(self):
+        return os.path.exists(self.real_path)
+
+    @property
+    def parent(self):
+        parent = '/'.join(self.path.split('/')[0:-1])
+        return self.project.get_folder(parent)
+
+    @property
+    def path(self):
+        """Return the path of this resource relative to the project root
+
+        The path is the list of parent directories separated by '/' followed
+        by the resource name.
+        """
+        return self._path
+
+    @property
+    def name(self):
+        """Return the name of this resource"""
+        return self.path.split('/')[-1]
+
+    @property
+    def real_path(self):
+        """Return the file system path of this resource"""
+        return self.project._get_resource_path(self.path)
+
+    def __eq__(self, obj):
+        return self.__class__ == obj.__class__ and self.path == obj.path
+
+    def __ne__(self, obj):
+        return not self.__eq__(obj)
+
+    def __hash__(self):
+        return hash(self.path)
+
+    def _perform_change(self, change_, description):
+        changes = change.ChangeSet(description)
+        changes.add_change(change_)
+        self.project.do(changes)
+
+
+class File(Resource):
+    """Represents a file"""
+
+    def __init__(self, project, name):
+        super(File, self).__init__(project, name)
+
+    def read(self):
+        data = self.read_bytes()
+        try:
+            return fscommands.file_data_to_unicode(data)
+        except UnicodeDecodeError as e:
+            raise exceptions.ModuleDecodeError(self.path, e.reason)
+
+    def read_bytes(self):
+        handle = open(self.real_path, 'rb')
+        try:
+            return handle.read()
+        finally:
+            handle.close()
+
+    def write(self, contents):
+        try:
+            if contents == self.read():
+                return
+        except IOError:
+            pass
+        self._perform_change(change.ChangeContents(self, contents),
+                             'Writing file <%s>' % self.path)
+
+    def is_folder(self):
+        return False
+
+    def create(self):
+        self.parent.create_file(self.name)
+
+
+class Folder(Resource):
+    """Represents a folder"""
+
+    def __init__(self, project, name):
+        super(Folder, self).__init__(project, name)
+
+    def is_folder(self):
+        return True
+
+    def get_children(self):
+        """Return the children of this folder"""
+        try:
+            children = os.listdir(self.real_path)
+        except OSError:
+            return []
+        result = []
+        for name in children:
+            try:
+                child = self.get_child(name)
+            except exceptions.ResourceNotFoundError:
+                continue
+            if not self.project.is_ignored(child):
+                result.append(self.get_child(name))
+        return result
+
+    def create_file(self, file_name):
+        self._perform_change(
+            change.CreateFile(self, file_name),
+            'Creating file <%s>' % self._get_child_path(file_name))
+        return self.get_child(file_name)
+
+    def create_folder(self, folder_name):
+        self._perform_change(
+            change.CreateFolder(self, folder_name),
+            'Creating folder <%s>' % self._get_child_path(folder_name))
+        return self.get_child(folder_name)
+
+    def _get_child_path(self, name):
+        if self.path:
+            return self.path + '/' + name
+        else:
+            return name
+
+    def get_child(self, name):
+        return self.project.get_resource(self._get_child_path(name))
+
+    def has_child(self, name):
+        try:
+            self.get_child(name)
+            return True
+        except exceptions.ResourceNotFoundError:
+            return False
+
+    def get_files(self):
+        return [resource for resource in self.get_children()
+                if not resource.is_folder()]
+
+    def get_folders(self):
+        return [resource for resource in self.get_children()
+                if resource.is_folder()]
+
+    def contains(self, resource):
+        if self == resource:
+            return False
+        return self.path == '' or resource.path.startswith(self.path + '/')
+
+    def create(self):
+        self.parent.create_folder(self.name)
+
+
+class _ResourceMatcher(object):
+
+    def __init__(self):
+        self.patterns = []
+        self._compiled_patterns = []
+
+    def set_patterns(self, patterns):
+        """Specify which resources to match
+
+        `patterns` is a `list` of `str`\s that can contain ``*`` and
+        ``?`` signs for matching resource names.
+
+        """
+        self._compiled_patterns = None
+        self.patterns = patterns
+
+    def _add_pattern(self, pattern):
+        re_pattern = pattern.replace('.', '\\.').\
+            replace('*', '[^/]*').replace('?', '[^/]').\
+            replace('//', '/(.*/)?')
+        re_pattern = '^(.*/)?' + re_pattern + '(/.*)?$'
+        self.compiled_patterns.append(re.compile(re_pattern))
+
+    def does_match(self, resource):
+        for pattern in self.compiled_patterns:
+            if pattern.match(resource.path):
+                return True
+        path = os.path.join(resource.project.address,
+                            *resource.path.split('/'))
+        if os.path.islink(path):
+            return True
+        return False
+
+    @property
+    def compiled_patterns(self):
+        if self._compiled_patterns is None:
+            self._compiled_patterns = []
+            for pattern in self.patterns:
+                self._add_pattern(pattern)
+        return self._compiled_patterns
diff --git a/venv/Lib/site-packages/rope/base/simplify.py b/venv/Lib/site-packages/rope/base/simplify.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc4cade4ab910989e3143c17df1180a2770794b9
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/simplify.py
@@ -0,0 +1,55 @@
+"""A module to ease code analysis
+
+This module is here to help source code analysis.
+"""
+import re
+
+from rope.base import codeanalyze, utils
+
+
+@utils.cached(7)
+def real_code(source):
+    """Simplify `source` for analysis
+
+    It replaces:
+
+    * comments with spaces
+    * strs with a new str filled with spaces
+    * implicit and explicit continuations with spaces
+    * tabs and semicolons with spaces
+
+    The resulting code is a lot easier to analyze if we are interested
+    only in offsets.
+    """
+    collector = codeanalyze.ChangeCollector(source)
+    for start, end in ignored_regions(source):
+        if source[start] == '#':
+            replacement = ' ' * (end - start)
+        else:
+            replacement = '"%s"' % (' ' * (end - start - 2))
+        collector.add_change(start, end, replacement)
+    source = collector.get_changed() or source
+    collector = codeanalyze.ChangeCollector(source)
+    parens = 0
+    for match in _parens.finditer(source):
+        i = match.start()
+        c = match.group()
+        if c in '({[':
+            parens += 1
+        if c in ')}]':
+            parens -= 1
+        if c == '\n' and parens > 0:
+            collector.add_change(i, i + 1, ' ')
+    source = collector.get_changed() or source
+    return source.replace('\\\n', '  ').replace('\t', ' ').replace(';', '\n')
+
+
+@utils.cached(7)
+def ignored_regions(source):
+    """Return ignored regions like strings and comments in `source` """
+    return [(match.start(), match.end()) for match in _str.finditer(source)]
+
+
+_str = re.compile('%s|%s' % (codeanalyze.get_comment_pattern(),
+                             codeanalyze.get_string_pattern()))
+_parens = re.compile(r'[\({\[\]}\)\n]')
diff --git a/venv/Lib/site-packages/rope/base/stdmods.py b/venv/Lib/site-packages/rope/base/stdmods.py
new file mode 100644
index 0000000000000000000000000000000000000000..7d5db1d10ba79250960165a20b50c7c450c6da08
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/stdmods.py
@@ -0,0 +1,65 @@
+import os
+import re
+import sys
+
+from rope.base import utils
+from rope.base.utils import pycompat
+
+
+def _stdlib_path():
+    if pycompat.PY2:
+        from distutils import sysconfig
+        return sysconfig.get_python_lib(standard_lib=True,
+                                        plat_specific=True)
+    elif pycompat.PY3:
+        import inspect
+        return os.path.dirname(inspect.getsourcefile(inspect))
+
+
+@utils.cached(1)
+def standard_modules():
+    return python_modules() | dynload_modules()
+
+
+@utils.cached(1)
+def python_modules():
+    result = set()
+    lib_path = _stdlib_path()
+    if os.path.exists(lib_path):
+        for name in os.listdir(lib_path):
+            path = os.path.join(lib_path, name)
+            if os.path.isdir(path):
+                if '-' not in name:
+                    result.add(name)
+            else:
+                if name.endswith('.py'):
+                    result.add(name[:-3])
+    return result
+
+
+def normalize_so_name(name):
+    """
+    Handle different types of python installations
+    """
+    if "cpython" in name:
+        return os.path.splitext(os.path.splitext(name)[0])[0]
+    # XXX: Special handling for Fedora python2 distribution
+    # See: https://github.com/python-rope/rope/issues/211
+    if name == "timemodule.so":
+        return "time"
+    return os.path.splitext(name)[0]
+
+
+@utils.cached(1)
+def dynload_modules():
+    result = set(sys.builtin_module_names)
+    dynload_path = os.path.join(_stdlib_path(), 'lib-dynload')
+    if os.path.exists(dynload_path):
+        for name in os.listdir(dynload_path):
+            path = os.path.join(dynload_path, name)
+            if os.path.isfile(path):
+                if name.endswith('.dll'):
+                    result.add(normalize_so_name(name))
+                if name.endswith('.so'):
+                    result.add(normalize_so_name(name))
+    return result
diff --git a/venv/Lib/site-packages/rope/base/taskhandle.py b/venv/Lib/site-packages/rope/base/taskhandle.py
new file mode 100644
index 0000000000000000000000000000000000000000..c1f01b984399454ca6ad6a095e83905904035a0e
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/taskhandle.py
@@ -0,0 +1,131 @@
+from rope.base import exceptions
+
+
+class TaskHandle(object):
+
+    def __init__(self, name='Task', interrupts=True):
+        """Construct a TaskHandle
+
+        If `interrupts` is `False` the task won't be interrupted by
+        calling `TaskHandle.stop()`.
+
+        """
+        self.name = name
+        self.interrupts = interrupts
+        self.stopped = False
+        self.job_sets = []
+        self.observers = []
+
+    def stop(self):
+        """Interrupts the refactoring"""
+        if self.interrupts:
+            self.stopped = True
+            self._inform_observers()
+
+    def current_jobset(self):
+        """Return the current `JobSet`"""
+        if self.job_sets:
+            return self.job_sets[-1]
+
+    def add_observer(self, observer):
+        """Register an observer for this task handle
+
+        The observer is notified whenever the task is stopped or
+        a job gets finished.
+
+        """
+        self.observers.append(observer)
+
+    def is_stopped(self):
+        return self.stopped
+
+    def get_jobsets(self):
+        return self.job_sets
+
+    def create_jobset(self, name='JobSet', count=None):
+        result = JobSet(self, name=name, count=count)
+        self.job_sets.append(result)
+        self._inform_observers()
+        return result
+
+    def _inform_observers(self):
+        for observer in list(self.observers):
+            observer()
+
+
+class JobSet(object):
+
+    def __init__(self, handle, name, count):
+        self.handle = handle
+        self.name = name
+        self.count = count
+        self.done = 0
+        self.job_name = None
+
+    def started_job(self, name):
+        self.check_status()
+        self.job_name = name
+        self.handle._inform_observers()
+
+    def finished_job(self):
+        self.check_status()
+        self.done += 1
+        self.handle._inform_observers()
+        self.job_name = None
+
+    def check_status(self):
+        if self.handle.is_stopped():
+            raise exceptions.InterruptedTaskError()
+
+    def get_active_job_name(self):
+        return self.job_name
+
+    def get_percent_done(self):
+        if self.count is not None and self.count > 0:
+            percent = self.done * 100 // self.count
+            return min(percent, 100)
+
+    def get_name(self):
+        return self.name
+
+
+class NullTaskHandle(object):
+
+    def __init__(self):
+        pass
+
+    def is_stopped(self):
+        return False
+
+    def stop(self):
+        pass
+
+    def create_jobset(self, *args, **kwds):
+        return NullJobSet()
+
+    def get_jobsets(self):
+        return []
+
+    def add_observer(self, observer):
+        pass
+
+
+class NullJobSet(object):
+
+    def started_job(self, name):
+        pass
+
+    def finished_job(self):
+        pass
+
+    def check_status(self):
+        pass
+
+    def get_active_job_name(self):
+        pass
+
+    def get_percent_done(self):
+        pass
+
+    def get_name(self):
+        pass
diff --git a/venv/Lib/site-packages/rope/base/utils/__init__.py b/venv/Lib/site-packages/rope/base/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0fba8596f180b9468765b76c7d881e5026b33cec
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/utils/__init__.py
@@ -0,0 +1,98 @@
+import sys
+import warnings
+
+
+def saveit(func):
+    """A decorator that caches the return value of a function"""
+
+    name = '_' + func.__name__
+
+    def _wrapper(self, *args, **kwds):
+        if not hasattr(self, name):
+            setattr(self, name, func(self, *args, **kwds))
+        return getattr(self, name)
+    return _wrapper
+
+cacheit = saveit
+
+
+def prevent_recursion(default):
+    """A decorator that returns the return value of `default` in recursions"""
+    def decorator(func):
+        name = '_calling_%s_' % func.__name__
+
+        def newfunc(self, *args, **kwds):
+            if getattr(self, name, False):
+                return default()
+            setattr(self, name, True)
+            try:
+                return func(self, *args, **kwds)
+            finally:
+                setattr(self, name, False)
+        return newfunc
+    return decorator
+
+
+def ignore_exception(exception_class):
+    """A decorator that ignores `exception_class` exceptions"""
+    def _decorator(func):
+        def newfunc(*args, **kwds):
+            try:
+                return func(*args, **kwds)
+            except exception_class:
+                pass
+        return newfunc
+    return _decorator
+
+
+def deprecated(message=None):
+    """A decorator for deprecated functions"""
+    def _decorator(func, message=message):
+        if message is None:
+            message = '%s is deprecated' % func.__name__
+
+        def newfunc(*args, **kwds):
+            warnings.warn(message, DeprecationWarning, stacklevel=2)
+            return func(*args, **kwds)
+        return newfunc
+    return _decorator
+
+
+def cached(size):
+    """A caching decorator based on parameter objects"""
+    def decorator(func):
+        cached_func = _Cached(func, size)
+        return lambda *a, **kw: cached_func(*a, **kw)
+    return decorator
+
+
+class _Cached(object):
+
+    def __init__(self, func, count):
+        self.func = func
+        self.cache = []
+        self.count = count
+
+    def __call__(self, *args, **kwds):
+        key = (args, kwds)
+        for cached_key, cached_result in self.cache:
+            if cached_key == key:
+                return cached_result
+        result = self.func(*args, **kwds)
+        self.cache.append((key, result))
+        if len(self.cache) > self.count:
+            del self.cache[0]
+        return result
+
+
+def resolve(str_or_obj):
+    """Returns object from string"""
+    from rope.base.utils.pycompat import string_types
+    if not isinstance(str_or_obj, string_types):
+        return str_or_obj
+    if '.' not in str_or_obj:
+        str_or_obj += '.'
+    mod_name, obj_name = str_or_obj.rsplit('.', 1)
+    __import__(mod_name)
+    mod = sys.modules[mod_name]
+    return getattr(mod, obj_name) if obj_name else mod
diff --git a/venv/Lib/site-packages/rope/base/utils/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/base/utils/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..029c533c3e0f46368753aeae139f6f968a1a584d
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/utils/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/utils/__pycache__/datastructures.cpython-37.pyc b/venv/Lib/site-packages/rope/base/utils/__pycache__/datastructures.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..adef60ff49710d1b811cd73edfbfb88c011ee573
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/utils/__pycache__/datastructures.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/utils/__pycache__/pycompat.cpython-37.pyc b/venv/Lib/site-packages/rope/base/utils/__pycache__/pycompat.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9dd514a8dbd0dd98d73b75ed5d321e18dbb31bcc
Binary files /dev/null and b/venv/Lib/site-packages/rope/base/utils/__pycache__/pycompat.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/base/utils/datastructures.py b/venv/Lib/site-packages/rope/base/utils/datastructures.py
new file mode 100644
index 0000000000000000000000000000000000000000..0cb16cf2b19ed0d2649b00c6b4f3f082bbb79312
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/utils/datastructures.py
@@ -0,0 +1,67 @@
+# this snippet was taken from this link
+# http://code.activestate.com/recipes/576694/
+
+import collections
+
+
+class OrderedSet(collections.MutableSet):
+
+    def __init__(self, iterable=None):
+        self.end = end = []
+        end += [None, end, end]  # sentinel
+        # node for doubly linked list
+        self.map = {}  # key --> [key, prev, next]
+        if iterable is not None:
+            self |= iterable
+
+    def __len__(self):
+        return len(self.map)
+
+    def __contains__(self, key):
+        return key in self.map
+
+    def add(self, key):
+        if key not in self.map:
+            end = self.end
+            curr = end[1]
+            curr[2] = end[1] = self.map[key] = [key, curr, end]
+
+    def intersection(self, set_b):
+        return OrderedSet([item for item in self if item in set_b])
+
+    def discard(self, key):
+        if key in self.map:
+            key, prev, next = self.map.pop(key)
+            prev[2] = next
+            next[1] = prev
+
+    def __iter__(self):
+        end = self.end
+        curr = end[2]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[2]
+
+    def __reversed__(self):
+        end = self.end
+        curr = end[1]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[1]
+
+    def pop(self, last=True):
+        if not self:
+            raise KeyError('set is empty')
+        key = self.end[1][0] if last else self.end[2][0]
+        self.discard(key)
+        return key
+
+    def __repr__(self):
+        if not self:
+            return '%s()' % (self.__class__.__name__,)
+        return '%s(%r)' % (self.__class__.__name__, list(self))
+
+    def __eq__(self, other):
+        if isinstance(other, OrderedSet):
+            return len(self) == len(other) and list(self) == list(other)
+        return set(self) == set(other)
diff --git a/venv/Lib/site-packages/rope/base/utils/pycompat.py b/venv/Lib/site-packages/rope/base/utils/pycompat.py
new file mode 100644
index 0000000000000000000000000000000000000000..367cf09228f4630a7381fb0cb3272b779c96dfff
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/utils/pycompat.py
@@ -0,0 +1,45 @@
+import sys
+import _ast
+# from rope.base import ast
+
+PY2 = sys.version_info[0] == 2
+PY27 = sys.version_info[0:2] >= (2, 7)
+PY3 = sys.version_info[0] == 3
+PY34 = sys.version_info[0:2] >= (3, 4)
+
+try:
+    str = unicode
+except NameError:  # PY3
+
+    str = str
+    string_types = (str,)
+    import builtins
+    ast_arg_type = _ast.arg
+
+    def execfile(fn, global_vars=None, local_vars=None):
+        with open(fn) as f:
+            code = compile(f.read(), fn, 'exec')
+            exec(code, global_vars or {}, local_vars)
+
+    def get_ast_arg_arg(node):
+        if isinstance(node, string_types):  # TODO: G21: Understand the Algorithm (Where it's used?)
+            return node
+        return node.arg
+
+    def get_ast_with_items(node):
+        return node.items
+
+else:  # PY2
+
+    string_types = (basestring,)
+    builtins = __import__('__builtin__')
+    ast_arg_type = _ast.Name
+    execfile = execfile
+
+    def get_ast_arg_arg(node):
+        if isinstance(node, string_types):  # Python2 arguments.vararg, arguments.kwarg
+            return node
+        return node.id
+
+    def get_ast_with_items(node):
+        return [node]
diff --git a/venv/Lib/site-packages/rope/base/worder.py b/venv/Lib/site-packages/rope/base/worder.py
new file mode 100644
index 0000000000000000000000000000000000000000..2436eafe29f113c8a44cf3af81911e982596e0db
--- /dev/null
+++ b/venv/Lib/site-packages/rope/base/worder.py
@@ -0,0 +1,551 @@
+import bisect
+import keyword
+
+import rope.base.simplify
+
+
+def get_name_at(resource, offset):
+    source_code = resource.read()
+    word_finder = Worder(source_code)
+    return word_finder.get_word_at(offset)
+
+
+class Worder(object):
+    """A class for finding boundaries of words and expressions
+
+    Note that in these methods, offset should be the index of the
+    character not the index of the character after it.
+    """
+
+    def __init__(self, code, handle_ignores=False):
+        simplified = rope.base.simplify.real_code(code)
+        self.code_finder = _RealFinder(simplified, code)
+        self.handle_ignores = handle_ignores
+        self.code = code
+
+    def _init_ignores(self):
+        ignores = rope.base.simplify.ignored_regions(self.code)
+        self.dumb_finder = _RealFinder(self.code, self.code)
+        self.starts = [ignored[0] for ignored in ignores]
+        self.ends = [ignored[1] for ignored in ignores]
+
+    def _context_call(self, name, offset):
+        if self.handle_ignores:
+            if not hasattr(self, 'starts'):
+                self._init_ignores()
+            start = bisect.bisect(self.starts, offset)
+            if start > 0 and offset < self.ends[start - 1]:
+                return getattr(self.dumb_finder, name)(offset)
+        return getattr(self.code_finder, name)(offset)
+
+    def get_primary_at(self, offset):
+        return self._context_call('get_primary_at', offset)
+
+    def get_word_at(self, offset):
+        return self._context_call('get_word_at', offset)
+
+    def get_primary_range(self, offset):
+        return self._context_call('get_primary_range', offset)
+
+    def get_splitted_primary_before(self, offset):
+        return self._context_call('get_splitted_primary_before', offset)
+
+    def get_word_range(self, offset):
+        return self._context_call('get_word_range', offset)
+
+    def is_function_keyword_parameter(self, offset):
+        return self.code_finder.is_function_keyword_parameter(offset)
+
+    def is_a_class_or_function_name_in_header(self, offset):
+        return self.code_finder.is_a_class_or_function_name_in_header(offset)
+
+    def is_from_statement_module(self, offset):
+        return self.code_finder.is_from_statement_module(offset)
+
+    def is_from_aliased(self, offset):
+        return self.code_finder.is_from_aliased(offset)
+
+    def is_import_statement_aliased_module(self, offset):
+        return self.code_finder.is_import_statement_aliased_module(offset)
+
+    def find_parens_start_from_inside(self, offset):
+        return self.code_finder.find_parens_start_from_inside(offset)
+
+    def is_a_name_after_from_import(self, offset):
+        return self.code_finder.is_a_name_after_from_import(offset)
+
+    def is_from_statement(self, offset):
+        return self.code_finder.is_from_statement(offset)
+
+    def get_from_aliased(self, offset):
+        return self.code_finder.get_from_aliased(offset)
+
+    def is_import_statement(self, offset):
+        return self.code_finder.is_import_statement(offset)
+
+    def is_assigned_here(self, offset):
+        return self.code_finder.is_assigned_here(offset)
+
+    def is_a_function_being_called(self, offset):
+        return self.code_finder.is_a_function_being_called(offset)
+
+    def get_word_parens_range(self, offset):
+        return self.code_finder.get_word_parens_range(offset)
+
+    def is_name_assigned_in_class_body(self, offset):
+        return self.code_finder.is_name_assigned_in_class_body(offset)
+
+    def is_on_function_call_keyword(self, offset):
+        return self.code_finder.is_on_function_call_keyword(offset)
+
+    def _find_parens_start(self, offset):
+        return self.code_finder._find_parens_start(offset)
+
+    def get_parameters(self, first, last):
+        return self.code_finder.get_parameters(first, last)
+
+    def get_from_module(self, offset):
+        return self.code_finder.get_from_module(offset)
+
+    def is_assigned_in_a_tuple_assignment(self, offset):
+        return self.code_finder.is_assigned_in_a_tuple_assignment(offset)
+
+    def get_assignment_type(self, offset):
+        return self.code_finder.get_assignment_type(offset)
+
+    def get_function_and_args_in_header(self, offset):
+        return self.code_finder.get_function_and_args_in_header(offset)
+
+    def get_lambda_and_args(self, offset):
+        return self.code_finder.get_lambda_and_args(offset)
+
+    def find_function_offset(self, offset):
+        return self.code_finder.find_function_offset(offset)
+
+
+class _RealFinder(object):
+
+    def __init__(self, code, raw):
+        self.code = code
+        self.raw = raw
+
+    def _find_word_start(self, offset):
+        current_offset = offset
+        while current_offset >= 0 and self._is_id_char(current_offset):
+            current_offset -= 1
+        return current_offset + 1
+
+    def _find_word_end(self, offset):
+        while offset + 1 < len(self.code) and self._is_id_char(offset + 1):
+            offset += 1
+        return offset
+
+    def _find_last_non_space_char(self, offset):
+        while offset >= 0 and self.code[offset].isspace():
+            if self.code[offset] == '\n':
+                return offset
+            offset -= 1
+        return max(-1, offset)
+
+    def get_word_at(self, offset):
+        offset = self._get_fixed_offset(offset)
+        return self.raw[self._find_word_start(offset):
+                        self._find_word_end(offset) + 1]
+
+    def _get_fixed_offset(self, offset):
+        if offset >= len(self.code):
+            return offset - 1
+        if not self._is_id_char(offset):
+            if offset > 0 and self._is_id_char(offset - 1):
+                return offset - 1
+            if offset < len(self.code) - 1 and self._is_id_char(offset + 1):
+                return offset + 1
+        return offset
+
+    def _is_id_char(self, offset):
+        return self.code[offset].isalnum() or self.code[offset] == '_'
+
+    def _find_string_start(self, offset):
+        kind = self.code[offset]
+        try:
+            return self.code.rindex(kind, 0, offset)
+        except ValueError:
+            return 0
+
+    def _find_parens_start(self, offset):
+        offset = self._find_last_non_space_char(offset - 1)
+        while offset >= 0 and self.code[offset] not in '[({':
+            if self.code[offset] not in ':,':
+                offset = self._find_primary_start(offset)
+            offset = self._find_last_non_space_char(offset - 1)
+        return offset
+
+    def _find_atom_start(self, offset):
+        old_offset = offset
+        if self.code[offset] == '\n':
+            return offset + 1
+        if self.code[offset].isspace():
+            offset = self._find_last_non_space_char(offset)
+        if self.code[offset] in '\'"':
+            return self._find_string_start(offset)
+        if self.code[offset] in ')]}':
+            return self._find_parens_start(offset)
+        if self._is_id_char(offset):
+            return self._find_word_start(offset)
+        return old_offset
+
+    def _find_primary_without_dot_start(self, offset):
+        """It tries to find the undotted primary start
+
+        It is different from `self._get_atom_start()` in that it
+        follows function calls, too; such as in ``f(x)``.
+
+        """
+        last_atom = offset
+        offset = self._find_last_non_space_char(last_atom)
+        while offset > 0 and self.code[offset] in ')]':
+            last_atom = self._find_parens_start(offset)
+            offset = self._find_last_non_space_char(last_atom - 1)
+        if offset >= 0 and (self.code[offset] in '"\'})]' or
+                            self._is_id_char(offset)):
+            atom_start = self._find_atom_start(offset)
+            if not keyword.iskeyword(self.code[atom_start:offset + 1]):
+                return atom_start
+        return last_atom
+
+    def _find_primary_start(self, offset):
+        if offset >= len(self.code):
+            offset = len(self.code) - 1
+        if self.code[offset] != '.':
+            offset = self._find_primary_without_dot_start(offset)
+        else:
+            offset = offset + 1
+        while offset > 0:
+            prev = self._find_last_non_space_char(offset - 1)
+            if offset <= 0 or self.code[prev] != '.':
+                break
+            offset = self._find_primary_without_dot_start(prev - 1)
+            if not self._is_id_char(offset):
+                break
+
+        return offset
+
+    def get_primary_at(self, offset):
+        offset = self._get_fixed_offset(offset)
+        start, end = self.get_primary_range(offset)
+        return self.raw[start:end].strip()
+
+    def get_splitted_primary_before(self, offset):
+        """returns expression, starting, starting_offset
+
+        This function is used in `rope.codeassist.assist` function.
+        """
+        if offset == 0:
+            return ('', '', 0)
+        end = offset - 1
+        word_start = self._find_atom_start(end)
+        real_start = self._find_primary_start(end)
+        if self.code[word_start:offset].strip() == '':
+            word_start = end
+        if self.code[end].isspace():
+            word_start = end
+        if self.code[real_start:word_start].strip() == '':
+            real_start = word_start
+        if real_start == word_start == end and not self._is_id_char(end):
+            return ('', '', offset)
+        if real_start == word_start:
+            return ('', self.raw[word_start:offset], word_start)
+        else:
+            if self.code[end] == '.':
+                return (self.raw[real_start:end], '', offset)
+            last_dot_position = word_start
+            if self.code[word_start] != '.':
+                last_dot_position = \
+                    self._find_last_non_space_char(word_start - 1)
+            last_char_position = \
+                self._find_last_non_space_char(last_dot_position - 1)
+            if self.code[word_start].isspace():
+                word_start = offset
+            return (self.raw[real_start:last_char_position + 1],
+                    self.raw[word_start:offset], word_start)
+
+    def _get_line_start(self, offset):
+        try:
+            return self.code.rindex('\n', 0, offset + 1)
+        except ValueError:
+            return 0
+
+    def _get_line_end(self, offset):
+        try:
+            return self.code.index('\n', offset)
+        except ValueError:
+            return len(self.code)
+
+    def is_name_assigned_in_class_body(self, offset):
+        word_start = self._find_word_start(offset - 1)
+        word_end = self._find_word_end(offset) + 1
+        if '.' in self.code[word_start:word_end]:
+            return False
+        line_start = self._get_line_start(word_start)
+        line = self.code[line_start:word_start].strip()
+        return not line and self.get_assignment_type(offset) == '='
+
+    def is_a_class_or_function_name_in_header(self, offset):
+        word_start = self._find_word_start(offset - 1)
+        line_start = self._get_line_start(word_start)
+        prev_word = self.code[line_start:word_start].strip()
+        return prev_word in ['def', 'class']
+
+    def _find_first_non_space_char(self, offset):
+        if offset >= len(self.code):
+            return len(self.code)
+        while offset < len(self.code) and self.code[offset].isspace():
+            if self.code[offset] == '\n':
+                return offset
+            offset += 1
+        return offset
+
+    def is_a_function_being_called(self, offset):
+        word_end = self._find_word_end(offset) + 1
+        next_char = self._find_first_non_space_char(word_end)
+        return next_char < len(self.code) and \
+            self.code[next_char] == '(' and \
+            not self.is_a_class_or_function_name_in_header(offset)
+
+    def _find_import_end(self, start):
+        return self._get_line_end(start)
+
+    def is_import_statement(self, offset):
+        try:
+            last_import = self.code.rindex('import ', 0, offset)
+        except ValueError:
+            return False
+        line_start = self._get_line_start(last_import)
+        return (self._find_import_end(last_import + 7) >= offset and
+                self._find_word_start(line_start) == last_import)
+
+    def is_from_statement(self, offset):
+        try:
+            last_from = self.code.rindex('from ', 0, offset)
+            from_import = self.code.index(' import ', last_from)
+            from_names = from_import + 8
+        except ValueError:
+            return False
+        from_names = self._find_first_non_space_char(from_names)
+        return self._find_import_end(from_names) >= offset
+
+    def is_from_statement_module(self, offset):
+        if offset >= len(self.code) - 1:
+            return False
+        stmt_start = self._find_primary_start(offset)
+        line_start = self._get_line_start(stmt_start)
+        prev_word = self.code[line_start:stmt_start].strip()
+        return prev_word == 'from'
+
+    def is_import_statement_aliased_module(self, offset):
+        if not self.is_import_statement(offset):
+            return False
+        try:
+            line_start = self._get_line_start(offset)
+            import_idx = self.code.rindex('import', line_start, offset)
+            imported_names = import_idx + 7
+        except ValueError:
+            return False
+        # Check if the offset is within the imported names
+        if (imported_names - 1 > offset or
+            self._find_import_end(imported_names) < offset):
+            return False
+        try:
+            end = self._find_word_end(offset)
+            as_end = min(self._find_word_end(end + 1), len(self.code))
+            as_start = self._find_word_start(as_end)
+            return self.code[as_start:as_end + 1] == 'as'
+        except ValueError:
+            return False
+
+    def is_a_name_after_from_import(self, offset):
+        try:
+            if len(self.code) > offset and self.code[offset] == '\n':
+                line_start = self._get_line_start(offset - 1)
+            else:
+                line_start = self._get_line_start(offset)
+            last_from = self.code.rindex('from ', line_start, offset)
+            from_import = self.code.index(' import ', last_from)
+            from_names = from_import + 8
+        except ValueError:
+            return False
+        if from_names - 1 > offset:
+            return False
+        return self._find_import_end(from_names) >= offset
+
+    def get_from_module(self, offset):
+        try:
+            last_from = self.code.rindex('from ', 0, offset)
+            import_offset = self.code.index(' import ', last_from)
+            end = self._find_last_non_space_char(import_offset)
+            return self.get_primary_at(end)
+        except ValueError:
+            pass
+
+    def is_from_aliased(self, offset):
+        if not self.is_a_name_after_from_import(offset):
+            return False
+        try:
+            end = self._find_word_end(offset)
+            as_end = min(self._find_word_end(end + 1), len(self.code))
+            as_start = self._find_word_start(as_end)
+            return self.code[as_start:as_end + 1] == 'as'
+        except ValueError:
+            return False
+
+    def get_from_aliased(self, offset):
+        try:
+            end = self._find_word_end(offset)
+            as_ = self._find_word_end(end + 1)
+            alias = self._find_word_end(as_ + 1)
+            start = self._find_word_start(alias)
+            return self.raw[start:alias + 1]
+        except ValueError:
+            pass
+
+    def is_function_keyword_parameter(self, offset):
+        word_end = self._find_word_end(offset)
+        if word_end + 1 == len(self.code):
+            return False
+        next_char = self._find_first_non_space_char(word_end + 1)
+        equals = self.code[next_char:next_char + 2]
+        if equals == '==' or not equals.startswith('='):
+            return False
+        word_start = self._find_word_start(offset)
+        prev_char = self._find_last_non_space_char(word_start - 1)
+        return prev_char - 1 >= 0 and self.code[prev_char] in ',('
+
+    def is_on_function_call_keyword(self, offset):
+        stop = self._get_line_start(offset)
+        if self._is_id_char(offset):
+            offset = self._find_word_start(offset) - 1
+        offset = self._find_last_non_space_char(offset)
+        if offset <= stop or self.code[offset] not in '(,':
+            return False
+        parens_start = self.find_parens_start_from_inside(offset)
+        return stop < parens_start
+
+    def find_parens_start_from_inside(self, offset):
+        stop = self._get_line_start(offset)
+        while offset > stop:
+            if self.code[offset] == '(':
+                break
+            if self.code[offset] != ',':
+                offset = self._find_primary_start(offset)
+            offset -= 1
+        return max(stop, offset)
+
+    def is_assigned_here(self, offset):
+        return self.get_assignment_type(offset) is not None
+
+    def get_assignment_type(self, offset):
+        # XXX: does not handle tuple assignments
+        word_end = self._find_word_end(offset)
+        next_char = self._find_first_non_space_char(word_end + 1)
+        single = self.code[next_char:next_char + 1]
+        double = self.code[next_char:next_char + 2]
+        triple = self.code[next_char:next_char + 3]
+        if double not in ('==', '<=', '>=', '!='):
+            for op in [single, double, triple]:
+                if op.endswith('='):
+                    return op
+
+    def get_primary_range(self, offset):
+        start = self._find_primary_start(offset)
+        end = self._find_word_end(offset) + 1
+        return (start, end)
+
+    def get_word_range(self, offset):
+        offset = max(0, offset)
+        start = self._find_word_start(offset)
+        end = self._find_word_end(offset) + 1
+        return (start, end)
+
+    def get_word_parens_range(self, offset, opening='(', closing=')'):
+        end = self._find_word_end(offset)
+        start_parens = self.code.index(opening, end)
+        index = start_parens
+        open_count = 0
+        while index < len(self.code):
+            if self.code[index] == opening:
+                open_count += 1
+            if self.code[index] == closing:
+                open_count -= 1
+            if open_count == 0:
+                return (start_parens, index + 1)
+            index += 1
+        return (start_parens, index)
+
+    def get_parameters(self, first, last):
+        keywords = []
+        args = []
+        current = self._find_last_non_space_char(last - 1)
+        while current > first:
+            primary_start = current
+            current = self._find_primary_start(current)
+            while current != first and (self.code[current] not in '=,'
+                    or self.code[current-1] in '=!<>'):
+                current = self._find_last_non_space_char(current - 1)
+            primary = self.raw[current + 1:primary_start + 1].strip()
+            if self.code[current] == '=':
+                primary_start = current - 1
+                current -= 1
+                while current != first and self.code[current] not in ',':
+                    current = self._find_last_non_space_char(current - 1)
+                param_name = self.raw[current + 1:primary_start + 1].strip()
+                keywords.append((param_name, primary))
+            else:
+                args.append(primary)
+            current = self._find_last_non_space_char(current - 1)
+        args.reverse()
+        keywords.reverse()
+        return args, keywords
+
+    def is_assigned_in_a_tuple_assignment(self, offset):
+        start = self._get_line_start(offset)
+        end = self._get_line_end(offset)
+        primary_start = self._find_primary_start(offset)
+        primary_end = self._find_word_end(offset)
+
+        prev_char_offset = self._find_last_non_space_char(primary_start - 1)
+        next_char_offset = self._find_first_non_space_char(primary_end + 1)
+        next_char = prev_char = ''
+        if prev_char_offset >= start:
+            prev_char = self.code[prev_char_offset]
+        if next_char_offset < end:
+            next_char = self.code[next_char_offset]
+        try:
+            equals_offset = self.code.index('=', start, end)
+        except ValueError:
+            return False
+        if prev_char not in '(,' and next_char not in ',)':
+            return False
+        parens_start = self.find_parens_start_from_inside(offset)
+        # XXX: only handling (x, y) = value
+        return offset < equals_offset and \
+            self.code[start:parens_start].strip() == ''
+
+    def get_function_and_args_in_header(self, offset):
+        offset = self.find_function_offset(offset)
+        lparens, rparens = self.get_word_parens_range(offset)
+        return self.raw[offset:rparens + 1]
+
+    def find_function_offset(self, offset, definition='def '):
+        while True:
+            offset = self.code.index(definition, offset)
+            if offset == 0 or not self._is_id_char(offset - 1):
+                break
+            offset += 1
+        def_ = offset + 4
+        return self._find_first_non_space_char(def_)
+
+    def get_lambda_and_args(self, offset):
+        offset = self.find_function_offset(offset, definition='lambda ')
+        lparens, rparens = self.get_word_parens_range(offset, opening=' ',
+                                                      closing=':')
+        return self.raw[offset:rparens + 1]
diff --git a/venv/Lib/site-packages/rope/contrib/__init__.py b/venv/Lib/site-packages/rope/contrib/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d3f837ef48aa3892a2f0b20aae33f0193449bfe
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/__init__.py
@@ -0,0 +1,7 @@
+"""rope IDE tools package
+
+This package contains modules that can be used in IDEs
+but do not depend on the UI.  So these modules will be used
+by `rope.ui` modules.
+
+"""
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..779f43a5bfd071acd4268bc87cc0908f796c3f70
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/autoimport.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/autoimport.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0214fceaf2072ed6380a0286fcbe53279e7bde28
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/autoimport.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/changestack.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/changestack.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c9ce91d0aba3d7091074777aa0e14b6c78a84193
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/changestack.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/codeassist.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/codeassist.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2b5f211b036650bcaa360fcb39c7d24bb42c8a0d
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/codeassist.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/finderrors.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/finderrors.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..36bc2cab8c0ec1827348a03e7296ea1933af9a21
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/finderrors.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/findit.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/findit.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..970254fff5b787056692d2a2fa9de68c0dae5be0
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/findit.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/fixmodnames.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/fixmodnames.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..82b498d058f3e46a801677020056c2b6fb989d50
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/fixmodnames.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/fixsyntax.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/fixsyntax.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f66ae8dd7b60788e74c809ce21c8ed38eddd5024
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/fixsyntax.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/__pycache__/generate.cpython-37.pyc b/venv/Lib/site-packages/rope/contrib/__pycache__/generate.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3bfad08e48d18d46be0c76c72d1027c61243d11d
Binary files /dev/null and b/venv/Lib/site-packages/rope/contrib/__pycache__/generate.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/contrib/autoimport.py b/venv/Lib/site-packages/rope/contrib/autoimport.py
new file mode 100644
index 0000000000000000000000000000000000000000..9670080cf7f3c223f7e84156089c6c45e2a5db5b
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/autoimport.py
@@ -0,0 +1,222 @@
+import re
+
+from rope.base import builtins
+from rope.base import exceptions
+from rope.base import libutils
+from rope.base import pynames
+from rope.base import pyobjects
+from rope.base import resources
+from rope.base import resourceobserver
+from rope.base import taskhandle
+from rope.refactor import importutils
+
+
+class AutoImport(object):
+    """A class for finding the module that provides a name
+
+    This class maintains a cache of global names in python modules.
+    Note that this cache is not accurate and might be out of date.
+
+    """
+
+    def __init__(self, project, observe=True, underlined=False):
+        """Construct an AutoImport object
+
+        If `observe` is `True`, listen for project changes and update
+        the cache.
+
+        If `underlined` is `True`, underlined names are cached, too.
+        """
+        self.project = project
+        self.underlined = underlined
+        self.names = project.data_files.read_data('globalnames')
+        if self.names is None:
+            self.names = {}
+        project.data_files.add_write_hook(self._write)
+        # XXX: using a filtered observer
+        observer = resourceobserver.ResourceObserver(
+            changed=self._changed, moved=self._moved, removed=self._removed)
+        if observe:
+            project.add_observer(observer)
+
+    def import_assist(self, starting):
+        """Return a list of ``(name, module)`` tuples
+
+        This function tries to find modules that have a global name
+        that starts with `starting`.
+        """
+        # XXX: breaking if gave up! use generators
+        result = []
+        for module in self.names:
+            for global_name in self.names[module]:
+                if global_name.startswith(starting):
+                    result.append((global_name, module))
+        return result
+
+    def get_modules(self, name):
+        """Return the list of modules that have global `name`"""
+        result = []
+        for module in self.names:
+            if name in self.names[module]:
+                result.append(module)
+        return result
+
+    def get_all_names(self):
+        """Return the list of all cached global names"""
+        result = set()
+        for module in self.names:
+            result.update(set(self.names[module]))
+        return result
+
+    def get_name_locations(self, name):
+        """Return a list of ``(resource, lineno)`` tuples"""
+        result = []
+        for module in self.names:
+            if name in self.names[module]:
+                try:
+                    pymodule = self.project.get_module(module)
+                    if name in pymodule:
+                        pyname = pymodule[name]
+                        module, lineno = pyname.get_definition_location()
+                        if module is not None:
+                            resource = module.get_module().get_resource()
+                            if resource is not None and lineno is not None:
+                                result.append((resource, lineno))
+                except exceptions.ModuleNotFoundError:
+                    pass
+        return result
+
+    def generate_cache(self, resources=None, underlined=None,
+                       task_handle=taskhandle.NullTaskHandle()):
+        """Generate global name cache for project files
+
+        If `resources` is a list of `rope.base.resource.File`\s, only
+        those files are searched; otherwise all python modules in the
+        project are cached.
+
+        """
+        if resources is None:
+            resources = self.project.get_python_files()
+        job_set = task_handle.create_jobset(
+            'Generatig autoimport cache', len(resources))
+        for file in resources:
+            job_set.started_job('Working on <%s>' % file.path)
+            self.update_resource(file, underlined)
+            job_set.finished_job()
+
+    def generate_modules_cache(self, modules, underlined=None,
+                               task_handle=taskhandle.NullTaskHandle()):
+        """Generate global name cache for modules listed in `modules`"""
+        job_set = task_handle.create_jobset(
+            'Generatig autoimport cache for modules', len(modules))
+        for modname in modules:
+            job_set.started_job('Working on <%s>' % modname)
+            if modname.endswith('.*'):
+                mod = self.project.find_module(modname[:-2])
+                if mod:
+                    for sub in submodules(mod):
+                        self.update_resource(sub, underlined)
+            else:
+                self.update_module(modname, underlined)
+            job_set.finished_job()
+
+    def clear_cache(self):
+        """Clear all entries in global-name cache
+
+        It might be a good idea to use this function before
+        regenerating global names.
+
+        """
+        self.names.clear()
+
+    def find_insertion_line(self, code):
+        """Guess at what line the new import should be inserted"""
+        match = re.search(r'^(def|class)\s+', code)
+        if match is not None:
+            code = code[:match.start()]
+        try:
+            pymodule = libutils.get_string_module(self.project, code)
+        except exceptions.ModuleSyntaxError:
+            return 1
+        testmodname = '__rope_testmodule_rope'
+        importinfo = importutils.NormalImport(((testmodname, None),))
+        module_imports = importutils.get_module_imports(self.project,
+                                                        pymodule)
+        module_imports.add_import(importinfo)
+        code = module_imports.get_changed_source()
+        offset = code.index(testmodname)
+        lineno = code.count('\n', 0, offset) + 1
+        return lineno
+
+    def update_resource(self, resource, underlined=None):
+        """Update the cache for global names in `resource`"""
+        try:
+            pymodule = self.project.get_pymodule(resource)
+            modname = self._module_name(resource)
+            self._add_names(pymodule, modname, underlined)
+        except exceptions.ModuleSyntaxError:
+            pass
+
+    def update_module(self, modname, underlined=None):
+        """Update the cache for global names in `modname` module
+
+        `modname` is the name of a module.
+        """
+        try:
+            pymodule = self.project.get_module(modname)
+            self._add_names(pymodule, modname, underlined)
+        except exceptions.ModuleNotFoundError:
+            pass
+
+    def _module_name(self, resource):
+        return libutils.modname(resource)
+
+    def _add_names(self, pymodule, modname, underlined):
+        if underlined is None:
+            underlined = self.underlined
+        globals = []
+        if isinstance(pymodule, pyobjects.PyDefinedObject):
+            attributes = pymodule._get_structural_attributes()
+        else:
+            attributes = pymodule.get_attributes()
+        for name, pyname in attributes.items():
+            if not underlined and name.startswith('_'):
+                continue
+            if isinstance(pyname, (pynames.AssignedName, pynames.DefinedName)):
+                globals.append(name)
+            if isinstance(pymodule, builtins.BuiltinModule):
+                globals.append(name)
+        self.names[modname] = globals
+
+    def _write(self):
+        self.project.data_files.write_data('globalnames', self.names)
+
+    def _changed(self, resource):
+        if not resource.is_folder():
+            self.update_resource(resource)
+
+    def _moved(self, resource, newresource):
+        if not resource.is_folder():
+            modname = self._module_name(resource)
+            if modname in self.names:
+                del self.names[modname]
+            self.update_resource(newresource)
+
+    def _removed(self, resource):
+        if not resource.is_folder():
+            modname = self._module_name(resource)
+            if modname in self.names:
+                del self.names[modname]
+
+
+def submodules(mod):
+    if isinstance(mod, resources.File):
+        if mod.name.endswith('.py') and mod.name != '__init__.py':
+            return set([mod])
+        return set()
+    if not mod.has_child('__init__.py'):
+        return set()
+    result = set([mod])
+    for child in mod.get_children():
+        result |= submodules(child)
+    return result
diff --git a/venv/Lib/site-packages/rope/contrib/changestack.py b/venv/Lib/site-packages/rope/contrib/changestack.py
new file mode 100644
index 0000000000000000000000000000000000000000..70f2271f7c640229788823cdda7c6df18ea787de
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/changestack.py
@@ -0,0 +1,52 @@
+"""For performing many refactorings as a single command
+
+`changestack` module can be used to perform many refactorings on top
+of each other as one bigger command.  It can be used like::
+
+  stack = ChangeStack(project, 'my big command')
+
+  #..
+  stack.push(refactoring1.get_changes())
+  #..
+  stack.push(refactoring2.get_changes())
+  #..
+  stack.push(refactoringX.get_changes())
+
+  stack.pop_all()
+  changes = stack.merged()
+
+Now `changes` can be previewed or performed as before.
+"""
+
+from rope.base import change
+
+
+class ChangeStack(object):
+
+    def __init__(self, project, description='merged changes'):
+        self.project = project
+        self.description = description
+        self.stack = []
+
+    def push(self, changes):
+        self.stack.append(changes)
+        self.project.do(changes)
+
+    def pop_all(self):
+        for i in range(len(self.stack)):
+            self.project.history.undo(drop=True)
+
+    def merged(self):
+        result = change.ChangeSet(self.description)
+        for changes in self.stack:
+            for c in self._basic_changes(changes):
+                result.add_change(c)
+        return result
+
+    def _basic_changes(self, changes):
+        if isinstance(changes, change.ChangeSet):
+            for child in changes.changes:
+                for atom in self._basic_changes(child):
+                    yield atom
+        else:
+            yield changes
diff --git a/venv/Lib/site-packages/rope/contrib/codeassist.py b/venv/Lib/site-packages/rope/contrib/codeassist.py
new file mode 100644
index 0000000000000000000000000000000000000000..92c1bfc275c77c0b2985545426f736a5ed37dfde
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/codeassist.py
@@ -0,0 +1,695 @@
+import keyword
+import sys
+import warnings
+
+import rope.base.codeanalyze
+import rope.base.evaluate
+from rope.base import builtins
+from rope.base import exceptions
+from rope.base import libutils
+from rope.base import pynames
+from rope.base import pynamesdef
+from rope.base import pyobjects
+from rope.base import pyobjectsdef
+from rope.base import pyscopes
+from rope.base import worder
+from rope.contrib import fixsyntax
+from rope.refactor import functionutils
+
+
+def code_assist(project, source_code, offset, resource=None,
+                templates=None, maxfixes=1, later_locals=True):
+    """Return python code completions as a list of `CodeAssistProposal`\s
+
+    `resource` is a `rope.base.resources.Resource` object.  If
+    provided, relative imports are handled.
+
+    `maxfixes` is the maximum number of errors to fix if the code has
+    errors in it.
+
+    If `later_locals` is `False` names defined in this scope and after
+    this line is ignored.
+
+    """
+    if templates is not None:
+        warnings.warn('Codeassist no longer supports templates',
+                      DeprecationWarning, stacklevel=2)
+    assist = _PythonCodeAssist(
+        project, source_code, offset, resource=resource,
+        maxfixes=maxfixes, later_locals=later_locals)
+    return assist()
+
+
+def starting_offset(source_code, offset):
+    """Return the offset in which the completion should be inserted
+
+    Usually code assist proposals should be inserted like::
+
+        completion = proposal.name
+        result = (source_code[:starting_offset] +
+                  completion + source_code[offset:])
+
+    Where starting_offset is the offset returned by this function.
+
+    """
+    word_finder = worder.Worder(source_code, True)
+    expression, starting, starting_offset = \
+        word_finder.get_splitted_primary_before(offset)
+    return starting_offset
+
+
+def get_doc(project, source_code, offset, resource=None, maxfixes=1):
+    """Get the pydoc"""
+    fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes)
+    pyname = fixer.pyname_at(offset)
+    if pyname is None:
+        return None
+    pyobject = pyname.get_object()
+    return PyDocExtractor().get_doc(pyobject)
+
+
+def get_calltip(project, source_code, offset, resource=None,
+                maxfixes=1, ignore_unknown=False, remove_self=False):
+    """Get the calltip of a function
+
+    The format of the returned string is
+    ``module_name.holding_scope_names.function_name(arguments)``.  For
+    classes `__init__()` and for normal objects `__call__()` function
+    is used.
+
+    Note that the offset is on the function itself *not* after the its
+    open parenthesis.  (Actually it used to be the other way but it
+    was easily confused when string literals were involved.  So I
+    decided it is better for it not to try to be too clever when it
+    cannot be clever enough).  You can use a simple search like::
+
+        offset = source_code.rindex('(', 0, offset) - 1
+
+    to handle simple situations.
+
+    If `ignore_unknown` is `True`, `None` is returned for functions
+    without source-code like builtins and extensions.
+
+    If `remove_self` is `True`, the first parameter whose name is self
+    will be removed for methods.
+    """
+    fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes)
+    pyname = fixer.pyname_at(offset)
+    if pyname is None:
+        return None
+    pyobject = pyname.get_object()
+    return PyDocExtractor().get_calltip(pyobject, ignore_unknown, remove_self)
+
+
+def get_definition_location(project, source_code, offset,
+                            resource=None, maxfixes=1):
+    """Return the definition location of the python name at `offset`
+
+    Return a (`rope.base.resources.Resource`, lineno) tuple.  If no
+    `resource` is given and the definition is inside the same module,
+    the first element of the returned tuple would be `None`.  If the
+    location cannot be determined ``(None, None)`` is returned.
+
+    """
+    fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes)
+    pyname = fixer.pyname_at(offset)
+    if pyname is not None:
+        module, lineno = pyname.get_definition_location()
+        if module is not None:
+            return module.get_module().get_resource(), lineno
+    return (None, None)
+
+
+def find_occurrences(*args, **kwds):
+    import rope.contrib.findit
+    warnings.warn('Use `rope.contrib.findit.find_occurrences()` instead',
+                  DeprecationWarning, stacklevel=2)
+    return rope.contrib.findit.find_occurrences(*args, **kwds)
+
+
+def get_canonical_path(project, resource, offset):
+    """Get the canonical path to an object.
+
+    Given the offset of the object, this returns a list of
+    (name, name_type) tuples representing the canonical path to the
+    object. For example, the 'x' in the following code:
+
+        class Foo(object):
+            def bar(self):
+                class Qux(object):
+                    def mux(self, x):
+                        pass
+
+    we will return:
+
+        [('Foo', 'CLASS'), ('bar', 'FUNCTION'), ('Qux', 'CLASS'),
+         ('mux', 'FUNCTION'), ('x', 'PARAMETER')]
+
+    `resource` is a `rope.base.resources.Resource` object.
+
+    `offset` is the offset of the pyname you want the path to.
+
+    """
+    # Retrieve the PyName.
+    pymod = project.get_pymodule(resource)
+    pyname = rope.base.evaluate.eval_location(pymod, offset)
+
+    # Now get the location of the definition and its containing scope.
+    defmod, lineno = pyname.get_definition_location()
+    if not defmod:
+        return None
+    scope = defmod.get_scope().get_inner_scope_for_line(lineno)
+
+    # Start with the name of the object we're interested in.
+    names = []
+    if isinstance(pyname, pynamesdef.ParameterName):
+        names = [(worder.get_name_at(pymod.get_resource(), offset),
+                  'PARAMETER') ]
+    elif isinstance(pyname, pynamesdef.AssignedName):
+        names = [(worder.get_name_at(pymod.get_resource(), offset),
+                  'VARIABLE')]
+
+    # Collect scope names.
+    while scope.parent:
+        if isinstance(scope, pyscopes.FunctionScope):
+            scope_type = 'FUNCTION'
+        elif isinstance(scope, pyscopes.ClassScope):
+            scope_type = 'CLASS'
+        else:
+            scope_type = None
+        names.append((scope.pyobject.get_name(), scope_type))
+        scope = scope.parent
+
+    names.append((defmod.get_resource().real_path, 'MODULE'))
+    names.reverse()
+    return names
+
+
+class CompletionProposal(object):
+    """A completion proposal
+
+    The `scope` instance variable shows where proposed name came from
+    and can be 'global', 'local', 'builtin', 'attribute', 'keyword',
+    'imported', 'parameter_keyword'.
+
+    The `type` instance variable shows the approximate type of the
+    proposed object and can be 'instance', 'class', 'function', 'module',
+    and `None`.
+
+    All possible relations between proposal's `scope` and `type` are shown
+    in the table below (different scopes in rows and types in columns):
+
+                      | instance | class | function | module | None
+                local |    +     |   +   |    +     |   +    |
+               global |    +     |   +   |    +     |   +    |
+              builtin |    +     |   +   |    +     |        |
+            attribute |    +     |   +   |    +     |   +    |
+             imported |    +     |   +   |    +     |   +    |
+              keyword |          |       |          |        |  +
+    parameter_keyword |          |       |          |        |  +
+
+    """
+
+    def __init__(self, name, scope, pyname=None):
+        self.name = name
+        self.pyname = pyname
+        self.scope = self._get_scope(scope)
+
+    def __str__(self):
+        return '%s (%s, %s)' % (self.name, self.scope, self.type)
+
+    def __repr__(self):
+        return str(self)
+
+    @property
+    def parameters(self):
+        """The names of the parameters the function takes.
+
+        Returns None if this completion is not a function.
+        """
+        pyname = self.pyname
+        if isinstance(pyname, pynames.ImportedName):
+            pyname = pyname._get_imported_pyname()
+        if isinstance(pyname, pynames.DefinedName):
+            pyobject = pyname.get_object()
+            if isinstance(pyobject, pyobjects.AbstractFunction):
+                return pyobject.get_param_names()
+
+    @property
+    def type(self):
+        pyname = self.pyname
+        if isinstance(pyname, builtins.BuiltinName):
+            pyobject = pyname.get_object()
+            if isinstance(pyobject, builtins.BuiltinFunction):
+                return 'function'
+            elif isinstance(pyobject, builtins.BuiltinClass):
+                return 'class'
+            elif isinstance(pyobject, builtins.BuiltinObject) or \
+                    isinstance(pyobject, builtins.BuiltinName):
+                return 'instance'
+        elif isinstance(pyname, pynames.ImportedModule):
+            return 'module'
+        elif isinstance(pyname, pynames.ImportedName) or \
+                isinstance(pyname, pynames.DefinedName):
+            pyobject = pyname.get_object()
+            if isinstance(pyobject, pyobjects.AbstractFunction):
+                return 'function'
+            if isinstance(pyobject, pyobjects.AbstractClass):
+                return 'class'
+        return 'instance'
+
+    def _get_scope(self, scope):
+        if isinstance(self.pyname, builtins.BuiltinName):
+            return 'builtin'
+        if isinstance(self.pyname, pynames.ImportedModule) or \
+           isinstance(self.pyname, pynames.ImportedName):
+            return 'imported'
+        return scope
+
+    def get_doc(self):
+        """Get the proposed object's docstring.
+
+        Returns None if it can not be get.
+        """
+        if not self.pyname:
+            return None
+        pyobject = self.pyname.get_object()
+        if not hasattr(pyobject, 'get_doc'):
+            return None
+        return self.pyname.get_object().get_doc()
+
+    @property
+    def kind(self):
+        warnings.warn("the proposal's `kind` property is deprecated, "
+                      "use `scope` instead")
+        return self.scope
+
+
+# leaved for backward compatibility
+CodeAssistProposal = CompletionProposal
+
+
+class NamedParamProposal(CompletionProposal):
+    """A parameter keyword completion proposal
+
+    Holds reference to ``_function`` -- the function which
+    parameter ``name`` belongs to. This allows to determine
+    default value for this parameter.
+    """
+    def __init__(self, name, function):
+        self.argname = name
+        name = '%s=' % name
+        super(NamedParamProposal, self).__init__(name, 'parameter_keyword')
+        self._function = function
+
+    def get_default(self):
+        """Get a string representation of a param's default value.
+
+        Returns None if there is no default value for this param.
+        """
+        definfo = functionutils.DefinitionInfo.read(self._function)
+        for arg, default in definfo.args_with_defaults:
+            if self.argname == arg:
+                return default
+        return None
+
+
+def sorted_proposals(proposals, scopepref=None, typepref=None):
+    """Sort a list of proposals
+
+    Return a sorted list of the given `CodeAssistProposal`\s.
+
+    `scopepref` can be a list of proposal scopes.  Defaults to
+    ``['parameter_keyword', 'local', 'global', 'imported',
+    'attribute', 'builtin', 'keyword']``.
+
+    `typepref` can be a list of proposal types.  Defaults to
+    ``['class', 'function', 'instance', 'module', None]``.
+    (`None` stands for completions with no type like keywords.)
+    """
+    sorter = _ProposalSorter(proposals, scopepref, typepref)
+    return sorter.get_sorted_proposal_list()
+
+
+def starting_expression(source_code, offset):
+    """Return the expression to complete"""
+    word_finder = worder.Worder(source_code, True)
+    expression, starting, starting_offset = \
+        word_finder.get_splitted_primary_before(offset)
+    if expression:
+        return expression + '.' + starting
+    return starting
+
+
+def default_templates():
+    warnings.warn('default_templates() is deprecated.',
+                  DeprecationWarning, stacklevel=2)
+    return {}
+
+
+class _PythonCodeAssist(object):
+
+    def __init__(self, project, source_code, offset, resource=None,
+                 maxfixes=1, later_locals=True):
+        self.project = project
+        self.code = source_code
+        self.resource = resource
+        self.maxfixes = maxfixes
+        self.later_locals = later_locals
+        self.word_finder = worder.Worder(source_code, True)
+        self.expression, self.starting, self.offset = \
+            self.word_finder.get_splitted_primary_before(offset)
+
+    keywords = keyword.kwlist
+
+    def _find_starting_offset(self, source_code, offset):
+        current_offset = offset - 1
+        while current_offset >= 0 and (source_code[current_offset].isalnum() or
+                                       source_code[current_offset] in '_'):
+            current_offset -= 1
+        return current_offset + 1
+
+    def _matching_keywords(self, starting):
+        result = []
+        for kw in self.keywords:
+            if kw.startswith(starting):
+                result.append(CompletionProposal(kw, 'keyword'))
+        return result
+
+    def __call__(self):
+        if self.offset > len(self.code):
+            return []
+        completions = list(self._code_completions().values())
+        if self.expression.strip() == '' and self.starting.strip() != '':
+            completions.extend(self._matching_keywords(self.starting))
+        return completions
+
+    def _dotted_completions(self, module_scope, holding_scope):
+        result = {}
+        found_pyname = rope.base.evaluate.eval_str(holding_scope,
+                                                   self.expression)
+        if found_pyname is not None:
+            element = found_pyname.get_object()
+            compl_scope = 'attribute'
+            if isinstance(element, (pyobjectsdef.PyModule,
+                                    pyobjectsdef.PyPackage)):
+                compl_scope = 'imported'
+            for name, pyname in element.get_attributes().items():
+                if name.startswith(self.starting):
+                    result[name] = CompletionProposal(name, compl_scope,
+                                                      pyname)
+        return result
+
+    def _undotted_completions(self, scope, result, lineno=None):
+        if scope.parent is not None:
+            self._undotted_completions(scope.parent, result)
+        if lineno is None:
+            names = scope.get_propagated_names()
+        else:
+            names = scope.get_names()
+        for name, pyname in names.items():
+            if name.startswith(self.starting):
+                compl_scope = 'local'
+                if scope.get_kind() == 'Module':
+                    compl_scope = 'global'
+                if lineno is None or self.later_locals or \
+                   not self._is_defined_after(scope, pyname, lineno):
+                    result[name] = CompletionProposal(name, compl_scope,
+                                                      pyname)
+
+    def _from_import_completions(self, pymodule):
+        module_name = self.word_finder.get_from_module(self.offset)
+        if module_name is None:
+            return {}
+        pymodule = self._find_module(pymodule, module_name)
+        result = {}
+        for name in pymodule:
+            if name.startswith(self.starting):
+                result[name] = CompletionProposal(name, scope='global',
+                                                  pyname=pymodule[name])
+        return result
+
+    def _find_module(self, pymodule, module_name):
+        dots = 0
+        while module_name[dots] == '.':
+            dots += 1
+        pyname = pynames.ImportedModule(pymodule,
+                                        module_name[dots:], dots)
+        return pyname.get_object()
+
+    def _is_defined_after(self, scope, pyname, lineno):
+        location = pyname.get_definition_location()
+        if location is not None and location[1] is not None:
+            if location[0] == scope.pyobject.get_module() and \
+               lineno <= location[1] <= scope.get_end():
+                return True
+
+    def _code_completions(self):
+        lineno = self.code.count('\n', 0, self.offset) + 1
+        fixer = fixsyntax.FixSyntax(self.project, self.code,
+                                    self.resource, self.maxfixes)
+        pymodule = fixer.get_pymodule()
+        module_scope = pymodule.get_scope()
+        code = pymodule.source_code
+        lines = code.split('\n')
+        result = {}
+        start = fixsyntax._logical_start(lines, lineno)
+        indents = fixsyntax._get_line_indents(lines[start - 1])
+        inner_scope = module_scope.get_inner_scope_for_line(start, indents)
+        if self.word_finder.is_a_name_after_from_import(self.offset):
+            return self._from_import_completions(pymodule)
+        if self.expression.strip() != '':
+            result.update(self._dotted_completions(module_scope, inner_scope))
+        else:
+            result.update(self._keyword_parameters(module_scope.pyobject,
+                                                   inner_scope))
+            self._undotted_completions(inner_scope, result, lineno=lineno)
+        return result
+
+    def _keyword_parameters(self, pymodule, scope):
+        offset = self.offset
+        if offset == 0:
+            return {}
+        word_finder = worder.Worder(self.code, True)
+        if word_finder.is_on_function_call_keyword(offset - 1):
+            function_parens = word_finder.\
+                find_parens_start_from_inside(offset - 1)
+            primary = word_finder.get_primary_at(function_parens - 1)
+            try:
+                function_pyname = rope.base.evaluate.\
+                    eval_str(scope, primary)
+            except exceptions.BadIdentifierError:
+                return {}
+            if function_pyname is not None:
+                pyobject = function_pyname.get_object()
+                if isinstance(pyobject, pyobjects.AbstractFunction):
+                    pass
+                elif isinstance(pyobject, pyobjects.AbstractClass) and \
+                        '__init__' in pyobject:
+                    pyobject = pyobject['__init__'].get_object()
+                elif '__call__' in pyobject:
+                    pyobject = pyobject['__call__'].get_object()
+                if isinstance(pyobject, pyobjects.AbstractFunction):
+                    param_names = []
+                    param_names.extend(
+                        pyobject.get_param_names(special_args=False))
+                    result = {}
+                    for name in param_names:
+                        if name.startswith(self.starting):
+                            result[name + '='] = NamedParamProposal(
+                                name, pyobject
+                            )
+                    return result
+        return {}
+
+
+class _ProposalSorter(object):
+    """Sort a list of code assist proposals"""
+
+    def __init__(self, code_assist_proposals, scopepref=None, typepref=None):
+        self.proposals = code_assist_proposals
+        if scopepref is None:
+            scopepref = ['parameter_keyword', 'local', 'global', 'imported',
+                         'attribute', 'builtin', 'keyword']
+        self.scopepref = scopepref
+        if typepref is None:
+            typepref = ['class', 'function', 'instance', 'module', None]
+        self.typerank = dict((type, index)
+                             for index, type in enumerate(typepref))
+
+    def get_sorted_proposal_list(self):
+        """Return a list of `CodeAssistProposal`"""
+        proposals = {}
+        for proposal in self.proposals:
+            proposals.setdefault(proposal.scope, []).append(proposal)
+        result = []
+        for scope in self.scopepref:
+            scope_proposals = proposals.get(scope, [])
+            scope_proposals = [proposal for proposal in scope_proposals
+                               if proposal.type in self.typerank]
+            scope_proposals.sort(key=self._proposal_key)
+            result.extend(scope_proposals)
+        return result
+
+    def _proposal_key(self, proposal1):
+        def _underline_count(name):
+             return sum(1 for c in name if c == "_")
+        return (self.typerank.get(proposal1.type, 100),
+                _underline_count(proposal1.name),
+                proposal1.name)
+        #if proposal1.type != proposal2.type:
+        #    return cmp(self.typerank.get(proposal1.type, 100),
+        #               self.typerank.get(proposal2.type, 100))
+        #return self._compare_underlined_names(proposal1.name,
+        #                                      proposal2.name)
+
+
+class PyDocExtractor(object):
+
+    def get_doc(self, pyobject):
+        if isinstance(pyobject, pyobjects.AbstractFunction):
+            return self._get_function_docstring(pyobject)
+        elif isinstance(pyobject, pyobjects.AbstractClass):
+            return self._get_class_docstring(pyobject)
+        elif isinstance(pyobject, pyobjects.AbstractModule):
+            return self._trim_docstring(pyobject.get_doc())
+        return None
+
+    def get_calltip(self, pyobject, ignore_unknown=False, remove_self=False):
+        try:
+            if isinstance(pyobject, pyobjects.AbstractClass):
+                pyobject = pyobject['__init__'].get_object()
+            if not isinstance(pyobject, pyobjects.AbstractFunction):
+                pyobject = pyobject['__call__'].get_object()
+        except exceptions.AttributeNotFoundError:
+            return None
+        if ignore_unknown and not isinstance(pyobject, pyobjects.PyFunction):
+            return
+        if isinstance(pyobject, pyobjects.AbstractFunction):
+            result = self._get_function_signature(pyobject, add_module=True)
+            if remove_self and self._is_method(pyobject):
+                return result.replace('(self)', '()').replace('(self, ', '(')
+            return result
+
+    def _get_class_docstring(self, pyclass):
+        contents = self._trim_docstring(pyclass.get_doc(), 2)
+        supers = [super.get_name() for super in pyclass.get_superclasses()]
+        doc = 'class %s(%s):\n\n' % (pyclass.get_name(), ', '.join(supers)) \
+            + contents
+
+        if '__init__' in pyclass:
+            init = pyclass['__init__'].get_object()
+            if isinstance(init, pyobjects.AbstractFunction):
+                doc += '\n\n' + self._get_single_function_docstring(init)
+        return doc
+
+    def _get_function_docstring(self, pyfunction):
+        functions = [pyfunction]
+        if self._is_method(pyfunction):
+            functions.extend(self._get_super_methods(pyfunction.parent,
+                                                     pyfunction.get_name()))
+        return '\n\n'.join([self._get_single_function_docstring(function)
+                            for function in functions])
+
+    def _is_method(self, pyfunction):
+        return isinstance(pyfunction, pyobjects.PyFunction) and \
+            isinstance(pyfunction.parent, pyobjects.PyClass)
+
+    def _get_single_function_docstring(self, pyfunction):
+        signature = self._get_function_signature(pyfunction)
+        docs = self._trim_docstring(pyfunction.get_doc(), indents=2)
+        return signature + ':\n\n' + docs
+
+    def _get_super_methods(self, pyclass, name):
+        result = []
+        for super_class in pyclass.get_superclasses():
+            if name in super_class:
+                function = super_class[name].get_object()
+                if isinstance(function, pyobjects.AbstractFunction):
+                    result.append(function)
+            result.extend(self._get_super_methods(super_class, name))
+        return result
+
+    def _get_function_signature(self, pyfunction, add_module=False):
+        location = self._location(pyfunction, add_module)
+        if isinstance(pyfunction, pyobjects.PyFunction):
+            info = functionutils.DefinitionInfo.read(pyfunction)
+            return location + info.to_string()
+        else:
+            return '%s(%s)' % (location + pyfunction.get_name(),
+                               ', '.join(pyfunction.get_param_names()))
+
+    def _location(self, pyobject, add_module=False):
+        location = []
+        parent = pyobject.parent
+        while parent and not isinstance(parent, pyobjects.AbstractModule):
+            location.append(parent.get_name())
+            location.append('.')
+            parent = parent.parent
+        if add_module:
+            if isinstance(pyobject, pyobjects.PyFunction):
+                location.insert(0, self._get_module(pyobject))
+            if isinstance(parent, builtins.BuiltinModule):
+                location.insert(0, parent.get_name() + '.')
+        return ''.join(location)
+
+    def _get_module(self, pyfunction):
+        module = pyfunction.get_module()
+        if module is not None:
+            resource = module.get_resource()
+            if resource is not None:
+                return libutils.modname(resource) + '.'
+        return ''
+
+    def _trim_docstring(self, docstring, indents=0):
+        """The sample code from :PEP:`257`"""
+        if not docstring:
+            return ''
+        # Convert tabs to spaces (following normal Python rules)
+        # and split into a list of lines:
+        lines = docstring.expandtabs().splitlines()
+        # Determine minimum indentation (first line doesn't count):
+        indent = sys.maxsize
+        for line in lines[1:]:
+            stripped = line.lstrip()
+            if stripped:
+                indent = min(indent, len(line) - len(stripped))
+        # Remove indentation (first line is special):
+        trimmed = [lines[0].strip()]
+        if indent < sys.maxsize:
+            for line in lines[1:]:
+                trimmed.append(line[indent:].rstrip())
+        # Strip off trailing and leading blank lines:
+        while trimmed and not trimmed[-1]:
+            trimmed.pop()
+        while trimmed and not trimmed[0]:
+            trimmed.pop(0)
+        # Return a single string:
+        return '\n'.join((' ' * indents + line for line in trimmed))
+
+
+# Deprecated classes
+
+class TemplateProposal(CodeAssistProposal):
+    def __init__(self, name, template):
+        warnings.warn('TemplateProposal is deprecated.',
+                      DeprecationWarning, stacklevel=2)
+        super(TemplateProposal, self).__init__(name, 'template')
+        self.template = template
+
+
+class Template(object):
+
+    def __init__(self, template):
+        self.template = template
+        warnings.warn('Template is deprecated.',
+                      DeprecationWarning, stacklevel=2)
+
+    def variables(self):
+        return []
+
+    def substitute(self, mapping):
+        return self.template
+
+    def get_cursor_location(self, mapping):
+        return len(self.template)
diff --git a/venv/Lib/site-packages/rope/contrib/finderrors.py b/venv/Lib/site-packages/rope/contrib/finderrors.py
new file mode 100644
index 0000000000000000000000000000000000000000..109a3e8ac724fb1d48773d41ffff0604341b1496
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/finderrors.py
@@ -0,0 +1,91 @@
+"""Finding bad name and attribute accesses
+
+`find_errors` function can be used to find possible bad name and
+attribute accesses.  As an example::
+
+  errors = find_errors(project, project.get_resource('mod.py'))
+  for error in errors:
+      print('%s: %s' % (error.lineno, error.error))
+
+prints possible errors for ``mod.py`` file.
+
+TODO:
+
+* use task handles
+* reporting names at most once
+* attributes of extension modules that don't appear in
+  extension_modules project config can be ignored
+* not calling `PyScope.get_inner_scope_for_line()` if it is a
+  bottleneck; needs profiling
+* not reporting occurrences where rope cannot infer the object
+* rope saves multiple objects for some of the names in its objectdb
+  use all of them not to give false positives
+* ... ;-)
+
+"""
+from rope.base import ast, evaluate, pyobjects
+
+
+def find_errors(project, resource):
+    """Find possible bad name and attribute accesses
+
+    It returns a list of `Error`\s.
+    """
+    pymodule = project.get_pymodule(resource)
+    finder = _BadAccessFinder(pymodule)
+    ast.walk(pymodule.get_ast(), finder)
+    return finder.errors
+
+
+class _BadAccessFinder(object):
+
+    def __init__(self, pymodule):
+        self.pymodule = pymodule
+        self.scope = pymodule.get_scope()
+        self.errors = []
+
+    def _Name(self, node):
+        if isinstance(node.ctx, (ast.Store, ast.Param)):
+            return
+        scope = self.scope.get_inner_scope_for_line(node.lineno)
+        pyname = scope.lookup(node.id)
+        if pyname is None:
+            self._add_error(node, 'Unresolved variable')
+        elif self._is_defined_after(scope, pyname, node.lineno):
+            self._add_error(node, 'Defined later')
+
+    def _Attribute(self, node):
+        if not isinstance(node.ctx, ast.Store):
+            scope = self.scope.get_inner_scope_for_line(node.lineno)
+            pyname = evaluate.eval_node(scope, node.value)
+            if pyname is not None and \
+               pyname.get_object() != pyobjects.get_unknown():
+                if node.attr not in pyname.get_object():
+                    self._add_error(node, 'Unresolved attribute')
+        ast.walk(node.value, self)
+
+    def _add_error(self, node, msg):
+        if isinstance(node, ast.Attribute):
+            name = node.attr
+        else:
+            name = node.id
+        if name != 'None':
+            error = Error(node.lineno, msg + ' ' + name)
+            self.errors.append(error)
+
+    def _is_defined_after(self, scope, pyname, lineno):
+        location = pyname.get_definition_location()
+        if location is not None and location[1] is not None:
+            if location[0] == self.pymodule and \
+               lineno <= location[1] <= scope.get_end():
+                return True
+
+
+class Error(object):
+
+    def __init__(self, lineno, error):
+        self.lineno = lineno
+        self.error = error
+
+    def __str__(self):
+        return '%s: %s' % (self.lineno, self.error)
diff --git a/venv/Lib/site-packages/rope/contrib/findit.py b/venv/Lib/site-packages/rope/contrib/findit.py
new file mode 100644
index 0000000000000000000000000000000000000000..93eb01a8467649de1f094e7eab61ef49ff4940fb
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/findit.py
@@ -0,0 +1,114 @@
+import rope.base.codeanalyze
+import rope.base.evaluate
+import rope.base.pyobjects
+from rope.base import taskhandle, exceptions, worder
+from rope.contrib import fixsyntax
+from rope.refactor import occurrences
+
+
+def find_occurrences(project, resource, offset, unsure=False, resources=None,
+                     in_hierarchy=False,
+                     task_handle=taskhandle.NullTaskHandle()):
+    """Return a list of `Location`\s
+
+    If `unsure` is `True`, possible matches are returned, too.  You
+    can use `Location.unsure` to see which are unsure occurrences.
+    `resources` can be a list of `rope.base.resource.File`\s that
+    should be searched for occurrences; if `None` all python files
+    in the project are searched.
+
+    """
+    name = worder.get_name_at(resource, offset)
+    this_pymodule = project.get_pymodule(resource)
+    primary, pyname = rope.base.evaluate.eval_location2(
+        this_pymodule, offset)
+
+    def is_match(occurrence):
+        return unsure
+    finder = occurrences.create_finder(
+        project, name, pyname, unsure=is_match,
+        in_hierarchy=in_hierarchy, instance=primary)
+    if resources is None:
+        resources = project.get_python_files()
+    job_set = task_handle.create_jobset('Finding Occurrences',
+                                        count=len(resources))
+    return _find_locations(finder, resources, job_set)
+
+
+def find_implementations(project, resource, offset, resources=None,
+                         task_handle=taskhandle.NullTaskHandle()):
+    """Find the places a given method is overridden.
+
+    Finds the places a method is implemented.  Returns a list of
+    `Location`\s.
+    """
+    name = worder.get_name_at(resource, offset)
+    this_pymodule = project.get_pymodule(resource)
+    pyname = rope.base.evaluate.eval_location(this_pymodule, offset)
+    if pyname is not None:
+        pyobject = pyname.get_object()
+        if not isinstance(pyobject, rope.base.pyobjects.PyFunction) or \
+           pyobject.get_kind() != 'method':
+            raise exceptions.BadIdentifierError('Not a method!')
+    else:
+        raise exceptions.BadIdentifierError('Cannot resolve the identifier!')
+
+    def is_defined(occurrence):
+        if not occurrence.is_defined():
+            return False
+
+    def not_self(occurrence):
+        if occurrence.get_pyname().get_object() == pyname.get_object():
+            return False
+    filters = [is_defined, not_self,
+               occurrences.InHierarchyFilter(pyname, True)]
+    finder = occurrences.Finder(project, name, filters=filters)
+    if resources is None:
+        resources = project.get_python_files()
+    job_set = task_handle.create_jobset('Finding Implementations',
+                                        count=len(resources))
+    return _find_locations(finder, resources, job_set)
+
+
+def find_definition(project, code, offset, resource=None, maxfixes=1):
+    """Return the definition location of the python name at `offset`
+
+    A `Location` object is returned if the definition location can be
+    determined, otherwise ``None`` is returned.
+    """
+    fixer = fixsyntax.FixSyntax(project, code, resource, maxfixes)
+    pyname = fixer.pyname_at(offset)
+    if pyname is not None:
+        module, lineno = pyname.get_definition_location()
+        name = rope.base.worder.Worder(code).get_word_at(offset)
+        if lineno is not None:
+            start = module.lines.get_line_start(lineno)
+
+            def check_offset(occurrence):
+                if occurrence.offset < start:
+                    return False
+            pyname_filter = occurrences.PyNameFilter(pyname)
+            finder = occurrences.Finder(project, name,
+                                        [check_offset, pyname_filter])
+            for occurrence in finder.find_occurrences(pymodule=module):
+                return Location(occurrence)
+
+
+class Location(object):
+
+    def __init__(self, occurrence):
+        self.resource = occurrence.resource
+        self.region = occurrence.get_word_range()
+        self.offset = self.region[0]
+        self.unsure = occurrence.is_unsure()
+        self.lineno = occurrence.lineno
+
+
+def _find_locations(finder, resources, job_set):
+    result = []
+    for resource in resources:
+        job_set.started_job(resource.path)
+        for occurrence in finder.find_occurrences(resource):
+            result.append(Location(occurrence))
+        job_set.finished_job()
+    return result
diff --git a/venv/Lib/site-packages/rope/contrib/fixmodnames.py b/venv/Lib/site-packages/rope/contrib/fixmodnames.py
new file mode 100644
index 0000000000000000000000000000000000000000..d8bd3da109e09cc852e497da77c4d32c1c714060
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/fixmodnames.py
@@ -0,0 +1,69 @@
+"""Fix the name of modules
+
+This module is useful when you want to rename many of the modules in
+your project.  That can happen specially when you want to change their
+naming style.
+
+For instance::
+
+  fixer = FixModuleNames(project)
+  changes = fixer.get_changes(fixer=str.lower)
+  project.do(changes)
+
+Here it renames all modules and packages to use lower-cased chars.
+You can tell it to use any other style by using the ``fixer``
+argument.
+
+"""
+from rope.base import taskhandle
+from rope.contrib import changestack
+from rope.refactor import rename
+
+
+class FixModuleNames(object):
+
+    def __init__(self, project):
+        self.project = project
+
+    def get_changes(self, fixer=str.lower,
+                    task_handle=taskhandle.NullTaskHandle()):
+        """Fix module names
+
+        `fixer` is a function that takes and returns a `str`.  Given
+        the name of a module, it should return the fixed name.
+
+        """
+        stack = changestack.ChangeStack(self.project, 'Fixing module names')
+        jobset = task_handle.create_jobset('Fixing module names',
+                                           self._count_fixes(fixer) + 1)
+        try:
+            while True:
+                for resource in self._tobe_fixed(fixer):
+                    jobset.started_job(resource.path)
+                    renamer = rename.Rename(self.project, resource)
+                    changes = renamer.get_changes(fixer(self._name(resource)))
+                    stack.push(changes)
+                    jobset.finished_job()
+                    break
+                else:
+                    break
+        finally:
+            jobset.started_job('Reverting to original state')
+            stack.pop_all()
+            jobset.finished_job()
+        return stack.merged()
+
+    def _count_fixes(self, fixer):
+        return len(list(self._tobe_fixed(fixer)))
+
+    def _tobe_fixed(self, fixer):
+        for resource in self.project.get_python_files():
+            modname = self._name(resource)
+            if modname != fixer(modname):
+                yield resource
+
+    def _name(self, resource):
+        modname = resource.name.rsplit('.', 1)[0]
+        if modname == '__init__':
+            modname = resource.parent.name
+        return modname
diff --git a/venv/Lib/site-packages/rope/contrib/fixsyntax.py b/venv/Lib/site-packages/rope/contrib/fixsyntax.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa2a17d93c1289bc85ce7d99188d4a454204093c
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/fixsyntax.py
@@ -0,0 +1,181 @@
+import rope.base.codeanalyze
+import rope.base.evaluate
+from rope.base import exceptions
+from rope.base import libutils
+from rope.base import utils
+from rope.base import worder
+from rope.base.codeanalyze import ArrayLinesAdapter, LogicalLineFinder
+
+
+class FixSyntax(object):
+
+    def __init__(self, project, code, resource, maxfixes=1):
+        self.project = project
+        self.code = code
+        self.resource = resource
+        self.maxfixes = maxfixes
+
+    @utils.saveit
+    def get_pymodule(self):
+        """Get a `PyModule`"""
+        msg = None
+        code = self.code
+        tries = 0
+        while True:
+            try:
+                if tries == 0 and self.resource is not None and \
+                   self.resource.read() == code:
+                    return self.project.get_pymodule(self.resource,
+                                                     force_errors=True)
+                return libutils.get_string_module(
+                    self.project, code, resource=self.resource,
+                    force_errors=True)
+            except exceptions.ModuleSyntaxError as e:
+                if msg is None:
+                    msg = '%s:%s %s' % (e.filename, e.lineno, e.message_)
+                if tries < self.maxfixes:
+                    tries += 1
+                    self.commenter.comment(e.lineno)
+                    code = '\n'.join(self.commenter.lines)
+                else:
+                    raise exceptions.ModuleSyntaxError(
+                        e.filename, e.lineno,
+                        'Failed to fix error: {0}'.format(msg))
+
+    @property
+    @utils.saveit
+    def commenter(self):
+        return _Commenter(self.code)
+
+    def pyname_at(self, offset):
+        pymodule = self.get_pymodule()
+
+        def old_pyname():
+            word_finder = worder.Worder(self.code, True)
+            expression = word_finder.get_primary_at(offset)
+            expression = expression.replace('\\\n', ' ').replace('\n', ' ')
+            lineno = self.code.count('\n', 0, offset)
+            scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+            return rope.base.evaluate.eval_str(scope, expression)
+        new_code = pymodule.source_code
+
+        def new_pyname():
+            newoffset = self.commenter.transfered_offset(offset)
+            return rope.base.evaluate.eval_location(pymodule, newoffset)
+        if new_code.startswith(self.code[:offset + 1]):
+            return new_pyname()
+        result = old_pyname()
+        if result is None:
+            return new_pyname()
+        return result
+
+
+class _Commenter(object):
+
+    def __init__(self, code):
+        self.code = code
+        self.lines = self.code.split('\n')
+        self.lines.append('\n')
+        self.origs = list(range(len(self.lines) + 1))
+        self.diffs = [0] * (len(self.lines) + 1)
+
+    def comment(self, lineno):
+        start = _logical_start(self.lines, lineno, check_prev=True) - 1
+        # using self._get_stmt_end() instead of self._get_block_end()
+        # to lower commented lines
+        end = self._get_stmt_end(start)
+        indents = _get_line_indents(self.lines[start])
+        if 0 < start:
+            last_lineno = self._last_non_blank(start - 1)
+            last_line = self.lines[last_lineno]
+            if last_line.rstrip().endswith(':'):
+                indents = _get_line_indents(last_line) + 4
+        self._set(start, ' ' * indents + 'pass')
+        for line in range(start + 1, end + 1):
+            self._set(line, self.lines[start])
+        self._fix_incomplete_try_blocks(lineno, indents)
+
+    def transfered_offset(self, offset):
+        lineno = self.code.count('\n', 0, offset)
+        diff = sum(self.diffs[:lineno])
+        return offset + diff
+
+    def _last_non_blank(self, start):
+        while start > 0 and self.lines[start].strip() == '':
+            start -= 1
+        return start
+
+    def _get_block_end(self, lineno):
+        end_line = lineno
+        base_indents = _get_line_indents(self.lines[lineno])
+        for i in range(lineno + 1, len(self.lines)):
+            if _get_line_indents(self.lines[i]) >= base_indents:
+                end_line = i
+            else:
+                break
+        return end_line
+
+    def _get_stmt_end(self, lineno):
+        base_indents = _get_line_indents(self.lines[lineno])
+        for i in range(lineno + 1, len(self.lines)):
+            if _get_line_indents(self.lines[i]) <= base_indents:
+                return i - 1
+        return lineno
+
+    def _fix_incomplete_try_blocks(self, lineno, indents):
+        block_start = lineno
+        last_indents = indents
+        while block_start > 0:
+            block_start = rope.base.codeanalyze.get_block_start(
+                ArrayLinesAdapter(self.lines), block_start) - 1
+            if self.lines[block_start].strip().startswith('try:'):
+                indents = _get_line_indents(self.lines[block_start])
+                if indents > last_indents:
+                    continue
+                last_indents = indents
+                block_end = self._find_matching_deindent(block_start)
+                line = self.lines[block_end].strip()
+                if not (line.startswith('finally:') or
+                        line.startswith('except ') or
+                        line.startswith('except:')):
+                    self._insert(block_end, ' ' * indents + 'finally:')
+                    self._insert(block_end + 1, ' ' * indents + '    pass')
+
+    def _find_matching_deindent(self, line_number):
+        indents = _get_line_indents(self.lines[line_number])
+        current_line = line_number + 1
+        while current_line < len(self.lines):
+            line = self.lines[current_line]
+            if not line.strip().startswith('#') and not line.strip() == '':
+                # HACK: We should have used logical lines here
+                if _get_line_indents(self.lines[current_line]) <= indents:
+                    return current_line
+            current_line += 1
+        return len(self.lines) - 1
+
+    def _set(self, lineno, line):
+        self.diffs[self.origs[lineno]] += len(line) - len(self.lines[lineno])
+        self.lines[lineno] = line
+
+    def _insert(self, lineno, line):
+        self.diffs[self.origs[lineno]] += len(line) + 1
+        self.origs.insert(lineno, self.origs[lineno])
+        self.lines.insert(lineno, line)
+
+
+def _logical_start(lines, lineno, check_prev=False):
+    logical_finder = LogicalLineFinder(ArrayLinesAdapter(lines))
+    if check_prev:
+        prev = lineno - 1
+        while prev > 0:
+            start, end = logical_finder.logical_line_in(prev)
+            if end is None or start <= lineno < end:
+                return start
+            if start <= prev:
+                break
+            prev -= 1
+    return logical_finder.logical_line_in(lineno)[0]
+
+
+def _get_line_indents(line):
+    return rope.base.codeanalyze.count_line_indents(line)
diff --git a/venv/Lib/site-packages/rope/contrib/generate.py b/venv/Lib/site-packages/rope/contrib/generate.py
new file mode 100644
index 0000000000000000000000000000000000000000..9291a1d164ab05cc4355e1b6d24c7ec54db3e458
--- /dev/null
+++ b/venv/Lib/site-packages/rope/contrib/generate.py
@@ -0,0 +1,379 @@
+import rope.base.evaluate
+from rope.base import libutils
+from rope.base import (change, pyobjects, exceptions, pynames, worder,
+                       codeanalyze)
+from rope.refactor import sourceutils, importutils, functionutils, suites
+
+
+def create_generate(kind, project, resource, offset):
+    """A factory for creating `Generate` objects
+
+    `kind` can be 'variable', 'function', 'class', 'module' or
+    'package'.
+
+    """
+    generate = eval('Generate' + kind.title())
+    return generate(project, resource, offset)
+
+
+def create_module(project, name, sourcefolder=None):
+    """Creates a module and returns a `rope.base.resources.File`"""
+    if sourcefolder is None:
+        sourcefolder = project.root
+    packages = name.split('.')
+    parent = sourcefolder
+    for package in packages[:-1]:
+        parent = parent.get_child(package)
+    return parent.create_file(packages[-1] + '.py')
+
+
+def create_package(project, name, sourcefolder=None):
+    """Creates a package and returns a `rope.base.resources.Folder`"""
+    if sourcefolder is None:
+        sourcefolder = project.root
+    packages = name.split('.')
+    parent = sourcefolder
+    for package in packages[:-1]:
+        parent = parent.get_child(package)
+    made_packages = parent.create_folder(packages[-1])
+    made_packages.create_file('__init__.py')
+    return made_packages
+
+
+class _Generate(object):
+
+    def __init__(self, project, resource, offset, goal_resource=None):
+        self.project = project
+        self.resource = resource
+        self.goal_resource = goal_resource
+        self.info = self._generate_info(project, resource, offset)
+        self.name = self.info.get_name()
+        self._check_exceptional_conditions()
+
+    def _generate_info(self, project, resource, offset):
+        return _GenerationInfo(project.pycore, resource, offset, self.goal_resource)
+
+    def _check_exceptional_conditions(self):
+        if self.info.element_already_exists():
+            raise exceptions.RefactoringError(
+                'Element <%s> already exists.' % self.name)
+        if not self.info.primary_is_found():
+            raise exceptions.RefactoringError(
+                'Cannot determine the scope <%s> should be defined in.' %
+                self.name)
+
+    def get_changes(self):
+        changes = change.ChangeSet('Generate %s <%s>' %
+                                   (self._get_element_kind(), self.name))
+        indents = self.info.get_scope_indents()
+        blanks = self.info.get_blank_lines()
+        base_definition = sourceutils.fix_indentation(self._get_element(),
+                                                      indents)
+        definition = '\n' * blanks[0] + base_definition + '\n' * blanks[1]
+
+        resource = self.info.get_insertion_resource()
+        start, end = self.info.get_insertion_offsets()
+
+        collector = codeanalyze.ChangeCollector(resource.read())
+        collector.add_change(start, end, definition)
+        changes.add_change(change.ChangeContents(
+                           resource, collector.get_changed()))
+        if self.goal_resource:
+            relative_import = _add_relative_import_to_module(self.project, self.resource, self.goal_resource, self.name)
+            changes.add_change(relative_import)
+        return changes
+
+    def get_location(self):
+        return (self.info.get_insertion_resource(),
+                self.info.get_insertion_lineno())
+
+    def _get_element_kind(self):
+        raise NotImplementedError()
+
+    def _get_element(self):
+        raise NotImplementedError()
+
+
+class GenerateFunction(_Generate):
+
+    def _generate_info(self, project, resource, offset):
+        return _FunctionGenerationInfo(project.pycore, resource, offset)
+
+    def _get_element(self):
+        decorator = ''
+        args = []
+        if self.info.is_static_method():
+            decorator = '@staticmethod\n'
+        if self.info.is_method() or self.info.is_constructor() or \
+           self.info.is_instance():
+            args.append('self')
+        args.extend(self.info.get_passed_args())
+        definition = '%sdef %s(%s):\n    pass\n' % (decorator, self.name,
+                                                    ', '.join(args))
+        return definition
+
+    def _get_element_kind(self):
+        return 'Function'
+
+
+class GenerateVariable(_Generate):
+
+    def _get_element(self):
+        return '%s = None\n' % self.name
+
+    def _get_element_kind(self):
+        return 'Variable'
+
+
+class GenerateClass(_Generate):
+
+    def _get_element(self):
+        return 'class %s(object):\n    pass\n' % self.name
+
+    def _get_element_kind(self):
+        return 'Class'
+
+
+class GenerateModule(_Generate):
+
+    def get_changes(self):
+        package = self.info.get_package()
+        changes = change.ChangeSet('Generate Module <%s>' % self.name)
+        new_resource = self.project.get_file('%s/%s.py' %
+                                             (package.path, self.name))
+        if new_resource.exists():
+            raise exceptions.RefactoringError(
+                'Module <%s> already exists' % new_resource.path)
+        changes.add_change(change.CreateResource(new_resource))
+        changes.add_change(_add_import_to_module(
+                           self.project, self.resource, new_resource))
+        return changes
+
+    def get_location(self):
+        package = self.info.get_package()
+        return (package.get_child('%s.py' % self.name), 1)
+
+
+class GeneratePackage(_Generate):
+
+    def get_changes(self):
+        package = self.info.get_package()
+        changes = change.ChangeSet('Generate Package <%s>' % self.name)
+        new_resource = self.project.get_folder('%s/%s' %
+                                               (package.path, self.name))
+        if new_resource.exists():
+            raise exceptions.RefactoringError(
+                'Package <%s> already exists' % new_resource.path)
+        changes.add_change(change.CreateResource(new_resource))
+        changes.add_change(_add_import_to_module(
+                           self.project, self.resource, new_resource))
+        child = self.project.get_folder(package.path + '/' + self.name)
+        changes.add_change(change.CreateFile(child, '__init__.py'))
+        return changes
+
+    def get_location(self):
+        package = self.info.get_package()
+        child = package.get_child(self.name)
+        return (child.get_child('__init__.py'), 1)
+
+
+def _add_import_to_module(project, resource, imported):
+    pymodule = project.get_pymodule(resource)
+    import_tools = importutils.ImportTools(project)
+    module_imports = import_tools.module_imports(pymodule)
+    module_name = libutils.modname(imported)
+    new_import = importutils.NormalImport(((module_name, None), ))
+    module_imports.add_import(new_import)
+    return change.ChangeContents(resource, module_imports.get_changed_source())
+
+
+def _add_relative_import_to_module(project, resource, imported, name):
+    pymodule = project.get_pymodule(resource)
+    import_tools = importutils.ImportTools(project)
+    module_imports = import_tools.module_imports(pymodule)
+    new_import = import_tools.get_from_import(imported, name)
+    module_imports.add_import(new_import)
+    return change.ChangeContents(resource, module_imports.get_changed_source())
+
+
+class _GenerationInfo(object):
+
+    def __init__(self, pycore, resource, offset, goal_resource=None):
+        self.pycore = pycore
+        self.resource = resource
+        self.offset = offset
+        self.goal_resource = goal_resource
+        self.source_pymodule = self.pycore.project.get_pymodule(resource)
+        finder = rope.base.evaluate.ScopeNameFinder(self.source_pymodule)
+        self.primary, self.pyname = finder.get_primary_and_pyname_at(offset)
+        self._init_fields()
+
+    def _init_fields(self):
+        self.source_scope = self._get_source_scope()
+        self.goal_scope = self._get_goal_scope()
+        self.goal_pymodule = self._get_goal_module(self.goal_scope)
+
+    def _get_goal_scope(self):
+        if self.primary is None:
+            if self.goal_resource:
+                return self.pycore.project.get_pymodule(self.goal_resource).get_scope()
+            else:
+                return self._get_source_scope()
+        pyobject = self.primary.get_object()
+        if isinstance(pyobject, pyobjects.PyDefinedObject):
+            return pyobject.get_scope()
+        elif isinstance(pyobject.get_type(), pyobjects.PyClass):
+            return pyobject.get_type().get_scope()
+
+    def _get_goal_module(self, scope):
+        if scope is None:
+            return
+        while scope.parent is not None:
+            scope = scope.parent
+        return scope.pyobject
+
+    def _get_source_scope(self):
+        module_scope = self.source_pymodule.get_scope()
+        lineno = self.source_pymodule.lines.get_line_number(self.offset)
+        return module_scope.get_inner_scope_for_line(lineno)
+
+    def get_insertion_lineno(self):
+        lines = self.goal_pymodule.lines
+        if self.goal_scope == self.source_scope:
+            line_finder = self.goal_pymodule.logical_lines
+            lineno = lines.get_line_number(self.offset)
+            lineno = line_finder.logical_line_in(lineno)[0]
+            root = suites.ast_suite_tree(self.goal_scope.pyobject.get_ast())
+            suite = root.find_suite(lineno)
+            indents = sourceutils.get_indents(lines, lineno)
+            while self.get_scope_indents() < indents:
+                lineno = suite.get_start()
+                indents = sourceutils.get_indents(lines, lineno)
+                suite = suite.parent
+            return lineno
+        else:
+            return min(self.goal_scope.get_end() + 1, lines.length())
+
+    def get_insertion_resource(self):
+        return self.goal_pymodule.get_resource()
+
+    def get_insertion_offsets(self):
+        if self.goal_scope.get_kind() == 'Class':
+            start, end = sourceutils.get_body_region(self.goal_scope.pyobject)
+            if self.goal_pymodule.source_code[start:end].strip() == 'pass':
+                return start, end
+        lines = self.goal_pymodule.lines
+        start = lines.get_line_start(self.get_insertion_lineno())
+        return (start, start)
+
+    def get_scope_indents(self):
+        if self.goal_scope.get_kind() == 'Module':
+            return 0
+        return sourceutils.get_indents(self.goal_pymodule.lines,
+                                       self.goal_scope.get_start()) + 4
+
+    def get_blank_lines(self):
+        if self.goal_scope.get_kind() == 'Module':
+            base_blanks = 2
+            if self.goal_pymodule.source_code.strip() == '':
+                base_blanks = 0
+        if self.goal_scope.get_kind() == 'Class':
+            base_blanks = 1
+        if self.goal_scope.get_kind() == 'Function':
+            base_blanks = 0
+        if self.goal_scope == self.source_scope:
+            return (0, base_blanks)
+        return (base_blanks, 0)
+
+    def get_package(self):
+        primary = self.primary
+        if self.primary is None:
+            return self.pycore.project.get_source_folders()[0]
+        if isinstance(primary.get_object(), pyobjects.PyPackage):
+            return primary.get_object().get_resource()
+        raise exceptions.RefactoringError(
+            'A module/package can be only created in a package.')
+
+    def primary_is_found(self):
+        return self.goal_scope is not None
+
+    def element_already_exists(self):
+        if self.pyname is None or isinstance(self.pyname, pynames.UnboundName):
+            return False
+        return self.get_name() in self.goal_scope.get_defined_names()
+
+    def get_name(self):
+        return worder.get_name_at(self.resource, self.offset)
+
+
+class _FunctionGenerationInfo(_GenerationInfo):
+
+    def _get_goal_scope(self):
+        if self.is_constructor():
+            return self.pyname.get_object().get_scope()
+        if self.is_instance():
+            return self.pyname.get_object().get_type().get_scope()
+        if self.primary is None:
+            return self._get_source_scope()
+        pyobject = self.primary.get_object()
+        if isinstance(pyobject, pyobjects.PyDefinedObject):
+            return pyobject.get_scope()
+        elif isinstance(pyobject.get_type(), pyobjects.PyClass):
+            return pyobject.get_type().get_scope()
+
+    def element_already_exists(self):
+        if self.pyname is None or isinstance(self.pyname, pynames.UnboundName):
+            return False
+        return self.get_name() in self.goal_scope.get_defined_names()
+
+    def is_static_method(self):
+        return self.primary is not None and \
+            isinstance(self.primary.get_object(), pyobjects.PyClass)
+
+    def is_method(self):
+        return self.primary is not None and \
+            isinstance(self.primary.get_object().get_type(), pyobjects.PyClass)
+
+    def is_constructor(self):
+        return self.pyname is not None and \
+            isinstance(self.pyname.get_object(), pyobjects.PyClass)
+
+    def is_instance(self):
+        if self.pyname is None:
+            return False
+        pyobject = self.pyname.get_object()
+        return isinstance(pyobject.get_type(), pyobjects.PyClass)
+
+    def get_name(self):
+        if self.is_constructor():
+            return '__init__'
+        if self.is_instance():
+            return '__call__'
+        return worder.get_name_at(self.resource, self.offset)
+
+    def get_passed_args(self):
+        result = []
+        source = self.source_pymodule.source_code
+        finder = worder.Worder(source)
+        if finder.is_a_function_being_called(self.offset):
+            start, end = finder.get_primary_range(self.offset)
+            parens_start, parens_end = finder.get_word_parens_range(end - 1)
+            call = source[start:parens_end]
+            parser = functionutils._FunctionParser(call, False)
+            args, keywords = parser.get_parameters()
+            for arg in args:
+                if self._is_id(arg):
+                    result.append(arg)
+                else:
+                    result.append('arg%d' % len(result))
+            for name, value in keywords:
+                result.append(name)
+        return result
+
+    def _is_id(self, arg):
+        def id_or_underline(c):
+            return c.isalpha() or c == '_'
+        for c in arg:
+            if not id_or_underline(c) and not c.isdigit():
+                return False
+        return id_or_underline(arg[0])
diff --git a/venv/Lib/site-packages/rope/refactor/__init__.py b/venv/Lib/site-packages/rope/refactor/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..4ef6751348145de962ee58c9074927d99590829f
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/__init__.py
@@ -0,0 +1,55 @@
+"""rope refactor package
+
+This package contains modules that perform python refactorings.
+Refactoring classes perform refactorings in 4 steps:
+
+1. Collect some data for performing the refactoring and use them
+   to construct a refactoring class.  Like::
+
+     renamer = Rename(project, resource, offset)
+
+2. Some refactorings give you useful information about the
+   refactoring after their construction.  Like::
+
+     print(renamer.get_old_name())
+
+3. Give the refactoring class more information about how to
+   perform the refactoring and get the changes this refactoring is
+   going to make.  This is done by calling `get_changes` method of the
+   refactoring class.  Like::
+
+     changes = renamer.get_changes(new_name)
+
+4. You can commit the changes.  Like::
+
+     project.do(changes)
+
+These steps are like the steps IDEs usually do for performing a
+refactoring.  These are the things an IDE does in each step:
+
+1. Construct a refactoring object by giving it information like
+   resource, offset and ... .  Some of the refactoring problems (like
+   performing rename refactoring on language keywords) can be reported
+   here.
+2. Print some information about the refactoring and ask the user
+   about the information that are necessary for completing the
+   refactoring (like new name).
+3. Call the `get_changes` by passing it information asked from
+   the user (if necessary) and get and preview the changes returned by
+   it.
+4. perform the refactoring.
+
+From ``0.5m5`` release the `get_changes()` method of some time-
+consuming refactorings take an optional `rope.base.taskhandle.
+TaskHandle` parameter.  You can use this object for stopping or
+monitoring the progress of refactorings.
+
+"""
+from rope.refactor.importutils import ImportOrganizer  # noqa
+from rope.refactor.topackage import ModuleToPackage  # noqa
+
+
+__all__ = ['rename', 'move', 'inline', 'extract', 'restructure', 'topackage',
+           'importutils', 'usefunction', 'change_signature',
+           'encapsulate_field', 'introduce_factory', 'introduce_parameter',
+           'localtofield', 'method_object', 'multiproject']
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9808d74cae4ab7e46cdc97327ed55dd21e6e308c
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/change_signature.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/change_signature.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8ff9464a0484301db3db688574ee85af1146a3a5
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/change_signature.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/encapsulate_field.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/encapsulate_field.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..92d8bfbac71895ad01f9785d02d53d4a6e5afb7d
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/encapsulate_field.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/extract.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/extract.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a42b8730ca18ee89a72211e77874786d500fde1c
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/extract.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/functionutils.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/functionutils.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3064e76d96f2d4ee2d7d88624192793c30c3ca0a
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/functionutils.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/inline.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/inline.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..13d4ccbea89f8b7e31f17acfa322a1649e0fa01d
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/inline.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/introduce_factory.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/introduce_factory.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bee7d578c35fd432afd55b1c5e53d68d4fbe77bd
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/introduce_factory.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/introduce_parameter.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/introduce_parameter.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7a47f5a3d1a1ca1cba3d0a08f1071c5d4872c712
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/introduce_parameter.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/localtofield.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/localtofield.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c28f70b8d571ec1af9c8d8edaca14207da6661f2
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/localtofield.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/method_object.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/method_object.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8847338d155d8bbe8682b781a7347a3908addb08
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/method_object.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/move.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/move.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1d4febfa8b521b29d10d4e9fc02091d64f8a2a86
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/move.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/multiproject.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/multiproject.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b0d100999e21e344d9e35481118c96ef7a6c2fed
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/multiproject.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/occurrences.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/occurrences.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bf3bf986205435719da7dbfe9bfbc64bfd27bfe7
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/occurrences.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/patchedast.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/patchedast.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f83cc32564a801a486808dbfc3aa45feb01409f1
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/patchedast.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/rename.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/rename.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..248e4ed5147ff7a6dfb927c34adaabda93a9f995
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/rename.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/restructure.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/restructure.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1aa58dcf0d0babcf25ce181d75291c4f1616b009
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/restructure.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/similarfinder.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/similarfinder.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3d612877fb2d44f85850fa8169663983812d1e0f
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/similarfinder.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/sourceutils.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/sourceutils.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5f091d6f4328069bc6b272506669f9e529453839
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/sourceutils.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/suites.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/suites.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b21aab05b50caaa82a1efbc2ee36eeb752664b19
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/suites.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/topackage.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/topackage.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..152ab6b4b49157571e497e5271cb3d9e0ae159e2
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/topackage.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/usefunction.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/usefunction.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c51aa1997e6aa9b2039900bc7aa5a6ac29650f3b
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/usefunction.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/__pycache__/wildcards.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/__pycache__/wildcards.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..aa139ce4d7814c0b44a5dcc271e83240f51e88de
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/__pycache__/wildcards.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/change_signature.py b/venv/Lib/site-packages/rope/refactor/change_signature.py
new file mode 100644
index 0000000000000000000000000000000000000000..b5ba1856a80746cef2ff8c2cbeb84fd296138fbc
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/change_signature.py
@@ -0,0 +1,352 @@
+import copy
+
+import rope.base.exceptions
+from rope.base import codeanalyze
+from rope.base import evaluate
+from rope.base import pyobjects
+from rope.base import taskhandle
+from rope.base import utils
+from rope.base import worder
+from rope.base.change import ChangeContents, ChangeSet
+from rope.refactor import occurrences, functionutils
+
+
+class ChangeSignature(object):
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        self.resource = resource
+        self.offset = offset
+        self._set_name_and_pyname()
+        if self.pyname is None or self.pyname.get_object() is None or \
+           not isinstance(self.pyname.get_object(), pyobjects.PyFunction):
+            raise rope.base.exceptions.RefactoringError(
+                'Change method signature should be performed on functions')
+
+    def _set_name_and_pyname(self):
+        self.name = worder.get_name_at(self.resource, self.offset)
+        this_pymodule = self.project.get_pymodule(self.resource)
+        self.primary, self.pyname = evaluate.eval_location2(
+            this_pymodule, self.offset)
+        if self.pyname is None:
+            return
+        pyobject = self.pyname.get_object()
+        if isinstance(pyobject, pyobjects.PyClass) and \
+           '__init__' in pyobject:
+            self.pyname = pyobject['__init__']
+            self.name = '__init__'
+        pyobject = self.pyname.get_object()
+        self.others = None
+        if self.name == '__init__' and \
+           isinstance(pyobject, pyobjects.PyFunction) and \
+           isinstance(pyobject.parent, pyobjects.PyClass):
+            pyclass = pyobject.parent
+            self.others = (pyclass.get_name(),
+                           pyclass.parent[pyclass.get_name()])
+
+    def _change_calls(self, call_changer, in_hierarchy=None, resources=None,
+                      handle=taskhandle.NullTaskHandle()):
+        if resources is None:
+            resources = self.project.get_python_files()
+        changes = ChangeSet('Changing signature of <%s>' % self.name)
+        job_set = handle.create_jobset('Collecting Changes', len(resources))
+        finder = occurrences.create_finder(
+            self.project, self.name, self.pyname, instance=self.primary,
+            in_hierarchy=in_hierarchy and self.is_method())
+        if self.others:
+            name, pyname = self.others
+            constructor_finder = occurrences.create_finder(
+                self.project, name, pyname, only_calls=True)
+            finder = _MultipleFinders([finder, constructor_finder])
+        for file in resources:
+            job_set.started_job(file.path)
+            change_calls = _ChangeCallsInModule(
+                self.project, finder, file, call_changer)
+            changed_file = change_calls.get_changed_module()
+            if changed_file is not None:
+                changes.add_change(ChangeContents(file, changed_file))
+            job_set.finished_job()
+        return changes
+
+    def get_args(self):
+        """Get function arguments.
+
+        Return a list of ``(name, default)`` tuples for all but star
+        and double star arguments.  For arguments that don't have a
+        default, `None` will be used.
+        """
+        return self._definfo().args_with_defaults
+
+    def is_method(self):
+        pyfunction = self.pyname.get_object()
+        return isinstance(pyfunction.parent, pyobjects.PyClass)
+
+    @utils.deprecated('Use `ChangeSignature.get_args()` instead')
+    def get_definition_info(self):
+        return self._definfo()
+
+    def _definfo(self):
+        return functionutils.DefinitionInfo.read(self.pyname.get_object())
+
+    @utils.deprecated()
+    def normalize(self):
+        changer = _FunctionChangers(
+            self.pyname.get_object(), self.get_definition_info(),
+            [ArgumentNormalizer()])
+        return self._change_calls(changer)
+
+    @utils.deprecated()
+    def remove(self, index):
+        changer = _FunctionChangers(
+            self.pyname.get_object(), self.get_definition_info(),
+            [ArgumentRemover(index)])
+        return self._change_calls(changer)
+
+    @utils.deprecated()
+    def add(self, index, name, default=None, value=None):
+        changer = _FunctionChangers(
+            self.pyname.get_object(), self.get_definition_info(),
+            [ArgumentAdder(index, name, default, value)])
+        return self._change_calls(changer)
+
+    @utils.deprecated()
+    def inline_default(self, index):
+        changer = _FunctionChangers(
+            self.pyname.get_object(), self.get_definition_info(),
+            [ArgumentDefaultInliner(index)])
+        return self._change_calls(changer)
+
+    @utils.deprecated()
+    def reorder(self, new_ordering):
+        changer = _FunctionChangers(
+            self.pyname.get_object(), self.get_definition_info(),
+            [ArgumentReorderer(new_ordering)])
+        return self._change_calls(changer)
+
+    def get_changes(self, changers, in_hierarchy=False, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        """Get changes caused by this refactoring
+
+        `changers` is a list of `_ArgumentChanger`\s.  If `in_hierarchy`
+        is `True` the changers are applyed to all matching methods in
+        the class hierarchy.
+        `resources` can be a list of `rope.base.resource.File`\s that
+        should be searched for occurrences; if `None` all python files
+        in the project are searched.
+
+        """
+        function_changer = _FunctionChangers(self.pyname.get_object(),
+                                             self._definfo(), changers)
+        return self._change_calls(function_changer, in_hierarchy,
+                                  resources, task_handle)
+
+
+class _FunctionChangers(object):
+
+    def __init__(self, pyfunction, definition_info, changers=None):
+        self.pyfunction = pyfunction
+        self.definition_info = definition_info
+        self.changers = changers
+        self.changed_definition_infos = self._get_changed_definition_infos()
+
+    def _get_changed_definition_infos(self):
+        result = []
+        definition_info = self.definition_info
+        result.append(definition_info)
+        for changer in self.changers:
+            definition_info = copy.deepcopy(definition_info)
+            changer.change_definition_info(definition_info)
+            result.append(definition_info)
+        return result
+
+    def change_definition(self, call):
+        return self.changed_definition_infos[-1].to_string()
+
+    def change_call(self, primary, pyname, call):
+        call_info = functionutils.CallInfo.read(
+            primary, pyname, self.definition_info, call)
+        mapping = functionutils.ArgumentMapping(self.definition_info,
+                                                call_info)
+
+        for definition_info, changer in zip(self.changed_definition_infos,
+                                            self.changers):
+            changer.change_argument_mapping(definition_info, mapping)
+
+        return mapping.to_call_info(
+            self.changed_definition_infos[-1]).to_string()
+
+
+class _ArgumentChanger(object):
+
+    def change_definition_info(self, definition_info):
+        pass
+
+    def change_argument_mapping(self, definition_info, argument_mapping):
+        pass
+
+
+class ArgumentNormalizer(_ArgumentChanger):
+    pass
+
+
+class ArgumentRemover(_ArgumentChanger):
+
+    def __init__(self, index):
+        self.index = index
+
+    def change_definition_info(self, call_info):
+        if self.index < len(call_info.args_with_defaults):
+            del call_info.args_with_defaults[self.index]
+        elif self.index == len(call_info.args_with_defaults) and \
+                call_info.args_arg is not None:
+            call_info.args_arg = None
+        elif (self.index == len(call_info.args_with_defaults) and
+              call_info.args_arg is None and
+              call_info.keywords_arg is not None) or \
+                (self.index == len(call_info.args_with_defaults) + 1 and
+                 call_info.args_arg is not None and
+                 call_info.keywords_arg is not None):
+            call_info.keywords_arg = None
+
+    def change_argument_mapping(self, definition_info, mapping):
+        if self.index < len(definition_info.args_with_defaults):
+            name = definition_info.args_with_defaults[0]
+            if name in mapping.param_dict:
+                del mapping.param_dict[name]
+
+
+class ArgumentAdder(_ArgumentChanger):
+
+    def __init__(self, index, name, default=None, value=None):
+        self.index = index
+        self.name = name
+        self.default = default
+        self.value = value
+
+    def change_definition_info(self, definition_info):
+        for pair in definition_info.args_with_defaults:
+            if pair[0] == self.name:
+                raise rope.base.exceptions.RefactoringError(
+                    'Adding duplicate parameter: <%s>.' % self.name)
+        definition_info.args_with_defaults.insert(self.index,
+                                                  (self.name, self.default))
+
+    def change_argument_mapping(self, definition_info, mapping):
+        if self.value is not None:
+            mapping.param_dict[self.name] = self.value
+
+
+class ArgumentDefaultInliner(_ArgumentChanger):
+
+    def __init__(self, index):
+        self.index = index
+        self.remove = False
+
+    def change_definition_info(self, definition_info):
+        if self.remove:
+            definition_info.args_with_defaults[self.index] = \
+                (definition_info.args_with_defaults[self.index][0], None)
+
+    def change_argument_mapping(self, definition_info, mapping):
+        default = definition_info.args_with_defaults[self.index][1]
+        name = definition_info.args_with_defaults[self.index][0]
+        if default is not None and name not in mapping.param_dict:
+            mapping.param_dict[name] = default
+
+
+class ArgumentReorderer(_ArgumentChanger):
+
+    def __init__(self, new_order, autodef=None):
+        """Construct an `ArgumentReorderer`
+
+        Note that the `new_order` is a list containing the new
+        position of parameters; not the position each parameter
+        is going to be moved to. (changed in ``0.5m4``)
+
+        For example changing ``f(a, b, c)`` to ``f(c, a, b)``
+        requires passing ``[2, 0, 1]`` and *not* ``[1, 2, 0]``.
+
+        The `autodef` (automatic default) argument, forces rope to use
+        it as a default if a default is needed after the change.  That
+        happens when an argument without default is moved after
+        another that has a default value.  Note that `autodef` should
+        be a string or `None`; the latter disables adding automatic
+        default.
+
+        """
+        self.new_order = new_order
+        self.autodef = autodef
+
+    def change_definition_info(self, definition_info):
+        new_args = list(definition_info.args_with_defaults)
+        for new_index, index in enumerate(self.new_order):
+            new_args[new_index] = definition_info.args_with_defaults[index]
+        seen_default = False
+        for index, (arg, default) in enumerate(list(new_args)):
+            if default is not None:
+                seen_default = True
+            if seen_default and default is None and self.autodef is not None:
+                new_args[index] = (arg, self.autodef)
+        definition_info.args_with_defaults = new_args
+
+
+class _ChangeCallsInModule(object):
+
+    def __init__(self, project, occurrence_finder, resource, call_changer):
+        self.project = project
+        self.occurrence_finder = occurrence_finder
+        self.resource = resource
+        self.call_changer = call_changer
+
+    def get_changed_module(self):
+        word_finder = worder.Worder(self.source)
+        change_collector = codeanalyze.ChangeCollector(self.source)
+        for occurrence in self.occurrence_finder.find_occurrences(
+                self.resource):
+            if not occurrence.is_called() and not occurrence.is_defined():
+                continue
+            start, end = occurrence.get_primary_range()
+            begin_parens, end_parens = word_finder.\
+                get_word_parens_range(end - 1)
+            if occurrence.is_called():
+                primary, pyname = occurrence.get_primary_and_pyname()
+                changed_call = self.call_changer.change_call(
+                    primary, pyname, self.source[start:end_parens])
+            else:
+                changed_call = self.call_changer.change_definition(
+                    self.source[start:end_parens])
+            if changed_call is not None:
+                change_collector.add_change(start, end_parens, changed_call)
+        return change_collector.get_changed()
+
+    @property
+    @utils.saveit
+    def pymodule(self):
+        return self.project.get_pymodule(self.resource)
+
+    @property
+    @utils.saveit
+    def source(self):
+        if self.resource is not None:
+            return self.resource.read()
+        else:
+            return self.pymodule.source_code
+
+    @property
+    @utils.saveit
+    def lines(self):
+        return self.pymodule.lines
+
+
+class _MultipleFinders(object):
+
+    def __init__(self, finders):
+        self.finders = finders
+
+    def find_occurrences(self, resource=None, pymodule=None):
+        all_occurrences = []
+        for finder in self.finders:
+            all_occurrences.extend(finder.find_occurrences(resource, pymodule))
+        all_occurrences.sort(key=lambda x: x.get_primary_range())
+        return all_occurrences
+
diff --git a/venv/Lib/site-packages/rope/refactor/encapsulate_field.py b/venv/Lib/site-packages/rope/refactor/encapsulate_field.py
new file mode 100644
index 0000000000000000000000000000000000000000..32cb7a957b5f3a61de6dbaeda52c49fb143f78b3
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/encapsulate_field.py
@@ -0,0 +1,209 @@
+from rope.base import evaluate
+from rope.base import exceptions
+from rope.base import libutils
+from rope.base import pynames
+from rope.base import taskhandle
+from rope.base import utils
+from rope.base import worder
+from rope.base.change import ChangeSet, ChangeContents
+from rope.refactor import sourceutils, occurrences
+
+
+class EncapsulateField(object):
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        self.name = worder.get_name_at(resource, offset)
+        this_pymodule = self.project.get_pymodule(resource)
+        self.pyname = evaluate.eval_location(this_pymodule, offset)
+        if not self._is_an_attribute(self.pyname):
+            raise exceptions.RefactoringError(
+                'Encapsulate field should be performed on class attributes.')
+        self.resource = self.pyname.get_definition_location()[0].get_resource()
+
+    def get_changes(self, getter=None, setter=None, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        """Get the changes this refactoring makes
+
+        If `getter` is not `None`, that will be the name of the
+        getter, otherwise ``get_${field_name}`` will be used.  The
+        same is true for `setter` and if it is None set_${field_name} is
+        used.
+
+        `resources` can be a list of `rope.base.resource.File`\s that
+        the refactoring should be applied on; if `None` all python
+        files in the project are searched.
+
+        """
+        if resources is None:
+            resources = self.project.get_python_files()
+        changes = ChangeSet('Encapsulate field <%s>' % self.name)
+        job_set = task_handle.create_jobset('Collecting Changes',
+                                            len(resources))
+        if getter is None:
+            getter = 'get_' + self.name
+        if setter is None:
+            setter = 'set_' + self.name
+        renamer = GetterSetterRenameInModule(
+            self.project, self.name, self.pyname, getter, setter)
+        for file in resources:
+            job_set.started_job(file.path)
+            if file == self.resource:
+                result = self._change_holding_module(changes, renamer,
+                                                     getter, setter)
+                changes.add_change(ChangeContents(self.resource, result))
+            else:
+                result = renamer.get_changed_module(file)
+                if result is not None:
+                    changes.add_change(ChangeContents(file, result))
+            job_set.finished_job()
+        return changes
+
+    def get_field_name(self):
+        """Get the name of the field to be encapsulated"""
+        return self.name
+
+    def _is_an_attribute(self, pyname):
+        if pyname is not None and isinstance(pyname, pynames.AssignedName):
+            pymodule, lineno = self.pyname.get_definition_location()
+            scope = pymodule.get_scope().\
+                get_inner_scope_for_line(lineno)
+            if scope.get_kind() == 'Class':
+                return pyname in scope.get_names().values()
+            parent = scope.parent
+            if parent is not None and parent.get_kind() == 'Class':
+                return pyname in parent.get_names().values()
+        return False
+
+    def _get_defining_class_scope(self):
+        defining_scope = self._get_defining_scope()
+        if defining_scope.get_kind() == 'Function':
+            defining_scope = defining_scope.parent
+        return defining_scope
+
+    def _get_defining_scope(self):
+        pymodule, line = self.pyname.get_definition_location()
+        return pymodule.get_scope().get_inner_scope_for_line(line)
+
+    def _change_holding_module(self, changes, renamer, getter, setter):
+        pymodule = self.project.get_pymodule(self.resource)
+        class_scope = self._get_defining_class_scope()
+        defining_object = self._get_defining_scope().pyobject
+        start, end = sourceutils.get_body_region(defining_object)
+
+        new_source = renamer.get_changed_module(pymodule=pymodule,
+                                                skip_start=start, skip_end=end)
+        if new_source is not None:
+            pymodule = libutils.get_string_module(
+                self.project, new_source, self.resource)
+            class_scope = pymodule.get_scope().\
+                get_inner_scope_for_line(class_scope.get_start())
+        indents = sourceutils.get_indent(self.project) * ' '
+        getter = 'def %s(self):\n%sreturn self.%s' % \
+                 (getter, indents, self.name)
+        setter = 'def %s(self, value):\n%sself.%s = value' % \
+                 (setter, indents, self.name)
+        new_source = sourceutils.add_methods(pymodule, class_scope,
+                                             [getter, setter])
+        return new_source
+
+
+class GetterSetterRenameInModule(object):
+
+    def __init__(self, project, name, pyname, getter, setter):
+        self.project = project
+        self.name = name
+        self.finder = occurrences.create_finder(project, name, pyname)
+        self.getter = getter
+        self.setter = setter
+
+    def get_changed_module(self, resource=None, pymodule=None,
+                           skip_start=0, skip_end=0):
+        change_finder = _FindChangesForModule(self, resource, pymodule,
+                                              skip_start, skip_end)
+        return change_finder.get_changed_module()
+
+
+class _FindChangesForModule(object):
+
+    def __init__(self, finder, resource, pymodule, skip_start, skip_end):
+        self.project = finder.project
+        self.finder = finder.finder
+        self.getter = finder.getter
+        self.setter = finder.setter
+        self.resource = resource
+        self.pymodule = pymodule
+        self.last_modified = 0
+        self.last_set = None
+        self.set_index = None
+        self.skip_start = skip_start
+        self.skip_end = skip_end
+
+    def get_changed_module(self):
+        result = []
+        for occurrence in self.finder.find_occurrences(self.resource,
+                                                       self.pymodule):
+            start, end = occurrence.get_word_range()
+            if self.skip_start <= start < self.skip_end:
+                continue
+            self._manage_writes(start, result)
+            result.append(self.source[self.last_modified:start])
+            if self._is_assigned_in_a_tuple_assignment(occurrence):
+                raise exceptions.RefactoringError(
+                    'Cannot handle tuple assignments in encapsulate field.')
+            if occurrence.is_written():
+                assignment_type = self.worder.get_assignment_type(start)
+                if assignment_type == '=':
+                    result.append(self.setter + '(')
+                else:
+                    var_name = self.source[occurrence.get_primary_range()[0]:
+                                           start] + self.getter + '()'
+                    result.append(self.setter + '(' + var_name
+                                  + ' %s ' % assignment_type[:-1])
+                current_line = self.lines.get_line_number(start)
+                start_line, end_line = self.pymodule.logical_lines.\
+                    logical_line_in(current_line)
+                self.last_set = self.lines.get_line_end(end_line)
+                end = self.source.index('=', end) + 1
+                self.set_index = len(result)
+            else:
+                result.append(self.getter + '()')
+            self.last_modified = end
+        if self.last_modified != 0:
+            self._manage_writes(len(self.source), result)
+            result.append(self.source[self.last_modified:])
+            return ''.join(result)
+        return None
+
+    def _manage_writes(self, offset, result):
+        if self.last_set is not None and self.last_set <= offset:
+            result.append(self.source[self.last_modified:self.last_set])
+            set_value = ''.join(result[self.set_index:]).strip()
+            del result[self.set_index:]
+            result.append(set_value + ')')
+            self.last_modified = self.last_set
+            self.last_set = None
+
+    def _is_assigned_in_a_tuple_assignment(self, occurance):
+        offset = occurance.get_word_range()[0]
+        return self.worder.is_assigned_in_a_tuple_assignment(offset)
+
+    @property
+    @utils.saveit
+    def source(self):
+        if self.resource is not None:
+            return self.resource.read()
+        else:
+            return self.pymodule.source_code
+
+    @property
+    @utils.saveit
+    def lines(self):
+        if self.pymodule is None:
+            self.pymodule = self.project.get_pymodule(self.resource)
+        return self.pymodule.lines
+
+    @property
+    @utils.saveit
+    def worder(self):
+        return worder.Worder(self.source)
diff --git a/venv/Lib/site-packages/rope/refactor/extract.py b/venv/Lib/site-packages/rope/refactor/extract.py
new file mode 100644
index 0000000000000000000000000000000000000000..bfd9a75586602fd247843eb4579e8cd08758a159
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/extract.py
@@ -0,0 +1,817 @@
+import re
+
+from rope.base.utils.datastructures import OrderedSet
+from rope.base import ast, codeanalyze
+from rope.base.change import ChangeSet, ChangeContents
+from rope.base.exceptions import RefactoringError
+from rope.base.utils import pycompat
+from rope.refactor import (sourceutils, similarfinder,
+                           patchedast, suites, usefunction)
+
+
+# Extract refactoring has lots of special cases.  I tried to split it
+# to smaller parts to make it more manageable:
+#
+# _ExtractInfo: holds information about the refactoring; it is passed
+# to the parts that need to have information about the refactoring
+#
+# _ExtractCollector: merely saves all of the information necessary for
+# performing the refactoring.
+#
+# _DefinitionLocationFinder: finds where to insert the definition.
+#
+# _ExceptionalConditionChecker: checks for exceptional conditions in
+# which the refactoring cannot be applied.
+#
+# _ExtractMethodParts: generates the pieces of code (like definition)
+# needed for performing extract method.
+#
+# _ExtractVariableParts: like _ExtractMethodParts for variables.
+#
+# _ExtractPerformer: Uses above classes to collect refactoring
+# changes.
+#
+# There are a few more helper functions and classes used by above
+# classes.
+class _ExtractRefactoring(object):
+
+    def __init__(self, project, resource, start_offset, end_offset,
+                 variable=False):
+        self.project = project
+        self.resource = resource
+        self.start_offset = self._fix_start(resource.read(), start_offset)
+        self.end_offset = self._fix_end(resource.read(), end_offset)
+
+    def _fix_start(self, source, offset):
+        while offset < len(source) and source[offset].isspace():
+            offset += 1
+        return offset
+
+    def _fix_end(self, source, offset):
+        while offset > 0 and source[offset - 1].isspace():
+            offset -= 1
+        return offset
+
+    def get_changes(self, extracted_name, similar=False, global_=False):
+        """Get the changes this refactoring makes
+
+        :parameters:
+            - `similar`: if `True`, similar expressions/statements are also
+              replaced.
+            - `global_`: if `True`, the extracted method/variable will
+              be global.
+
+        """
+        info = _ExtractInfo(
+            self.project, self.resource, self.start_offset, self.end_offset,
+            extracted_name, variable=self.kind == 'variable',
+            similar=similar, make_global=global_)
+        new_contents = _ExtractPerformer(info).extract()
+        changes = ChangeSet('Extract %s <%s>' % (self.kind,
+                                                 extracted_name))
+        changes.add_change(ChangeContents(self.resource, new_contents))
+        return changes
+
+
+class ExtractMethod(_ExtractRefactoring):
+
+    def __init__(self, *args, **kwds):
+        super(ExtractMethod, self).__init__(*args, **kwds)
+
+    kind = 'method'
+
+
+class ExtractVariable(_ExtractRefactoring):
+
+    def __init__(self, *args, **kwds):
+        kwds = dict(kwds)
+        kwds['variable'] = True
+        super(ExtractVariable, self).__init__(*args, **kwds)
+
+    kind = 'variable'
+
+
+class _ExtractInfo(object):
+    """Holds information about the extract to be performed"""
+
+    def __init__(self, project, resource, start, end, new_name,
+                 variable, similar, make_global):
+        self.project = project
+        self.resource = resource
+        self.pymodule = project.get_pymodule(resource)
+        self.global_scope = self.pymodule.get_scope()
+        self.source = self.pymodule.source_code
+        self.lines = self.pymodule.lines
+        self.new_name = new_name
+        self.variable = variable
+        self.similar = similar
+        self._init_parts(start, end)
+        self._init_scope()
+        self.make_global = make_global
+
+    def _init_parts(self, start, end):
+        self.region = (self._choose_closest_line_end(start),
+                       self._choose_closest_line_end(end, end=True))
+
+        start = self.logical_lines.logical_line_in(
+            self.lines.get_line_number(self.region[0]))[0]
+        end = self.logical_lines.logical_line_in(
+            self.lines.get_line_number(self.region[1]))[1]
+        self.region_lines = (start, end)
+
+        self.lines_region = (self.lines.get_line_start(self.region_lines[0]),
+                             self.lines.get_line_end(self.region_lines[1]))
+
+    @property
+    def logical_lines(self):
+        return self.pymodule.logical_lines
+
+    def _init_scope(self):
+        start_line = self.region_lines[0]
+        scope = self.global_scope.get_inner_scope_for_line(start_line)
+        if scope.get_kind() != 'Module' and scope.get_start() == start_line:
+            scope = scope.parent
+        self.scope = scope
+        self.scope_region = self._get_scope_region(self.scope)
+
+    def _get_scope_region(self, scope):
+        return (self.lines.get_line_start(scope.get_start()),
+                self.lines.get_line_end(scope.get_end()) + 1)
+
+    def _choose_closest_line_end(self, offset, end=False):
+        lineno = self.lines.get_line_number(offset)
+        line_start = self.lines.get_line_start(lineno)
+        line_end = self.lines.get_line_end(lineno)
+        if self.source[line_start:offset].strip() == '':
+            if end:
+                return line_start - 1
+            else:
+                return line_start
+        elif self.source[offset:line_end].strip() == '':
+            return min(line_end, len(self.source))
+        return offset
+
+    @property
+    def one_line(self):
+        return self.region != self.lines_region and \
+            (self.logical_lines.logical_line_in(self.region_lines[0]) ==
+             self.logical_lines.logical_line_in(self.region_lines[1]))
+
+    @property
+    def global_(self):
+        return self.scope.parent is None
+
+    @property
+    def method(self):
+        return self.scope.parent is not None and \
+            self.scope.parent.get_kind() == 'Class'
+
+    @property
+    def indents(self):
+        return sourceutils.get_indents(self.pymodule.lines,
+                                       self.region_lines[0])
+
+    @property
+    def scope_indents(self):
+        if self.global_:
+            return 0
+        return sourceutils.get_indents(self.pymodule.lines,
+                                       self.scope.get_start())
+
+    @property
+    def extracted(self):
+        return self.source[self.region[0]:self.region[1]]
+
+    _returned = None
+
+    @property
+    def returned(self):
+        """Does the extracted piece contain return statement"""
+        if self._returned is None:
+            node = _parse_text(self.extracted)
+            self._returned = usefunction._returns_last(node)
+        return self._returned
+
+
+class _ExtractCollector(object):
+    """Collects information needed for performing the extract"""
+
+    def __init__(self, info):
+        self.definition = None
+        self.body_pattern = None
+        self.checks = {}
+        self.replacement_pattern = None
+        self.matches = None
+        self.replacements = None
+        self.definition_location = None
+
+
+class _ExtractPerformer(object):
+
+    def __init__(self, info):
+        self.info = info
+        _ExceptionalConditionChecker()(self.info)
+
+    def extract(self):
+        extract_info = self._collect_info()
+        content = codeanalyze.ChangeCollector(self.info.source)
+        definition = extract_info.definition
+        lineno, indents = extract_info.definition_location
+        offset = self.info.lines.get_line_start(lineno)
+        indented = sourceutils.fix_indentation(definition, indents)
+        content.add_change(offset, offset, indented)
+        self._replace_occurrences(content, extract_info)
+        return content.get_changed()
+
+    def _replace_occurrences(self, content, extract_info):
+        for match in extract_info.matches:
+            replacement = similarfinder.CodeTemplate(
+                extract_info.replacement_pattern)
+            mapping = {}
+            for name in replacement.get_names():
+                node = match.get_ast(name)
+                if node:
+                    start, end = patchedast.node_region(match.get_ast(name))
+                    mapping[name] = self.info.source[start:end]
+                else:
+                    mapping[name] = name
+            region = match.get_region()
+            content.add_change(region[0], region[1],
+                               replacement.substitute(mapping))
+
+    def _collect_info(self):
+        extract_collector = _ExtractCollector(self.info)
+        self._find_definition(extract_collector)
+        self._find_matches(extract_collector)
+        self._find_definition_location(extract_collector)
+        return extract_collector
+
+    def _find_matches(self, collector):
+        regions = self._where_to_search()
+        finder = similarfinder.SimilarFinder(self.info.pymodule)
+        matches = []
+        for start, end in regions:
+            region_matches = finder.get_matches(collector.body_pattern,
+                                               collector.checks, start, end)
+            # Don't extract overlapping regions
+            last_match_end = -1
+            for region_match in region_matches:
+                start, end = region_match.get_region()
+                if last_match_end < start:
+                    matches.append(region_match)
+                    last_match_end = end
+        collector.matches = matches
+
+    def _where_to_search(self):
+        if self.info.similar:
+            if self.info.make_global or self.info.global_:
+                return [(0, len(self.info.pymodule.source_code))]
+            if self.info.method and not self.info.variable:
+                class_scope = self.info.scope.parent
+                regions = []
+                method_kind = _get_function_kind(self.info.scope)
+                for scope in class_scope.get_scopes():
+                    if method_kind == 'method' and \
+                       _get_function_kind(scope) != 'method':
+                        continue
+                    start = self.info.lines.get_line_start(scope.get_start())
+                    end = self.info.lines.get_line_end(scope.get_end())
+                    regions.append((start, end))
+                return regions
+            else:
+                if self.info.variable:
+                    return [self.info.scope_region]
+                else:
+                    return [self.info._get_scope_region(
+                        self.info.scope.parent)]
+        else:
+            return [self.info.region]
+
+    def _find_definition_location(self, collector):
+        matched_lines = []
+        for match in collector.matches:
+            start = self.info.lines.get_line_number(match.get_region()[0])
+            start_line = self.info.logical_lines.logical_line_in(start)[0]
+            matched_lines.append(start_line)
+        location_finder = _DefinitionLocationFinder(self.info, matched_lines)
+        collector.definition_location = (location_finder.find_lineno(),
+                                         location_finder.find_indents())
+
+    def _find_definition(self, collector):
+        if self.info.variable:
+            parts = _ExtractVariableParts(self.info)
+        else:
+            parts = _ExtractMethodParts(self.info)
+        collector.definition = parts.get_definition()
+        collector.body_pattern = parts.get_body_pattern()
+        collector.replacement_pattern = parts.get_replacement_pattern()
+        collector.checks = parts.get_checks()
+
+
+class _DefinitionLocationFinder(object):
+
+    def __init__(self, info, matched_lines):
+        self.info = info
+        self.matched_lines = matched_lines
+        # This only happens when subexpressions cannot be matched
+        if not matched_lines:
+            self.matched_lines.append(self.info.region_lines[0])
+
+    def find_lineno(self):
+        if self.info.variable and not self.info.make_global:
+            return self._get_before_line()
+        if self.info.make_global or self.info.global_:
+            toplevel = self._find_toplevel(self.info.scope)
+            ast = self.info.pymodule.get_ast()
+            newlines = sorted(self.matched_lines + [toplevel.get_end() + 1])
+            return suites.find_visible(ast, newlines)
+        return self._get_after_scope()
+
+    def _find_toplevel(self, scope):
+        toplevel = scope
+        if toplevel.parent is not None:
+            while toplevel.parent.parent is not None:
+                toplevel = toplevel.parent
+        return toplevel
+
+    def find_indents(self):
+        if self.info.variable and not self.info.make_global:
+            return sourceutils.get_indents(self.info.lines,
+                                           self._get_before_line())
+        else:
+            if self.info.global_ or self.info.make_global:
+                return 0
+        return self.info.scope_indents
+
+    def _get_before_line(self):
+        ast = self.info.scope.pyobject.get_ast()
+        return suites.find_visible(ast, self.matched_lines)
+
+    def _get_after_scope(self):
+        return self.info.scope.get_end() + 1
+
+
+class _ExceptionalConditionChecker(object):
+
+    def __call__(self, info):
+        self.base_conditions(info)
+        if info.one_line:
+            self.one_line_conditions(info)
+        else:
+            self.multi_line_conditions(info)
+
+    def base_conditions(self, info):
+        if info.region[1] > info.scope_region[1]:
+            raise RefactoringError('Bad region selected for extract method')
+        end_line = info.region_lines[1]
+        end_scope = info.global_scope.get_inner_scope_for_line(end_line)
+        if end_scope != info.scope and end_scope.get_end() != end_line:
+            raise RefactoringError('Bad region selected for extract method')
+        try:
+            extracted = info.source[info.region[0]:info.region[1]]
+            if info.one_line:
+                extracted = '(%s)' % extracted
+            if _UnmatchedBreakOrContinueFinder.has_errors(extracted):
+                raise RefactoringError('A break/continue without having a '
+                                       'matching for/while loop.')
+        except SyntaxError:
+            raise RefactoringError('Extracted piece should '
+                                   'contain complete statements.')
+
+    def one_line_conditions(self, info):
+        if self._is_region_on_a_word(info):
+            raise RefactoringError('Should extract complete statements.')
+        if info.variable and not info.one_line:
+            raise RefactoringError('Extract variable should not '
+                                   'span multiple lines.')
+
+    def multi_line_conditions(self, info):
+        node = _parse_text(info.source[info.region[0]:info.region[1]])
+        count = usefunction._return_count(node)
+        if count > 1:
+            raise RefactoringError('Extracted piece can have only one '
+                                   'return statement.')
+        if usefunction._yield_count(node):
+            raise RefactoringError('Extracted piece cannot '
+                                   'have yield statements.')
+        if count == 1 and not usefunction._returns_last(node):
+            raise RefactoringError('Return should be the last statement.')
+        if info.region != info.lines_region:
+            raise RefactoringError('Extracted piece should '
+                                   'contain complete statements.')
+
+    def _is_region_on_a_word(self, info):
+        if info.region[0] > 0 and \
+                self._is_on_a_word(info, info.region[0] - 1) or \
+                self._is_on_a_word(info, info.region[1] - 1):
+            return True
+
+    def _is_on_a_word(self, info, offset):
+        prev = info.source[offset]
+        if not (prev.isalnum() or prev == '_') or \
+           offset + 1 == len(info.source):
+            return False
+        next = info.source[offset + 1]
+        return next.isalnum() or next == '_'
+
+
+class _ExtractMethodParts(object):
+
+    def __init__(self, info):
+        self.info = info
+        self.info_collector = self._create_info_collector()
+
+    def get_definition(self):
+        if self.info.global_:
+            return '\n%s\n' % self._get_function_definition()
+        else:
+            return '\n%s' % self._get_function_definition()
+
+    def get_replacement_pattern(self):
+        variables = []
+        variables.extend(self._find_function_arguments())
+        variables.extend(self._find_function_returns())
+        return similarfinder.make_pattern(self._get_call(), variables)
+
+    def get_body_pattern(self):
+        variables = []
+        variables.extend(self._find_function_arguments())
+        variables.extend(self._find_function_returns())
+        variables.extend(self._find_temps())
+        return similarfinder.make_pattern(self._get_body(), variables)
+
+    def _get_body(self):
+        result = sourceutils.fix_indentation(self.info.extracted, 0)
+        if self.info.one_line:
+            result = '(%s)' % result
+        return result
+
+    def _find_temps(self):
+        return usefunction.find_temps(self.info.project,
+                                      self._get_body())
+
+    def get_checks(self):
+        if self.info.method and not self.info.make_global:
+            if _get_function_kind(self.info.scope) == 'method':
+                class_name = similarfinder._pydefined_to_str(
+                    self.info.scope.parent.pyobject)
+                return {self._get_self_name(): 'type=' + class_name}
+        return {}
+
+    def _create_info_collector(self):
+        zero = self.info.scope.get_start() - 1
+        start_line = self.info.region_lines[0] - zero
+        end_line = self.info.region_lines[1] - zero
+        info_collector = _FunctionInformationCollector(start_line, end_line,
+                                                       self.info.global_)
+        body = self.info.source[self.info.scope_region[0]:
+                                self.info.scope_region[1]]
+        node = _parse_text(body)
+        ast.walk(node, info_collector)
+        return info_collector
+
+    def _get_function_definition(self):
+        args = self._find_function_arguments()
+        returns = self._find_function_returns()
+        result = []
+        if self.info.method and not self.info.make_global and \
+           _get_function_kind(self.info.scope) != 'method':
+            result.append('@staticmethod\n')
+        result.append('def %s:\n' % self._get_function_signature(args))
+        unindented_body = self._get_unindented_function_body(returns)
+        indents = sourceutils.get_indent(self.info.project)
+        function_body = sourceutils.indent_lines(unindented_body, indents)
+        result.append(function_body)
+        definition = ''.join(result)
+
+        return definition + '\n'
+
+    def _get_function_signature(self, args):
+        args = list(args)
+        prefix = ''
+        if self._extracting_method():
+            self_name = self._get_self_name()
+            if self_name is None:
+                raise RefactoringError('Extracting a method from a function '
+                                       'with no self argument.')
+            if self_name in args:
+                args.remove(self_name)
+            args.insert(0, self_name)
+        return prefix + self.info.new_name + \
+            '(%s)' % self._get_comma_form(args)
+
+    def _extracting_method(self):
+        return self.info.method and not self.info.make_global and \
+            _get_function_kind(self.info.scope) == 'method'
+
+    def _get_self_name(self):
+        param_names = self.info.scope.pyobject.get_param_names()
+        if param_names:
+            return param_names[0]
+
+    def _get_function_call(self, args):
+        prefix = ''
+        if self.info.method and not self.info.make_global:
+            if _get_function_kind(self.info.scope) == 'method':
+                self_name = self._get_self_name()
+                if self_name in args:
+                    args.remove(self_name)
+                prefix = self_name + '.'
+            else:
+                prefix = self.info.scope.parent.pyobject.get_name() + '.'
+        return prefix + '%s(%s)' % (self.info.new_name,
+                                    self._get_comma_form(args))
+
+    def _get_comma_form(self, names):
+        result = ''
+        if names:
+            result += names[0]
+            for name in names[1:]:
+                result += ', ' + name
+        return result
+
+    def _get_call(self):
+        if self.info.one_line:
+            args = self._find_function_arguments()
+            return self._get_function_call(args)
+        args = self._find_function_arguments()
+        returns = self._find_function_returns()
+        call_prefix = ''
+        if returns:
+            call_prefix = self._get_comma_form(returns) + ' = '
+        if self.info.returned:
+            call_prefix = 'return '
+        return call_prefix + self._get_function_call(args)
+
+    def _find_function_arguments(self):
+        # if not make_global, do not pass any global names; they are
+        # all visible.
+        if self.info.global_ and not self.info.make_global:
+            return ()
+        if not self.info.one_line:
+            result = (self.info_collector.prewritten &
+                      self.info_collector.read)
+            result |= (self.info_collector.prewritten &
+                       self.info_collector.postread &
+                       (self.info_collector.maybe_written -
+                        self.info_collector.written))
+            return list(result)
+        start = self.info.region[0]
+        if start == self.info.lines_region[0]:
+            start = start + re.search('\S', self.info.extracted).start()
+        function_definition = self.info.source[start:self.info.region[1]]
+        read = _VariableReadsAndWritesFinder.find_reads_for_one_liners(
+            function_definition)
+        return list(self.info_collector.prewritten.intersection(read))
+
+    def _find_function_returns(self):
+        if self.info.one_line or self.info.returned:
+            return []
+        written = self.info_collector.written | \
+            self.info_collector.maybe_written
+        return list(written & self.info_collector.postread)
+
+    def _get_unindented_function_body(self, returns):
+        if self.info.one_line:
+            return 'return ' + _join_lines(self.info.extracted)
+        extracted_body = self.info.extracted
+        unindented_body = sourceutils.fix_indentation(extracted_body, 0)
+        if returns:
+            unindented_body += '\nreturn %s' % self._get_comma_form(returns)
+        return unindented_body
+
+
+class _ExtractVariableParts(object):
+
+    def __init__(self, info):
+        self.info = info
+
+    def get_definition(self):
+        result = self.info.new_name + ' = ' + \
+            _join_lines(self.info.extracted) + '\n'
+        return result
+
+    def get_body_pattern(self):
+        return '(%s)' % self.info.extracted.strip()
+
+    def get_replacement_pattern(self):
+        return self.info.new_name
+
+    def get_checks(self):
+        return {}
+
+
+class _FunctionInformationCollector(object):
+
+    def __init__(self, start, end, is_global):
+        self.start = start
+        self.end = end
+        self.is_global = is_global
+        self.prewritten = OrderedSet()
+        self.maybe_written = OrderedSet()
+        self.written = OrderedSet()
+        self.read = OrderedSet()
+        self.postread = OrderedSet()
+        self.postwritten = OrderedSet()
+        self.host_function = True
+        self.conditional = False
+
+    def _read_variable(self, name, lineno):
+        if self.start <= lineno <= self.end:
+            if name not in self.written:
+                if not self.conditional or name not in self.maybe_written:
+                    self.read.add(name)
+        if self.end < lineno:
+            if name not in self.postwritten:
+                self.postread.add(name)
+
+    def _written_variable(self, name, lineno):
+        if self.start <= lineno <= self.end:
+            if self.conditional:
+                self.maybe_written.add(name)
+            else:
+                self.written.add(name)
+        if self.start > lineno:
+            self.prewritten.add(name)
+        if self.end < lineno:
+            self.postwritten.add(name)
+
+    def _FunctionDef(self, node):
+        if not self.is_global and self.host_function:
+            self.host_function = False
+            for name in _get_argnames(node.args):
+                self._written_variable(name, node.lineno)
+            for child in node.body:
+                ast.walk(child, self)
+        else:
+            self._written_variable(node.name, node.lineno)
+            visitor = _VariableReadsAndWritesFinder()
+            for child in node.body:
+                ast.walk(child, visitor)
+            for name in visitor.read - visitor.written:
+                self._read_variable(name, node.lineno)
+
+    def _Name(self, node):
+        if isinstance(node.ctx, (ast.Store, ast.AugStore)):
+            self._written_variable(node.id, node.lineno)
+        if not isinstance(node.ctx, ast.Store):
+            self._read_variable(node.id, node.lineno)
+
+    def _Assign(self, node):
+        ast.walk(node.value, self)
+        for child in node.targets:
+            ast.walk(child, self)
+
+    def _ClassDef(self, node):
+        self._written_variable(node.name, node.lineno)
+
+    def _handle_conditional_node(self, node):
+        self.conditional = True
+        try:
+            for child in ast.get_child_nodes(node):
+                ast.walk(child, self)
+        finally:
+            self.conditional = False
+
+    def _If(self, node):
+        self._handle_conditional_node(node)
+
+    def _While(self, node):
+        self._handle_conditional_node(node)
+
+    def _For(self, node):
+        self.conditional = True
+        try:
+            # iter has to be checked before the target variables
+            ast.walk(node.iter, self)
+            ast.walk(node.target, self)
+
+            for child in node.body:
+                ast.walk(child, self)
+            for child in node.orelse:
+                ast.walk(child, self)
+        finally:
+            self.conditional = False
+
+
+def _get_argnames(arguments):
+    result = [pycompat.get_ast_arg_arg(node) for node in arguments.args
+              if isinstance(node, pycompat.ast_arg_type)]
+    if arguments.vararg:
+        result.append(pycompat.get_ast_arg_arg(arguments.vararg))
+    if arguments.kwarg:
+        result.append(pycompat.get_ast_arg_arg(arguments.kwarg))
+    return result
+
+
+class _VariableReadsAndWritesFinder(object):
+
+    def __init__(self):
+        self.written = set()
+        self.read = set()
+
+    def _Name(self, node):
+        if isinstance(node.ctx, (ast.Store, ast.AugStore)):
+            self.written.add(node.id)
+        if not isinstance(node, ast.Store):
+            self.read.add(node.id)
+
+    def _FunctionDef(self, node):
+        self.written.add(node.name)
+        visitor = _VariableReadsAndWritesFinder()
+        for child in ast.get_child_nodes(node):
+            ast.walk(child, visitor)
+        self.read.update(visitor.read - visitor.written)
+
+    def _Class(self, node):
+        self.written.add(node.name)
+
+    @staticmethod
+    def find_reads_and_writes(code):
+        if code.strip() == '':
+            return set(), set()
+        if isinstance(code, unicode):
+            code = code.encode('utf-8')
+        node = _parse_text(code)
+        visitor = _VariableReadsAndWritesFinder()
+        ast.walk(node, visitor)
+        return visitor.read, visitor.written
+
+    @staticmethod
+    def find_reads_for_one_liners(code):
+        if code.strip() == '':
+            return set(), set()
+        node = _parse_text(code)
+        visitor = _VariableReadsAndWritesFinder()
+        ast.walk(node, visitor)
+        return visitor.read
+
+
+class _UnmatchedBreakOrContinueFinder(object):
+
+    def __init__(self):
+        self.error = False
+        self.loop_count = 0
+
+    def _For(self, node):
+        self.loop_encountered(node)
+
+    def _While(self, node):
+        self.loop_encountered(node)
+
+    def loop_encountered(self, node):
+        self.loop_count += 1
+        for child in node.body:
+            ast.walk(child, self)
+        self.loop_count -= 1
+        if node.orelse:
+            if isinstance(node.orelse,(list,tuple)):
+                for node_ in node.orelse:
+                    ast.walk(node_, self)
+            else:
+                ast.walk(node.orelse, self)
+
+    def _Break(self, node):
+        self.check_loop()
+
+    def _Continue(self, node):
+        self.check_loop()
+
+    def check_loop(self):
+        if self.loop_count < 1:
+            self.error = True
+
+    def _FunctionDef(self, node):
+        pass
+
+    def _ClassDef(self, node):
+        pass
+
+    @staticmethod
+    def has_errors(code):
+        if code.strip() == '':
+            return False
+        node = _parse_text(code)
+        visitor = _UnmatchedBreakOrContinueFinder()
+        ast.walk(node, visitor)
+        return visitor.error
+
+
+def _get_function_kind(scope):
+    return scope.pyobject.get_kind()
+
+
+def _parse_text(body):
+    body = sourceutils.fix_indentation(body, 0)
+    node = ast.parse(body)
+    return node
+
+
+def _join_lines(code):
+    lines = []
+    for line in code.splitlines():
+        if line.endswith('\\'):
+            lines.append(line[:-1].strip())
+        else:
+            lines.append(line.strip())
+    return ' '.join(lines)
diff --git a/venv/Lib/site-packages/rope/refactor/functionutils.py b/venv/Lib/site-packages/rope/refactor/functionutils.py
new file mode 100644
index 0000000000000000000000000000000000000000..58baf9174fd9bec2f18849063f832847103cfdea
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/functionutils.py
@@ -0,0 +1,222 @@
+import rope.base.exceptions
+import rope.base.pyobjects
+from rope.base.builtins import Lambda
+from rope.base import worder
+
+
+class DefinitionInfo(object):
+
+    def __init__(self, function_name, is_method, args_with_defaults,
+                 args_arg, keywords_arg):
+        self.function_name = function_name
+        self.is_method = is_method
+        self.args_with_defaults = args_with_defaults
+        self.args_arg = args_arg
+        self.keywords_arg = keywords_arg
+
+    def to_string(self):
+        return '%s(%s)' % (self.function_name, self.arguments_to_string())
+
+    def arguments_to_string(self, from_index=0):
+        params = []
+        for arg, default in self.args_with_defaults:
+            if default is not None:
+                params.append('%s=%s' % (arg, default))
+            else:
+                params.append(arg)
+        if self.args_arg is not None:
+            params.append('*' + self.args_arg)
+        if self.keywords_arg:
+            params.append('**' + self.keywords_arg)
+        return ', '.join(params[from_index:])
+
+    @staticmethod
+    def _read(pyfunction, code):
+        kind = pyfunction.get_kind()
+        is_method = kind == 'method'
+        is_lambda = kind == 'lambda'
+        info = _FunctionParser(code, is_method, is_lambda)
+        args, keywords = info.get_parameters()
+        args_arg = None
+        keywords_arg = None
+        if args and args[-1].startswith('**'):
+            keywords_arg = args[-1][2:]
+            del args[-1]
+        if args and args[-1].startswith('*'):
+            args_arg = args[-1][1:]
+            del args[-1]
+        args_with_defaults = [(name, None) for name in args]
+        args_with_defaults.extend(keywords)
+        return DefinitionInfo(info.get_function_name(), is_method,
+                              args_with_defaults, args_arg, keywords_arg)
+
+    @staticmethod
+    def read(pyfunction):
+        pymodule = pyfunction.get_module()
+        word_finder = worder.Worder(pymodule.source_code)
+        lineno = pyfunction.get_ast().lineno
+        start = pymodule.lines.get_line_start(lineno)
+        if isinstance(pyfunction, Lambda):
+            call = word_finder.get_lambda_and_args(start)
+        else:
+            call = word_finder.get_function_and_args_in_header(start)
+        return DefinitionInfo._read(pyfunction, call)
+
+
+class CallInfo(object):
+
+    def __init__(self, function_name, args, keywords, args_arg,
+                 keywords_arg, implicit_arg, constructor):
+        self.function_name = function_name
+        self.args = args
+        self.keywords = keywords
+        self.args_arg = args_arg
+        self.keywords_arg = keywords_arg
+        self.implicit_arg = implicit_arg
+        self.constructor = constructor
+
+    def to_string(self):
+        function = self.function_name
+        if self.implicit_arg:
+            function = self.args[0] + '.' + self.function_name
+        params = []
+        start = 0
+        if self.implicit_arg or self.constructor:
+            start = 1
+        if self.args[start:]:
+            params.extend(self.args[start:])
+        if self.keywords:
+            params.extend(['%s=%s' % (name, value)
+                          for name, value in self.keywords])
+        if self.args_arg is not None:
+            params.append('*' + self.args_arg)
+        if self.keywords_arg:
+            params.append('**' + self.keywords_arg)
+        return '%s(%s)' % (function, ', '.join(params))
+
+    @staticmethod
+    def read(primary, pyname, definition_info, code):
+        is_method_call = CallInfo._is_method_call(primary, pyname)
+        is_constructor = CallInfo._is_class(pyname)
+        is_classmethod = CallInfo._is_classmethod(pyname)
+        info = _FunctionParser(code, is_method_call or is_classmethod)
+        args, keywords = info.get_parameters()
+        args_arg = None
+        keywords_arg = None
+        if args and args[-1].startswith('**'):
+            keywords_arg = args[-1][2:]
+            del args[-1]
+        if args and args[-1].startswith('*'):
+            args_arg = args[-1][1:]
+            del args[-1]
+        if is_constructor:
+            args.insert(0, definition_info.args_with_defaults[0][0])
+        return CallInfo(info.get_function_name(), args, keywords, args_arg,
+                        keywords_arg, is_method_call or is_classmethod,
+                        is_constructor)
+
+    @staticmethod
+    def _is_method_call(primary, pyname):
+        return primary is not None and \
+            isinstance(primary.get_object().get_type(),
+                       rope.base.pyobjects.PyClass) and \
+            CallInfo._is_method(pyname)
+
+    @staticmethod
+    def _is_class(pyname):
+        return pyname is not None and \
+            isinstance(pyname.get_object(),
+                       rope.base.pyobjects.PyClass)
+
+    @staticmethod
+    def _is_method(pyname):
+        if pyname is not None and \
+           isinstance(pyname.get_object(), rope.base.pyobjects.PyFunction):
+            return pyname.get_object().get_kind() == 'method'
+        return False
+
+    @staticmethod
+    def _is_classmethod(pyname):
+        if pyname is not None and \
+           isinstance(pyname.get_object(), rope.base.pyobjects.PyFunction):
+            return pyname.get_object().get_kind() == 'classmethod'
+        return False
+
+
+class ArgumentMapping(object):
+
+    def __init__(self, definition_info, call_info):
+        self.call_info = call_info
+        self.param_dict = {}
+        self.keyword_args = []
+        self.args_arg = []
+        for index, value in enumerate(call_info.args):
+            if index < len(definition_info.args_with_defaults):
+                name = definition_info.args_with_defaults[index][0]
+                self.param_dict[name] = value
+            else:
+                self.args_arg.append(value)
+        for name, value in call_info.keywords:
+            index = -1
+            for pair in definition_info.args_with_defaults:
+                if pair[0] == name:
+                    self.param_dict[name] = value
+                    break
+            else:
+                self.keyword_args.append((name, value))
+
+    def to_call_info(self, definition_info):
+        args = []
+        keywords = []
+        for index in range(len(definition_info.args_with_defaults)):
+            name = definition_info.args_with_defaults[index][0]
+            if name in self.param_dict:
+                args.append(self.param_dict[name])
+            else:
+                for i in range(index, len(definition_info.args_with_defaults)):
+                    name = definition_info.args_with_defaults[i][0]
+                    if name in self.param_dict:
+                        keywords.append((name, self.param_dict[name]))
+                break
+        args.extend(self.args_arg)
+        keywords.extend(self.keyword_args)
+        return CallInfo(self.call_info.function_name, args, keywords,
+                        self.call_info.args_arg, self.call_info.keywords_arg,
+                        self.call_info.implicit_arg,
+                        self.call_info.constructor)
+
+
+class _FunctionParser(object):
+
+    def __init__(self, call, implicit_arg, is_lambda=False):
+        self.call = call
+        self.implicit_arg = implicit_arg
+        self.word_finder = worder.Worder(self.call)
+        if is_lambda:
+            self.last_parens = self.call.rindex(':')
+        else:
+            self.last_parens = self.call.rindex(')')
+        self.first_parens = self.word_finder._find_parens_start(
+            self.last_parens)
+
+    def get_parameters(self):
+        args, keywords = self.word_finder.get_parameters(self.first_parens,
+                                                         self.last_parens)
+        if self.is_called_as_a_method():
+            instance = self.call[:self.call.rindex('.', 0, self.first_parens)]
+            args.insert(0, instance.strip())
+        return args, keywords
+
+    def get_instance(self):
+        if self.is_called_as_a_method():
+            return self.word_finder.get_primary_at(
+                self.call.rindex('.', 0, self.first_parens) - 1)
+
+    def get_function_name(self):
+        if self.is_called_as_a_method():
+            return self.word_finder.get_word_at(self.first_parens - 1)
+        else:
+            return self.word_finder.get_primary_at(self.first_parens - 1)
+
+    def is_called_as_a_method(self):
+        return self.implicit_arg and '.' in self.call[:self.first_parens]
diff --git a/venv/Lib/site-packages/rope/refactor/importutils/__init__.py b/venv/Lib/site-packages/rope/refactor/importutils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a44f01b6cd90891465a3101b9184130d3635bc8
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/importutils/__init__.py
@@ -0,0 +1,316 @@
+"""A package for handling imports
+
+This package provides tools for modifying module imports after
+refactorings or as a separate task.
+
+"""
+import rope.base.evaluate
+from rope.base import libutils
+from rope.base.change import ChangeSet, ChangeContents
+from rope.refactor import occurrences, rename
+from rope.refactor.importutils import module_imports, actions
+from rope.refactor.importutils.importinfo import NormalImport, FromImport
+import rope.base.codeanalyze
+
+
+class ImportOrganizer(object):
+    """Perform some import-related commands
+
+    Each method returns a `rope.base.change.Change` object.
+
+    """
+
+    def __init__(self, project):
+        self.project = project
+        self.import_tools = ImportTools(self.project)
+
+    def organize_imports(self, resource, offset=None):
+        return self._perform_command_on_import_tools(
+            self.import_tools.organize_imports, resource, offset)
+
+    def expand_star_imports(self, resource, offset=None):
+        return self._perform_command_on_import_tools(
+            self.import_tools.expand_stars, resource, offset)
+
+    def froms_to_imports(self, resource, offset=None):
+        return self._perform_command_on_import_tools(
+            self.import_tools.froms_to_imports, resource, offset)
+
+    def relatives_to_absolutes(self, resource, offset=None):
+        return self._perform_command_on_import_tools(
+            self.import_tools.relatives_to_absolutes, resource, offset)
+
+    def handle_long_imports(self, resource, offset=None):
+        return self._perform_command_on_import_tools(
+            self.import_tools.handle_long_imports, resource, offset)
+
+    def _perform_command_on_import_tools(self, method, resource, offset):
+        pymodule = self.project.get_pymodule(resource)
+        before_performing = pymodule.source_code
+        import_filter = None
+        if offset is not None:
+            import_filter = self._line_filter(
+                pymodule.lines.get_line_number(offset))
+        result = method(pymodule, import_filter=import_filter)
+        if result is not None and result != before_performing:
+            changes = ChangeSet(method.__name__.replace('_', ' ') +
+                                ' in <%s>' % resource.path)
+            changes.add_change(ChangeContents(resource, result))
+            return changes
+
+    def _line_filter(self, lineno):
+        def import_filter(import_stmt):
+            return import_stmt.start_line <= lineno < import_stmt.end_line
+        return import_filter
+
+
+class ImportTools(object):
+
+    def __init__(self, project):
+        self.project = project
+
+    def get_import(self, resource):
+        """The import statement for `resource`"""
+        module_name = libutils.modname(resource)
+        return NormalImport(((module_name, None), ))
+
+    def get_from_import(self, resource, name):
+        """The from import statement for `name` in `resource`"""
+        module_name = libutils.modname(resource)
+        names = []
+        if isinstance(name, list):
+            names = [(imported, None) for imported in name]
+        else:
+            names = [(name, None), ]
+        return FromImport(module_name, 0, tuple(names))
+
+    def module_imports(self, module, imports_filter=None):
+        return module_imports.ModuleImports(self.project, module,
+                                            imports_filter)
+
+    def froms_to_imports(self, pymodule, import_filter=None):
+        pymodule = self._clean_up_imports(pymodule, import_filter)
+        module_imports = self.module_imports(pymodule, import_filter)
+        for import_stmt in module_imports.imports:
+            if import_stmt.readonly or \
+               not self._is_transformable_to_normal(import_stmt.import_info):
+                continue
+            pymodule = self._from_to_normal(pymodule, import_stmt)
+
+        # Adding normal imports in place of froms
+        module_imports = self.module_imports(pymodule, import_filter)
+        for import_stmt in module_imports.imports:
+            if not import_stmt.readonly and \
+               self._is_transformable_to_normal(import_stmt.import_info):
+                import_stmt.import_info = \
+                    NormalImport(((import_stmt.import_info.module_name,
+                                 None),))
+        module_imports.remove_duplicates()
+        return module_imports.get_changed_source()
+
+    def expand_stars(self, pymodule, import_filter=None):
+        module_imports = self.module_imports(pymodule, import_filter)
+        module_imports.expand_stars()
+        return module_imports.get_changed_source()
+
+    def _from_to_normal(self, pymodule, import_stmt):
+        resource = pymodule.get_resource()
+        from_import = import_stmt.import_info
+        module_name = from_import.module_name
+        for name, alias in from_import.names_and_aliases:
+            imported = name
+            if alias is not None:
+                imported = alias
+            occurrence_finder = occurrences.create_finder(
+                self.project, imported, pymodule[imported], imports=False)
+            source = rename.rename_in_module(
+                occurrence_finder, module_name + '.' + name,
+                pymodule=pymodule, replace_primary=True)
+            if source is not None:
+                pymodule = libutils.get_string_module(
+                    self.project, source, resource)
+        return pymodule
+
+    def _clean_up_imports(self, pymodule, import_filter):
+        resource = pymodule.get_resource()
+        module_with_imports = self.module_imports(pymodule, import_filter)
+        module_with_imports.expand_stars()
+        source = module_with_imports.get_changed_source()
+        if source is not None:
+            pymodule = libutils.get_string_module(
+                self.project, source, resource)
+        source = self.relatives_to_absolutes(pymodule)
+        if source is not None:
+            pymodule = libutils.get_string_module(
+                self.project, source, resource)
+
+        module_with_imports = self.module_imports(pymodule, import_filter)
+        module_with_imports.remove_duplicates()
+        module_with_imports.remove_unused_imports()
+        source = module_with_imports.get_changed_source()
+        if source is not None:
+            pymodule = libutils.get_string_module(
+                self.project, source, resource)
+        return pymodule
+
+    def relatives_to_absolutes(self, pymodule, import_filter=None):
+        module_imports = self.module_imports(pymodule, import_filter)
+        to_be_absolute_list = module_imports.get_relative_to_absolute_list()
+        for name, absolute_name in to_be_absolute_list:
+            pymodule = self._rename_in_module(pymodule, name, absolute_name)
+        module_imports = self.module_imports(pymodule, import_filter)
+        module_imports.get_relative_to_absolute_list()
+        source = module_imports.get_changed_source()
+        if source is None:
+            source = pymodule.source_code
+        return source
+
+    def _is_transformable_to_normal(self, import_info):
+        if not isinstance(import_info, FromImport):
+            return False
+        return True
+
+    def organize_imports(self, pymodule,
+                         unused=True, duplicates=True,
+                         selfs=True, sort=True, import_filter=None):
+        if unused or duplicates:
+            module_imports = self.module_imports(pymodule, import_filter)
+            if unused:
+                module_imports.remove_unused_imports()
+            if self.project.prefs.get("split_imports"):
+                module_imports.force_single_imports()
+            if duplicates:
+                module_imports.remove_duplicates()
+            source = module_imports.get_changed_source()
+            if source is not None:
+                pymodule = libutils.get_string_module(
+                    self.project, source, pymodule.get_resource())
+        if selfs:
+            pymodule = self._remove_self_imports(pymodule, import_filter)
+        if sort:
+            return self.sort_imports(pymodule, import_filter)
+        else:
+            return pymodule.source_code
+
+    def _remove_self_imports(self, pymodule, import_filter=None):
+        module_imports = self.module_imports(pymodule, import_filter)
+        to_be_fixed, to_be_renamed = \
+            module_imports.get_self_import_fix_and_rename_list()
+        for name in to_be_fixed:
+            try:
+                pymodule = self._rename_in_module(pymodule, name, '',
+                                                  till_dot=True)
+            except ValueError:
+                # There is a self import with direct access to it
+                return pymodule
+        for name, new_name in to_be_renamed:
+            pymodule = self._rename_in_module(pymodule, name, new_name)
+        module_imports = self.module_imports(pymodule, import_filter)
+        module_imports.get_self_import_fix_and_rename_list()
+        source = module_imports.get_changed_source()
+        if source is not None:
+            pymodule = libutils.get_string_module(
+                self.project, source, pymodule.get_resource())
+        return pymodule
+
+    def _rename_in_module(self, pymodule, name, new_name, till_dot=False):
+        old_name = name.split('.')[-1]
+        old_pyname = rope.base.evaluate.eval_str(pymodule.get_scope(), name)
+        occurrence_finder = occurrences.create_finder(
+            self.project, old_name, old_pyname, imports=False)
+        changes = rope.base.codeanalyze.ChangeCollector(pymodule.source_code)
+        for occurrence in occurrence_finder.find_occurrences(
+                pymodule=pymodule):
+            start, end = occurrence.get_primary_range()
+            if till_dot:
+                new_end = pymodule.source_code.index('.', end) + 1
+                space = pymodule.source_code[end:new_end - 1].strip()
+                if not space == '':
+                    for c in space:
+                        if not c.isspace() and c not in '\\':
+                            raise ValueError()
+                end = new_end
+            changes.add_change(start, end, new_name)
+        source = changes.get_changed()
+        if source is not None:
+            pymodule = libutils.get_string_module(
+                self.project, source, pymodule.get_resource())
+        return pymodule
+
+    def sort_imports(self, pymodule, import_filter=None):
+        module_imports = self.module_imports(pymodule, import_filter)
+        module_imports.sort_imports()
+        return module_imports.get_changed_source()
+
+    def handle_long_imports(self, pymodule, maxdots=2, maxlength=27,
+                            import_filter=None):
+        # IDEA: `maxdots` and `maxlength` can be specified in project config
+        # adding new from imports
+        module_imports = self.module_imports(pymodule, import_filter)
+        to_be_fixed = module_imports.handle_long_imports(maxdots, maxlength)
+        # performing the renaming
+        pymodule = libutils.get_string_module(
+            self.project, module_imports.get_changed_source(),
+            resource=pymodule.get_resource())
+        for name in to_be_fixed:
+            pymodule = self._rename_in_module(pymodule, name,
+                                              name.split('.')[-1])
+        # organizing imports
+        return self.organize_imports(pymodule, selfs=False, sort=False,
+                                     import_filter=import_filter)
+
+
+def get_imports(project, pydefined):
+    """A shortcut for getting the `ImportInfo`\s used in a scope"""
+    pymodule = pydefined.get_module()
+    module = module_imports.ModuleImports(project, pymodule)
+    if pymodule == pydefined:
+        return [stmt.import_info for stmt in module.imports]
+    return module.get_used_imports(pydefined)
+
+
+def get_module_imports(project, pymodule):
+    """A shortcut for creating a `module_imports.ModuleImports` object"""
+    return module_imports.ModuleImports(project, pymodule)
+
+
+def add_import(project, pymodule, module_name, name=None):
+    imports = get_module_imports(project, pymodule)
+    candidates = []
+    names = []
+    selected_import = None
+    # from mod import name
+    if name is not None:
+        from_import = FromImport(module_name, 0, [(name, None)])
+        names.append(name)
+        candidates.append(from_import)
+    # from pkg import mod
+    if '.' in module_name:
+        pkg, mod = module_name.rsplit('.', 1)
+        from_import = FromImport(pkg, 0, [(mod, None)])
+        if project.prefs.get('prefer_module_from_imports'):
+            selected_import = from_import
+        candidates.append(from_import)
+        if name:
+            names.append(mod + '.' + name)
+        else:
+            names.append(mod)
+    # import mod
+    normal_import = NormalImport([(module_name, None)])
+    if name:
+        names.append(module_name + '.' + name)
+    else:
+        names.append(module_name)
+
+    candidates.append(normal_import)
+
+    visitor = actions.AddingVisitor(project, candidates)
+    if selected_import is None:
+        selected_import = normal_import
+    for import_statement in imports.imports:
+        if import_statement.accept(visitor):
+            selected_import = visitor.import_info
+            break
+    imports.add_import(selected_import)
+    imported_name = names[candidates.index(selected_import)]
+    return imports.get_changed_source(), imported_name
diff --git a/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4f94dc3ce42cf5918f806ddd52032315537be5d7
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/__init__.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/actions.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/actions.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b5ab73c3668c70ef677a03426c8691d92faae459
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/actions.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/importinfo.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/importinfo.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..380b2e75ecf9c5291c56b41b5ab982dd7f65d9cd
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/importinfo.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/module_imports.cpython-37.pyc b/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/module_imports.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2ad17f6f643fb7842242a1a0e76270ffa61be423
Binary files /dev/null and b/venv/Lib/site-packages/rope/refactor/importutils/__pycache__/module_imports.cpython-37.pyc differ
diff --git a/venv/Lib/site-packages/rope/refactor/importutils/actions.py b/venv/Lib/site-packages/rope/refactor/importutils/actions.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd0f70542b10521b2126d0134efa1db30d1e028b
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/importutils/actions.py
@@ -0,0 +1,361 @@
+from rope.base import libutils
+from rope.base import pyobjects, exceptions, stdmods
+from rope.refactor import occurrences
+from rope.refactor.importutils import importinfo
+
+
+class ImportInfoVisitor(object):
+
+    def dispatch(self, import_):
+        try:
+            method_name = 'visit' + import_.import_info.__class__.__name__
+            method = getattr(self, method_name)
+            return method(import_, import_.import_info)
+        except exceptions.ModuleNotFoundError:
+            pass
+
+    def visitEmptyImport(self, import_stmt, import_info):
+        pass
+
+    def visitNormalImport(self, import_stmt, import_info):
+        pass
+
+    def visitFromImport(self, import_stmt, import_info):
+        pass
+
+
+class RelativeToAbsoluteVisitor(ImportInfoVisitor):
+
+    def __init__(self, project, current_folder):
+        self.to_be_absolute = []
+        self.project = project
+        self.folder = current_folder
+        self.context = importinfo.ImportContext(project, current_folder)
+
+    def visitNormalImport(self, import_stmt, import_info):
+        self.to_be_absolute.extend(
+            self._get_relative_to_absolute_list(import_info))
+        new_pairs = []
+        for name, alias in import_info.names_and_aliases:
+            resource = self.project.find_module(name, folder=self.folder)
+            if resource is None:
+                new_pairs.append((name, alias))
+                continue
+            absolute_name = libutils.modname(resource)
+            new_pairs.append((absolute_name, alias))
+        if not import_info._are_name_and_alias_lists_equal(
+                new_pairs, import_info.names_and_aliases):
+            import_stmt.import_info = importinfo.NormalImport(new_pairs)
+
+    def _get_relative_to_absolute_list(self, import_info):
+        result = []
+        for name, alias in import_info.names_and_aliases:
+            if alias is not None:
+                continue
+            resource = self.project.find_module(name, folder=self.folder)
+            if resource is None:
+                continue
+            absolute_name = libutils.modname(resource)
+            if absolute_name != name:
+                result.append((name, absolute_name))
+        return result
+
+    def visitFromImport(self, import_stmt, import_info):
+        resource = import_info.get_imported_resource(self.context)
+        if resource is None:
+            return None
+        absolute_name = libutils.modname(resource)
+        if import_info.module_name != absolute_name:
+            import_stmt.import_info = importinfo.FromImport(
+                absolute_name, 0, import_info.names_and_aliases)
+
+
+class FilteringVisitor(ImportInfoVisitor):
+
+    def __init__(self, project, folder, can_select):
+        self.to_be_absolute = []
+        self.project = project
+        self.can_select = self._transform_can_select(can_select)
+        self.context = importinfo.ImportContext(project, folder)
+
+    def _transform_can_select(self, can_select):
+        def can_select_name_and_alias(name, alias):
+            imported = name
+            if alias is not None:
+                imported = alias
+            return can_select(imported)
+        return can_select_name_and_alias
+
+    def visitNormalImport(self, import_stmt, import_info):
+        new_pairs = []
+        for name, alias in import_info.names_and_aliases:
+            if self.can_select(name, alias):
+                new_pairs.append((name, alias))
+        return importinfo.NormalImport(new_pairs)
+
+    def visitFromImport(self, import_stmt, import_info):
+        if _is_future(import_info):
+            return import_info
+        new_pairs = []
+        if import_info.is_star_import():
+            for name in import_info.get_imported_names(self.context):
+                if self.can_select(name, None):
+                    new_pairs.append(import_info.names_and_aliases[0])
+                    break
+        else:
+            for name, alias in import_info.names_and_aliases:
+                if self.can_select(name, alias):
+                    new_pairs.append((name, alias))
+        return importinfo.FromImport(
+            import_info.module_name, import_info.level, new_pairs)
+
+
+class RemovingVisitor(ImportInfoVisitor):
+
+    def __init__(self, project, folder, can_select):
+        self.to_be_absolute = []
+        self.project = project
+        self.filtering = FilteringVisitor(project, folder, can_select)
+
+    def dispatch(self, import_):
+        result = self.filtering.dispatch(import_)
+        if result is not None:
+            import_.import_info = result
+
+
+class AddingVisitor(ImportInfoVisitor):
+    """A class for adding imports
+
+    Given a list of `ImportInfo`\s, it tries to add each import to the
+    module and returns `True` and gives up when an import can be added
+    to older ones.
+
+    """
+
+    def __init__(self, project, import_list):
+        self.project = project
+        self.import_list = import_list
+        self.import_info = None
+
+    def dispatch(self, import_):
+        for import_info in self.import_list:
+            self.import_info = import_info
+            if ImportInfoVisitor.dispatch(self, import_):
+                return True
+
+    # TODO: Handle adding relative and absolute imports
+    def visitNormalImport(self, import_stmt, import_info):
+        if not isinstance(self.import_info, import_info.__class__):
+            return False
+        # Adding ``import x`` and ``import x.y`` that results ``import x.y``
+        if len(import_info.names_and_aliases) == \
+           len(self.import_info.names_and_aliases) == 1:
+            imported1 = import_info.names_and_aliases[0]
+            imported2 = self.import_info.names_and_aliases[0]
+            if imported1[1] == imported2[1] is None:
+                if imported1[0].startswith(imported2[0] + '.'):
+                    return True
+                if imported2[0].startswith(imported1[0] + '.'):
+                    import_stmt.import_info = self.import_info
+                    return True
+        # Multiple imports using a single import statement is discouraged
+        # so we won't bother adding them.
+        if self.import_info._are_name_and_alias_lists_equal(
+                import_info.names_and_aliases,
+                self.import_info.names_and_aliases):
+            return True
+
+    def visitFromImport(self, import_stmt, import_info):
+        if isinstance(self.import_info, import_info.__class__) and \
+           import_info.module_name == self.import_info.module_name and \
+           import_info.level == self.import_info.level:
+            if import_info.is_star_import():
+                return True
+            if self.import_info.is_star_import():
+                import_stmt.import_info = self.import_info
+                return True
+            if self.project.prefs.get("split_imports"):
+                return self.import_info.names_and_aliases == \
+                    import_info.names_and_aliases
+            new_pairs = list(import_info.names_and_aliases)
+            for pair in self.import_info.names_and_aliases:
+                if pair not in new_pairs:
+                    new_pairs.append(pair)
+            import_stmt.import_info = importinfo.FromImport(
+                import_info.module_name, import_info.level, new_pairs)
+            return True
+
+
+class ExpandStarsVisitor(ImportInfoVisitor):
+
+    def __init__(self, project, folder, can_select):
+        self.project = project
+        self.filtering = FilteringVisitor(project, folder, can_select)
+        self.context = importinfo.ImportContext(project, folder)
+
+    def visitNormalImport(self, import_stmt, import_info):
+        self.filtering.dispatch(import_stmt)
+
+    def visitFromImport(self, import_stmt, import_info):
+        if import_info.is_star_import():
+            new_pairs = []
+            for name in import_info.get_imported_names(self.context):
+                new_pairs.append((name, None))
+            new_import = importinfo.FromImport(
+                import_info.module_name, import_info.level, new_pairs)
+            import_stmt.import_info = \
+                self.filtering.visitFromImport(None, new_import)
+        else:
+            self.filtering.dispatch(import_stmt)
+
+
+class SelfImportVisitor(ImportInfoVisitor):
+
+    def __init__(self, project, current_folder, resource):
+        self.project = project
+        self.folder = current_folder
+        self.resource = resource
+        self.to_be_fixed = set()
+        self.to_be_renamed = set()
+        self.context = importinfo.ImportContext(project, current_folder)
+
+    def visitNormalImport(self, import_stmt, import_info):
+        new_pairs = []
+        for name, alias in import_info.names_and_aliases:
+            resource = self.project.find_module(name, folder=self.folder)
+            if resource is not None and resource == self.resource:
+                imported = name
+                if alias is not None:
+                    imported = alias
+                self.to_be_fixed.add(imported)
+            else:
+                new_pairs.append((name, alias))
+        if not import_info._are_name_and_alias_lists_equal(
+                new_pairs, import_info.names_and_aliases):
+            import_stmt.import_info = importinfo.NormalImport(new_pairs)
+
+    def visitFromImport(self, import_stmt, import_info):
+        resource = import_info.get_imported_resource(self.context)
+        if resource is None:
+            return
+        if resource == self.resource:
+            self._importing_names_from_self(import_info, import_stmt)
+            return
+        pymodule = self.project.get_pymodule(resource)
+        new_pairs = []
+        for name, alias in import_info.names_and_aliases:
+            try:
+                result = pymodule[name].get_object()
+                if isinstance(result, pyobjects.PyModule) and \
+                   result.get_resource() == self.resource:
+                    imported = name
+                    if alias is not None:
+                        imported = alias
+                    self.to_be_fixed.add(imported)
+                else:
+                    new_pairs.append((name, alias))
+            except exceptions.AttributeNotFoundError:
+                new_pairs.append((name, alias))
+        if not import_info._are_name_and_alias_lists_equal(
+                new_pairs, import_info.names_and_aliases):
+            import_stmt.import_info = importinfo.FromImport(
+                import_info.module_name, import_info.level, new_pairs)
+
+    def _importing_names_from_self(self, import_info, import_stmt):
+        if not import_info.is_star_import():
+            for name, alias in import_info.names_and_aliases:
+                if alias is not None:
+                    self.to_be_renamed.add((alias, name))
+        import_stmt.empty_import()
+
+
+class SortingVisitor(ImportInfoVisitor):
+
+    def __init__(self, project, current_folder):
+        self.project = project
+        self.folder = current_folder
+        self.standard = set()
+        self.third_party = set()
+        self.in_project = set()
+        self.future = set()
+        self.context = importinfo.ImportContext(project, current_folder)
+
+    def visitNormalImport(self, import_stmt, import_info):
+        if import_info.names_and_aliases:
+            name, alias = import_info.names_and_aliases[0]
+            resource = self.project.find_module(
+                name, folder=self.folder)
+            self._check_imported_resource(import_stmt, resource, name)
+
+    def visitFromImport(self, import_stmt, import_info):
+        resource = import_info.get_imported_resource(self.context)
+        self._check_imported_resource(import_stmt, resource,
+                                      import_info.module_name)
+
+    def _check_imported_resource(self, import_stmt, resource, imported_name):
+        info = import_stmt.import_info
+        if resource is not None and resource.project == self.project:
+            self.in_project.add(import_stmt)
+        elif _is_future(info):
+            self.future.add(import_stmt)
+        elif imported_name.split('.')[0] in stdmods.standard_modules():
+            self.standard.add(import_stmt)
+        else:
+            self.third_party.add(import_stmt)
+
+
+class LongImportVisitor(ImportInfoVisitor):
+
+    def __init__(self, current_folder, project, maxdots, maxlength):
+        self.maxdots = maxdots
+        self.maxlength = maxlength
+        self.to_be_renamed = set()
+        self.current_folder = current_folder
+        self.project = project
+        self.new_imports = []
+
+    def visitNormalImport(self, import_stmt, import_info):
+        for name, alias in import_info.names_and_aliases:
+            if alias is None and self._is_long(name):
+                self.to_be_renamed.add(name)
+                last_dot = name.rindex('.')
+                from_ = name[:last_dot]
+                imported = name[last_dot + 1:]
+                self.new_imports.append(
+                    importinfo.FromImport(from_, 0, ((imported, None), )))
+
+    def _is_long(self, name):
+        return name.count('.') > self.maxdots or \
+            ('.' in name and len(name) > self.maxlength)
+
+
+class RemovePyNameVisitor(ImportInfoVisitor):
+
+    def __init__(self, project, pymodule, pyname, folder):
+        self.pymodule = pymodule
+        self.pyname = pyname
+        self.context = importinfo.ImportContext(project, folder)
+
+    def visitFromImport(self, import_stmt, import_info):
+        new_pairs = []
+        if not import_info.is_star_import():
+            for name, alias in import_info.names_and_aliases:
+                try:
+                    pyname = self.pymodule[alias or name]
+                    if occurrences.same_pyname(self.pyname, pyname):
+                        continue
+                except exceptions.AttributeNotFoundError:
+                    pass
+                new_pairs.append((name, alias))
+        return importinfo.FromImport(
+            import_info.module_name, import_info.level, new_pairs)
+
+    def dispatch(self, import_):
+        result = ImportInfoVisitor.dispatch(self, import_)
+        if result is not None:
+            import_.import_info = result
+
+
+def _is_future(info):
+    return isinstance(info, importinfo.FromImport) and \
+        info.module_name == '__future__'
diff --git a/venv/Lib/site-packages/rope/refactor/importutils/importinfo.py b/venv/Lib/site-packages/rope/refactor/importutils/importinfo.py
new file mode 100644
index 0000000000000000000000000000000000000000..114080aac486abddf7e14025bc97733e7177ab70
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/importutils/importinfo.py
@@ -0,0 +1,201 @@
+class ImportStatement(object):
+    """Represent an import in a module
+
+    `readonly` attribute controls whether this import can be changed
+    by import actions or not.
+
+    """
+
+    def __init__(self, import_info, start_line, end_line,
+                 main_statement=None, blank_lines=0):
+        self.start_line = start_line
+        self.end_line = end_line
+        self.readonly = False
+        self.main_statement = main_statement
+        self._import_info = None
+        self.import_info = import_info
+        self._is_changed = False
+        self.new_start = None
+        self.blank_lines = blank_lines
+
+    def _get_import_info(self):
+        return self._import_info
+
+    def _set_import_info(self, new_import):
+        if not self.readonly and \
+           new_import is not None and not new_import == self._import_info:
+            self._is_changed = True
+            self._import_info = new_import
+
+    import_info = property(_get_import_info, _set_import_info)
+
+    def get_import_statement(self):
+        if self._is_changed or self.main_statement is None:
+            return self.import_info.get_import_statement()
+        else:
+            return self.main_statement
+
+    def empty_import(self):
+        self.import_info = ImportInfo.get_empty_import()
+
+    def move(self, lineno, blank_lines=0):
+        self.new_start = lineno
+        self.blank_lines = blank_lines
+
+    def get_old_location(self):
+        return self.start_line, self.end_line
+
+    def get_new_start(self):
+        return self.new_start
+
+    def is_changed(self):
+        return self._is_changed or (self.new_start is not None or
+                                    self.new_start != self.start_line)
+
+    def accept(self, visitor):
+        return visitor.dispatch(self)
+
+
+class ImportInfo(object):
+
+    def get_imported_primaries(self, context):
+        pass
+
+    def get_imported_names(self, context):
+        return [primary.split('.')[0]
+                for primary in self.get_imported_primaries(context)]
+
+    def get_import_statement(self):
+        pass
+
+    def is_empty(self):
+        pass
+
+    def __hash__(self):
+        return hash(self.get_import_statement())
+
+    def _are_name_and_alias_lists_equal(self, list1, list2):
+        if len(list1) != len(list2):
+            return False
+        for pair1, pair2 in zip(list1, list2):
+            if pair1 != pair2:
+                return False
+        return True
+
+    def __eq__(self, obj):
+        return isinstance(obj, self.__class__) and \
+            self.get_import_statement() == obj.get_import_statement()
+
+    def __ne__(self, obj):
+        return not self.__eq__(obj)
+
+    @staticmethod
+    def get_empty_import():
+        return EmptyImport()
+
+
+class NormalImport(ImportInfo):
+
+    def __init__(self, names_and_aliases):
+        self.names_and_aliases = names_and_aliases
+
+    def get_imported_primaries(self, context):
+        result = []
+        for name, alias in self.names_and_aliases:
+            if alias:
+                result.append(alias)
+            else:
+                result.append(name)
+        return result
+
+    def get_import_statement(self):
+        result = 'import '
+        for name, alias in self.names_and_aliases:
+            result += name
+            if alias:
+                result += ' as ' + alias
+            result += ', '
+        return result[:-2]
+
+    def is_empty(self):
+        return len(self.names_and_aliases) == 0
+
+
+class FromImport(ImportInfo):
+
+    def __init__(self, module_name, level, names_and_aliases):
+        self.module_name = module_name
+        self.level = level
+        self.names_and_aliases = names_and_aliases
+
+    def get_imported_primaries(self, context):
+        if self.names_and_aliases[0][0] == '*':
+            module = self.get_imported_module(context)
+            return [name for name in module
+                    if not name.startswith('_')]
+        result = []
+        for name, alias in self.names_and_aliases:
+            if alias:
+                result.append(alias)
+            else:
+                result.append(name)
+        return result
+
+    def get_imported_resource(self, context):
+        """Get the imported resource
+
+        Returns `None` if module was not found.
+        """
+        if self.level == 0:
+            return context.project.find_module(
+                self.module_name, folder=context.folder)
+        else:
+            return context.project.find_relative_module(
+                self.module_name, context.folder, self.level)
+
+    def get_imported_module(self, context):
+        """Get the imported `PyModule`
+
+        Raises `rope.base.exceptions.ModuleNotFoundError` if module
+        could not be found.
+        """
+        if self.level == 0:
+            return context.project.get_module(
+                self.module_name, context.folder)
+        else:
+            return context.project.get_relative_module(
+                self.module_name, context.folder, self.level)
+
+    def get_import_statement(self):
+        result = 'from ' + '.' * self.level + self.module_name + ' import '
+        for name, alias in self.names_and_aliases:
+            result += name
+            if alias:
+                result += ' as ' + alias
+            result += ', '
+        return result[:-2]
+
+    def is_empty(self):
+        return len(self.names_and_aliases) == 0
+
+    def is_star_import(self):
+        return len(self.names_and_aliases) > 0 and \
+            self.names_and_aliases[0][0] == '*'
+
+
+class EmptyImport(ImportInfo):
+
+    names_and_aliases = []
+
+    def is_empty(self):
+        return True
+
+    def get_imported_primaries(self, context):
+        return []
+
+
+class ImportContext(object):
+
+    def __init__(self, project, folder):
+        self.project = project
+        self.folder = folder
diff --git a/venv/Lib/site-packages/rope/refactor/importutils/module_imports.py b/venv/Lib/site-packages/rope/refactor/importutils/module_imports.py
new file mode 100644
index 0000000000000000000000000000000000000000..07cc4c71454cf27b34c14c66ef6f48519a34ce0f
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/importutils/module_imports.py
@@ -0,0 +1,506 @@
+from rope.base import ast
+from rope.base import pynames
+from rope.base import utils
+from rope.refactor.importutils import actions
+from rope.refactor.importutils import importinfo
+
+
+class ModuleImports(object):
+
+    def __init__(self, project, pymodule, import_filter=None):
+        self.project = project
+        self.pymodule = pymodule
+        self.separating_lines = 0
+        self.filter = import_filter
+        self.sorted = False
+
+    @property
+    @utils.saveit
+    def imports(self):
+        finder = _GlobalImportFinder(self.pymodule)
+        result = finder.find_import_statements()
+        self.separating_lines = finder.get_separating_line_count()
+        if self.filter is not None:
+            for import_stmt in result:
+                if not self.filter(import_stmt):
+                    import_stmt.readonly = True
+        return result
+
+    def _get_unbound_names(self, defined_pyobject):
+        visitor = _GlobalUnboundNameFinder(self.pymodule, defined_pyobject)
+        ast.walk(self.pymodule.get_ast(), visitor)
+        return visitor.unbound
+
+    def remove_unused_imports(self):
+        can_select = _OneTimeSelector(self._get_unbound_names(self.pymodule))
+        visitor = actions.RemovingVisitor(
+            self.project, self._current_folder(), can_select)
+        for import_statement in self.imports:
+            import_statement.accept(visitor)
+
+    def get_used_imports(self, defined_pyobject):
+        result = []
+        can_select = _OneTimeSelector(
+            self._get_unbound_names(defined_pyobject))
+        visitor = actions.FilteringVisitor(
+            self.project, self._current_folder(), can_select)
+        for import_statement in self.imports:
+            new_import = import_statement.accept(visitor)
+            if new_import is not None and not new_import.is_empty():
+                result.append(new_import)
+        return result
+
+    def get_changed_source(self):
+        if (not self.project.prefs.get("pull_imports_to_top") and
+            not self.sorted):
+            return ''.join(self._rewrite_imports(self.imports))
+
+        # Make sure we forward a removed import's preceding blank
+        # lines count to the following import statement.
+        prev_stmt = None
+        for stmt in self.imports:
+            if prev_stmt is not None and prev_stmt.import_info.is_empty():
+                stmt.blank_lines = max(prev_stmt.blank_lines, stmt.blank_lines)
+            prev_stmt = stmt
+        # The new list of imports.
+        imports = [stmt for stmt in self.imports
+                   if not stmt.import_info.is_empty()]
+
+        after_removing = self._remove_imports(self.imports)
+        first_non_blank = self._first_non_blank_line(after_removing, 0)
+        first_import = self._first_import_line() - 1
+        result = []
+        # Writing module docs
+        result.extend(after_removing[first_non_blank:first_import])
+        # Writing imports
+        sorted_imports = sorted(imports, key=self._get_location)
+        for stmt in sorted_imports:
+            if stmt != sorted_imports[0]:
+                result.append('\n' * stmt.blank_lines)
+            result.append(stmt.get_import_statement() + '\n')
+        if sorted_imports and first_non_blank < len(after_removing):
+            result.append('\n' * self.separating_lines)
+
+        # Writing the body
+        first_after_imports = self._first_non_blank_line(after_removing,
+                                                         first_import)
+        result.extend(after_removing[first_after_imports:])
+        return ''.join(result)
+
+    def _get_import_location(self, stmt):
+        start = stmt.get_new_start()
+        if start is None:
+            start = stmt.get_old_location()[0]
+        return start
+
+    def _get_location(self, stmt):
+        if stmt.get_new_start() is not None:
+            return stmt.get_new_start()
+        else:
+            return stmt.get_old_location()[0]
+
+    def _remove_imports(self, imports):
+        lines = self.pymodule.source_code.splitlines(True)
+        after_removing = []
+        first_import_line = self._first_import_line()
+        last_index = 0
+        for stmt in imports:
+            start, end = stmt.get_old_location()
+            blank_lines = 0
+            if start != first_import_line:
+                blank_lines = _count_blank_lines(lines.__getitem__, start - 2,
+                                                 last_index - 1, -1)
+            after_removing.extend(lines[last_index:start - 1 - blank_lines])
+            last_index = end - 1
+        after_removing.extend(lines[last_index:])
+        return after_removing
+
+    def _rewrite_imports(self, imports):
+        lines = self.pymodule.source_code.splitlines(True)
+        after_rewriting = []
+        last_index = 0
+        for stmt in imports:
+            start, end = stmt.get_old_location()
+            after_rewriting.extend(lines[last_index:start - 1])
+            if not stmt.import_info.is_empty():
+                after_rewriting.append(stmt.get_import_statement() + '\n')
+            last_index = end - 1
+        after_rewriting.extend(lines[last_index:])
+        return after_rewriting
+
+    def _first_non_blank_line(self, lines, lineno):
+        return lineno + _count_blank_lines(lines.__getitem__, lineno,
+                                           len(lines))
+
+    def add_import(self, import_info):
+        visitor = actions.AddingVisitor(self.project, [import_info])
+        for import_statement in self.imports:
+            if import_statement.accept(visitor):
+                break
+        else:
+            lineno = self._get_new_import_lineno()
+            blanks = self._get_new_import_blanks()
+            self.imports.append(importinfo.ImportStatement(
+                                import_info, lineno, lineno,
+                                blank_lines=blanks))
+
+    def _get_new_import_blanks(self):
+        return 0
+
+    def _get_new_import_lineno(self):
+        if self.imports:
+            return self.imports[-1].end_line
+        return 1
+
+    def filter_names(self, can_select):
+        visitor = actions.RemovingVisitor(
+            self.project, self._current_folder(), can_select)
+        for import_statement in self.imports:
+            import_statement.accept(visitor)
+
+    def expand_stars(self):
+        can_select = _OneTimeSelector(self._get_unbound_names(self.pymodule))
+        visitor = actions.ExpandStarsVisitor(
+            self.project, self._current_folder(), can_select)
+        for import_statement in self.imports:
+            import_statement.accept(visitor)
+
+    def remove_duplicates(self):
+        added_imports = []
+        for import_stmt in self.imports:
+            visitor = actions.AddingVisitor(self.project,
+                                            [import_stmt.import_info])
+            for added_import in added_imports:
+                if added_import.accept(visitor):
+                    import_stmt.empty_import()
+            else:
+                added_imports.append(import_stmt)
+
+    def force_single_imports(self):
+        """force a single import per statement"""
+        for import_stmt in self.imports[:]:
+            import_info = import_stmt.import_info
+            if import_info.is_empty() or import_stmt.readonly:
+                continue
+            if len(import_info.names_and_aliases) > 1:
+                for name_and_alias in import_info.names_and_aliases:
+                    if hasattr(import_info, "module_name"):
+                        new_import = importinfo.FromImport(
+                            import_info.module_name, import_info.level,
+                            [name_and_alias])
+                    else:
+                        new_import = importinfo.NormalImport([name_and_alias])
+                    self.add_import(new_import)
+                import_stmt.empty_import()
+
+    def get_relative_to_absolute_list(self):
+        visitor = actions.RelativeToAbsoluteVisitor(
+            self.project, self._current_folder())
+        for import_stmt in self.imports:
+            if not import_stmt.readonly:
+                import_stmt.accept(visitor)
+        return visitor.to_be_absolute
+
+    def get_self_import_fix_and_rename_list(self):
+        visitor = actions.SelfImportVisitor(
+            self.project, self._current_folder(), self.pymodule.get_resource())
+        for import_stmt in self.imports:
+            if not import_stmt.readonly:
+                import_stmt.accept(visitor)
+        return visitor.to_be_fixed, visitor.to_be_renamed
+
+    def _current_folder(self):
+        return self.pymodule.get_resource().parent
+
+    def sort_imports(self):
+        if self.project.prefs.get("sort_imports_alphabetically"):
+            sort_kwargs = dict(key=self._get_import_name)
+        else:
+            sort_kwargs = dict(key=self._key_imports)
+
+        # IDEA: Sort from import list
+        visitor = actions.SortingVisitor(self.project, self._current_folder())
+        for import_statement in self.imports:
+            import_statement.accept(visitor)
+        in_projects = sorted(visitor.in_project, **sort_kwargs)
+        third_party = sorted(visitor.third_party, **sort_kwargs)
+        standards = sorted(visitor.standard, **sort_kwargs)
+        future = sorted(visitor.future, **sort_kwargs)
+        last_index = self._first_import_line()
+        last_index = self._move_imports(future, last_index, 0)
+        last_index = self._move_imports(standards, last_index, 1)
+        last_index = self._move_imports(third_party, last_index, 1)
+        last_index = self._move_imports(in_projects, last_index, 1)
+        self.separating_lines = 2
+        self.sorted = True
+
+    def _first_import_line(self):
+        nodes = self.pymodule.get_ast().body
+        lineno = 0
+        if self.pymodule.get_doc() is not None:
+            lineno = 1
+        if len(nodes) > lineno:
+            if (isinstance(nodes[lineno], ast.Import) or
+                isinstance(nodes[lineno], ast.ImportFrom)):
+                return nodes[lineno].lineno
+            lineno = self.pymodule.logical_lines.logical_line_in(
+                nodes[lineno].lineno)[0]
+        else:
+            lineno = self.pymodule.lines.length()
+
+        return lineno - _count_blank_lines(self.pymodule.lines.get_line,
+                                           lineno - 1, 1, -1)
+
+    def _get_import_name(self, import_stmt):
+        import_info = import_stmt.import_info
+        if hasattr(import_info, "module_name"):
+            return "%s.%s" % (import_info.module_name,
+                              import_info.names_and_aliases[0][0])
+        else:
+            return import_info.names_and_aliases[0][0]
+
+    def _key_imports(self, stm1):
+        str1 = stm1.get_import_statement()
+        return str1.startswith("from "), str1
+
+        #str1 = stmt1.get_import_statement()
+        #str2 = stmt2.get_import_statement()
+        #if str1.startswith('from ') and not str2.startswith('from '):
+        #    return 1
+        #if not str1.startswith('from ') and str2.startswith('from '):
+        #    return -1
+        #return cmp(str1, str2)
+
+    def _move_imports(self, imports, index, blank_lines):
+        if imports:
+            imports[0].move(index, blank_lines)
+            index += 1
+            if len(imports) > 1:
+                for stmt in imports[1:]:
+                    stmt.move(index)
+                    index += 1
+        return index
+
+    def handle_long_imports(self, maxdots, maxlength):
+        visitor = actions.LongImportVisitor(
+            self._current_folder(), self.project, maxdots, maxlength)
+        for import_statement in self.imports:
+            if not import_statement.readonly:
+                import_statement.accept(visitor)
+        for import_info in visitor.new_imports:
+            self.add_import(import_info)
+        return visitor.to_be_renamed
+
+    def remove_pyname(self, pyname):
+        """Removes pyname when imported in ``from mod import x``"""
+        visitor = actions.RemovePyNameVisitor(self.project, self.pymodule,
+                                              pyname, self._current_folder())
+        for import_stmt in self.imports:
+            import_stmt.accept(visitor)
+
+
+def _count_blank_lines(get_line, start, end, step=1):
+    count = 0
+    for idx in range(start, end, step):
+        if get_line(idx).strip() == '':
+            count += 1
+        else:
+            break
+    return count
+
+
+class _OneTimeSelector(object):
+
+    def __init__(self, names):
+        self.names = names
+        self.selected_names = set()
+
+    def __call__(self, imported_primary):
+        if self._can_name_be_added(imported_primary):
+            for name in self._get_dotted_tokens(imported_primary):
+                self.selected_names.add(name)
+            return True
+        return False
+
+    def _get_dotted_tokens(self, imported_primary):
+        tokens = imported_primary.split('.')
+        for i in range(len(tokens)):
+            yield '.'.join(tokens[:i + 1])
+
+    def _can_name_be_added(self, imported_primary):
+        for name in self._get_dotted_tokens(imported_primary):
+            if name in self.names and name not in self.selected_names:
+                return True
+        return False
+
+
+class _UnboundNameFinder(object):
+
+    def __init__(self, pyobject):
+        self.pyobject = pyobject
+
+    def _visit_child_scope(self, node):
+        pyobject = self.pyobject.get_module().get_scope().\
+            get_inner_scope_for_line(node.lineno).pyobject
+        visitor = _LocalUnboundNameFinder(pyobject, self)
+        for child in ast.get_child_nodes(node):
+            ast.walk(child, visitor)
+
+    def _FunctionDef(self, node):
+        self._visit_child_scope(node)
+
+    def _ClassDef(self, node):
+        self._visit_child_scope(node)
+
+    def _Name(self, node):
+        if self._get_root()._is_node_interesting(node) and \
+           not self.is_bound(node.id):
+            self.add_unbound(node.id)
+
+    def _Attribute(self, node):
+        result = []
+        while isinstance(node, ast.Attribute):
+            result.append(node.attr)
+            node = node.value
+        if isinstance(node, ast.Name):
+            result.append(node.id)
+            primary = '.'.join(reversed(result))
+            if self._get_root()._is_node_interesting(node) and \
+               not self.is_bound(primary):
+                self.add_unbound(primary)
+        else:
+            ast.walk(node, self)
+
+    def _get_root(self):
+        pass
+
+    def is_bound(self, name, propagated=False):
+        pass
+
+    def add_unbound(self, name):
+        pass
+
+
+class _GlobalUnboundNameFinder(_UnboundNameFinder):
+
+    def __init__(self, pymodule, wanted_pyobject):
+        super(_GlobalUnboundNameFinder, self).__init__(pymodule)
+        self.unbound = set()
+        self.names = set()
+        for name, pyname in pymodule._get_structural_attributes().items():
+            if not isinstance(pyname, (pynames.ImportedName,
+                                       pynames.ImportedModule)):
+                self.names.add(name)
+        wanted_scope = wanted_pyobject.get_scope()
+        self.start = wanted_scope.get_start()
+        self.end = wanted_scope.get_end() + 1
+
+    def _get_root(self):
+        return self
+
+    def is_bound(self, primary, propagated=False):
+        name = primary.split('.')[0]
+        if name in self.names:
+            return True
+        return False
+
+    def add_unbound(self, name):
+        names = name.split('.')
+        for i in range(len(names)):
+            self.unbound.add('.'.join(names[:i + 1]))
+
+    def _is_node_interesting(self, node):
+        return self.start <= node.lineno < self.end
+
+
+class _LocalUnboundNameFinder(_UnboundNameFinder):
+
+    def __init__(self, pyobject, parent):
+        super(_LocalUnboundNameFinder, self).__init__(pyobject)
+        self.parent = parent
+
+    def _get_root(self):
+        return self.parent._get_root()
+
+    def is_bound(self, primary, propagated=False):
+        name = primary.split('.')[0]
+        if propagated:
+            names = self.pyobject.get_scope().get_propagated_names()
+        else:
+            names = self.pyobject.get_scope().get_names()
+        if name in names or self.parent.is_bound(name, propagated=True):
+            return True
+        return False
+
+    def add_unbound(self, name):
+        self.parent.add_unbound(name)
+
+
+class _GlobalImportFinder(object):
+
+    def __init__(self, pymodule):
+        self.current_folder = None
+        if pymodule.get_resource():
+            self.current_folder = pymodule.get_resource().parent
+            self.pymodule = pymodule
+        self.imports = []
+        self.pymodule = pymodule
+        self.lines = self.pymodule.lines
+
+    def visit_import(self, node, end_line):
+        start_line = node.lineno
+        import_statement = importinfo.ImportStatement(
+            importinfo.NormalImport(self._get_names(node.names)),
+            start_line, end_line, self._get_text(start_line, end_line),
+            blank_lines=self._count_empty_lines_before(start_line))
+        self.imports.append(import_statement)
+
+    def _count_empty_lines_before(self, lineno):
+        return _count_blank_lines(self.lines.get_line, lineno - 1, 0, -1)
+
+    def _count_empty_lines_after(self, lineno):
+        return _count_blank_lines(self.lines.get_line, lineno + 1,
+                                  self.lines.length())
+
+    def get_separating_line_count(self):
+        if not self.imports:
+            return 0
+        return self._count_empty_lines_after(self.imports[-1].end_line - 1)
+
+    def _get_text(self, start_line, end_line):
+        result = []
+        for index in range(start_line, end_line):
+            result.append(self.lines.get_line(index))
+        return '\n'.join(result)
+
+    def visit_from(self, node, end_line):
+        level = 0
+        if node.level:
+            level = node.level
+        import_info = importinfo.FromImport(
+            node.module or '',  # see comment at rope.base.ast.walk
+            level, self._get_names(node.names))
+        start_line = node.lineno
+        self.imports.append(importinfo.ImportStatement(
+                            import_info, node.lineno, end_line,
+                            self._get_text(start_line, end_line),
+                            blank_lines=
+                            self._count_empty_lines_before(start_line)))
+
+    def _get_names(self, alias_names):
+        result = []
+        for alias in alias_names:
+            result.append((alias.name, alias.asname))
+        return result
+
+    def find_import_statements(self):
+        nodes = self.pymodule.get_ast().body
+        for index, node in enumerate(nodes):
+            if isinstance(node, (ast.Import, ast.ImportFrom)):
+                lines = self.pymodule.logical_lines
+                end_line = lines.logical_line_in(node.lineno)[1] + 1
+            if isinstance(node, ast.Import):
+                self.visit_import(node, end_line)
+            if isinstance(node, ast.ImportFrom):
+                self.visit_from(node, end_line)
+        return self.imports
diff --git a/venv/Lib/site-packages/rope/refactor/inline.py b/venv/Lib/site-packages/rope/refactor/inline.py
new file mode 100644
index 0000000000000000000000000000000000000000..467edefaa16facf95ef77406a32ce54e95688fad
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/inline.py
@@ -0,0 +1,625 @@
+# Known Bugs when inlining a function/method
+# The values passed to function are inlined using _inlined_variable.
+# This may cause two problems, illustrated in the examples below
+#
+# def foo(var1):
+#    var1 = var1*10
+#    return var1
+#
+#  If a call to foo(20) is inlined, the result of inlined function is 20,
+#  but it should be 200.
+#
+# def foo(var1):
+#    var2 = var1*10
+#    return var2
+#
+# 2- If a call to foo(10+10) is inlined the result of inlined function is 110
+#  but it should be 200.
+
+import re
+
+import rope.base.exceptions
+import rope.refactor.functionutils
+from rope.base import (pynames, pyobjects, codeanalyze,
+                       taskhandle, evaluate, worder, utils, libutils)
+from rope.base.change import ChangeSet, ChangeContents
+from rope.refactor import (occurrences, rename, sourceutils,
+                           importutils, move, change_signature)
+
+
+def unique_prefix():
+    n = 0
+    while True:
+        yield "__" + str(n) + "__"
+        n += 1
+
+
+def create_inline(project, resource, offset):
+    """Create a refactoring object for inlining
+
+    Based on `resource` and `offset` it returns an instance of
+    `InlineMethod`, `InlineVariable` or `InlineParameter`.
+
+    """
+    pyname = _get_pyname(project, resource, offset)
+    message = 'Inline refactoring should be performed on ' \
+              'a method, local variable or parameter.'
+    if pyname is None:
+        raise rope.base.exceptions.RefactoringError(message)
+    if isinstance(pyname, pynames.ImportedName):
+        pyname = pyname._get_imported_pyname()
+    if isinstance(pyname, pynames.AssignedName):
+        return InlineVariable(project, resource, offset)
+    if isinstance(pyname, pynames.ParameterName):
+        return InlineParameter(project, resource, offset)
+    if isinstance(pyname.get_object(), pyobjects.PyFunction):
+        return InlineMethod(project, resource, offset)
+    else:
+        raise rope.base.exceptions.RefactoringError(message)
+
+
+class _Inliner(object):
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        self.pyname = _get_pyname(project, resource, offset)
+        range_finder = worder.Worder(resource.read(), True)
+        self.region = range_finder.get_primary_range(offset)
+        self.name = range_finder.get_word_at(offset)
+        self.offset = offset
+        self.original = resource
+
+    def get_changes(self, *args, **kwds):
+        pass
+
+    def get_kind(self):
+        """Return either 'variable', 'method' or 'parameter'"""
+
+
+class InlineMethod(_Inliner):
+
+    def __init__(self, *args, **kwds):
+        super(InlineMethod, self).__init__(*args, **kwds)
+        self.pyfunction = self.pyname.get_object()
+        self.pymodule = self.pyfunction.get_module()
+        self.resource = self.pyfunction.get_module().get_resource()
+        self.occurrence_finder = occurrences.create_finder(
+            self.project, self.name, self.pyname)
+        self.normal_generator = _DefinitionGenerator(self.project,
+                                                     self.pyfunction)
+        self._init_imports()
+
+    def _init_imports(self):
+        body = sourceutils.get_body(self.pyfunction)
+        body, imports = move.moving_code_with_imports(
+            self.project, self.resource, body)
+        self.imports = imports
+        self.others_generator = _DefinitionGenerator(
+            self.project, self.pyfunction, body=body)
+
+    def _get_scope_range(self):
+        scope = self.pyfunction.get_scope()
+        lines = self.pymodule.lines
+        start_line = scope.get_start()
+        if self.pyfunction.decorators:
+            decorators = self.pyfunction.decorators
+            if hasattr(decorators[0], 'lineno'):
+                start_line = decorators[0].lineno
+        start_offset = lines.get_line_start(start_line)
+        end_offset = min(lines.get_line_end(scope.end) + 1,
+                         len(self.pymodule.source_code))
+        return (start_offset, end_offset)
+
+    def get_changes(self, remove=True, only_current=False, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        """Get the changes this refactoring makes
+
+        If `remove` is `False` the definition will not be removed.  If
+        `only_current` is `True`, the the current occurrence will be
+        inlined, only.
+        """
+        changes = ChangeSet('Inline method <%s>' % self.name)
+        if resources is None:
+            resources = self.project.get_python_files()
+        if only_current:
+            resources = [self.original]
+            if remove:
+                resources.append(self.resource)
+        job_set = task_handle.create_jobset('Collecting Changes',
+                                            len(resources))
+        for file in resources:
+            job_set.started_job(file.path)
+            if file == self.resource:
+                changes.add_change(self._defining_file_changes(
+                    changes, remove=remove, only_current=only_current))
+            else:
+                aim = None
+                if only_current and self.original == file:
+                    aim = self.offset
+                handle = _InlineFunctionCallsForModuleHandle(
+                    self.project, file, self.others_generator, aim)
+                result = move.ModuleSkipRenamer(
+                    self.occurrence_finder, file, handle).get_changed_module()
+                if result is not None:
+                    result = _add_imports(self.project, result,
+                                          file, self.imports)
+                    if remove:
+                        result = _remove_from(self.project, self.pyname,
+                                              result, file)
+                    changes.add_change(ChangeContents(file, result))
+            job_set.finished_job()
+        return changes
+
+    def _get_removed_range(self):
+        scope = self.pyfunction.get_scope()
+        lines = self.pymodule.lines
+        start, end = self._get_scope_range()
+        end_line = scope.get_end()
+        for i in range(end_line + 1, lines.length()):
+            if lines.get_line(i).strip() == '':
+                end_line = i
+            else:
+                break
+        end = min(lines.get_line_end(end_line) + 1,
+                  len(self.pymodule.source_code))
+        return (start, end)
+
+    def _defining_file_changes(self, changes, remove, only_current):
+        start_offset, end_offset = self._get_removed_range()
+        aim = None
+        if only_current:
+            if self.resource == self.original:
+                aim = self.offset
+            else:
+                # we don't want to change any of them
+                aim = len(self.resource.read()) + 100
+        handle = _InlineFunctionCallsForModuleHandle(
+            self.project, self.resource,
+            self.normal_generator, aim_offset=aim)
+        replacement = None
+        if remove:
+            replacement = self._get_method_replacement()
+        result = move.ModuleSkipRenamer(
+            self.occurrence_finder, self.resource, handle, start_offset,
+            end_offset, replacement).get_changed_module()
+        return ChangeContents(self.resource, result)
+
+    def _get_method_replacement(self):
+        if self._is_the_last_method_of_a_class():
+            indents = sourceutils.get_indents(
+                self.pymodule.lines, self.pyfunction.get_scope().get_start())
+            return ' ' * indents + 'pass\n'
+        return ''
+
+    def _is_the_last_method_of_a_class(self):
+        pyclass = self.pyfunction.parent
+        if not isinstance(pyclass, pyobjects.PyClass):
+            return False
+        class_start, class_end = sourceutils.get_body_region(pyclass)
+        source = self.pymodule.source_code
+        func_start, func_end = self._get_scope_range()
+        if source[class_start:func_start].strip() == '' and \
+           source[func_end:class_end].strip() == '':
+            return True
+        return False
+
+    def get_kind(self):
+        return 'method'
+
+
+class InlineVariable(_Inliner):
+
+    def __init__(self, *args, **kwds):
+        super(InlineVariable, self).__init__(*args, **kwds)
+        self.pymodule = self.pyname.get_definition_location()[0]
+        self.resource = self.pymodule.get_resource()
+        self._check_exceptional_conditions()
+        self._init_imports()
+
+    def _check_exceptional_conditions(self):
+        if len(self.pyname.assignments) != 1:
+            raise rope.base.exceptions.RefactoringError(
+                'Local variable should be assigned once for inlining.')
+
+    def get_changes(self, remove=True, only_current=False, resources=None,
+                    docs=False, task_handle=taskhandle.NullTaskHandle()):
+        if resources is None:
+            if rename._is_local(self.pyname):
+                resources = [self.resource]
+            else:
+                resources = self.project.get_python_files()
+        if only_current:
+            resources = [self.original]
+            if remove and self.original != self.resource:
+                resources.append(self.resource)
+        changes = ChangeSet('Inline variable <%s>' % self.name)
+        jobset = task_handle.create_jobset('Calculating changes',
+                                           len(resources))
+
+        for resource in resources:
+            jobset.started_job(resource.path)
+            if resource == self.resource:
+                source = self._change_main_module(remove, only_current, docs)
+                changes.add_change(ChangeContents(self.resource, source))
+            else:
+                result = self._change_module(resource, remove, only_current)
+                if result is not None:
+                    result = _add_imports(self.project, result,
+                                          resource, self.imports)
+                    changes.add_change(ChangeContents(resource, result))
+            jobset.finished_job()
+        return changes
+
+    def _change_main_module(self, remove, only_current, docs):
+        region = None
+        if only_current and self.original == self.resource:
+            region = self.region
+        return _inline_variable(self.project, self.pymodule, self.pyname,
+                                self.name, remove=remove, region=region,
+                                docs=docs)
+
+    def _init_imports(self):
+        vardef = _getvardef(self.pymodule, self.pyname)
+        self.imported, self.imports = move.moving_code_with_imports(
+            self.project, self.resource, vardef)
+
+    def _change_module(self, resource, remove, only_current):
+        filters = [occurrences.NoImportsFilter(),
+                   occurrences.PyNameFilter(self.pyname)]
+        if only_current and resource == self.original:
+            def check_aim(occurrence):
+                start, end = occurrence.get_primary_range()
+                if self.offset < start or end < self.offset:
+                    return False
+            filters.insert(0, check_aim)
+        finder = occurrences.Finder(self.project, self.name, filters=filters)
+        changed = rename.rename_in_module(
+            finder, self.imported, resource=resource, replace_primary=True)
+        if changed and remove:
+            changed = _remove_from(self.project, self.pyname,
+                                   changed, resource)
+        return changed
+
+    def get_kind(self):
+        return 'variable'
+
+
+class InlineParameter(_Inliner):
+
+    def __init__(self, *args, **kwds):
+        super(InlineParameter, self).__init__(*args, **kwds)
+        resource, offset = self._function_location()
+        index = self.pyname.index
+        self.changers = [change_signature.ArgumentDefaultInliner(index)]
+        self.signature = change_signature.ChangeSignature(self.project,
+                                                          resource, offset)
+
+    def _function_location(self):
+        pymodule, lineno = self.pyname.get_definition_location()
+        resource = pymodule.get_resource()
+        start = pymodule.lines.get_line_start(lineno)
+        word_finder = worder.Worder(pymodule.source_code)
+        offset = word_finder.find_function_offset(start)
+        return resource, offset
+
+    def get_changes(self, **kwds):
+        """Get the changes needed by this refactoring
+
+        See `rope.refactor.change_signature.ChangeSignature.get_changes()`
+        for arguments.
+        """
+        return self.signature.get_changes(self.changers, **kwds)
+
+    def get_kind(self):
+        return 'parameter'
+
+
+def _join_lines(lines):
+    definition_lines = []
+    for unchanged_line in lines:
+        line = unchanged_line.strip()
+        if line.endswith('\\'):
+            line = line[:-1].strip()
+        definition_lines.append(line)
+    joined = ' '.join(definition_lines)
+    return joined
+
+
+class _DefinitionGenerator(object):
+    unique_prefix = unique_prefix()
+
+    def __init__(self, project, pyfunction, body=None):
+        self.project = project
+        self.pyfunction = pyfunction
+        self.pymodule = pyfunction.get_module()
+        self.resource = self.pymodule.get_resource()
+        self.definition_info = self._get_definition_info()
+        self.definition_params = self._get_definition_params()
+        self._calculated_definitions = {}
+        if body is not None:
+            self.body = body
+        else:
+            self.body = sourceutils.get_body(self.pyfunction)
+
+    def _get_definition_info(self):
+        return rope.refactor.functionutils.DefinitionInfo.read(self.pyfunction)
+
+    def _get_definition_params(self):
+        definition_info = self.definition_info
+        paramdict = dict([pair for pair in definition_info.args_with_defaults])
+        if definition_info.args_arg is not None or \
+           definition_info.keywords_arg is not None:
+            raise rope.base.exceptions.RefactoringError(
+                'Cannot inline functions with list and keyword arguements.')
+        if self.pyfunction.get_kind() == 'classmethod':
+            paramdict[definition_info.args_with_defaults[0][0]] = \
+                self.pyfunction.parent.get_name()
+        return paramdict
+
+    def get_function_name(self):
+        return self.pyfunction.get_name()
+
+    def get_definition(self, primary, pyname, call, host_vars=[],
+                       returns=False):
+        # caching already calculated definitions
+        return self._calculate_definition(primary, pyname, call,
+                                          host_vars, returns)
+
+    def _calculate_header(self, primary, pyname, call):
+        # A header is created which initializes parameters
+        # to the values passed to the function.
+        call_info = rope.refactor.functionutils.CallInfo.read(
+            primary, pyname, self.definition_info, call)
+        paramdict = self.definition_params
+        mapping = rope.refactor.functionutils.ArgumentMapping(
+            self.definition_info, call_info)
+        for param_name, value in mapping.param_dict.items():
+            paramdict[param_name] = value
+        header = ''
+        to_be_inlined = []
+        for name, value in paramdict.items():
+            if name != value and value is not None:
+                header += name + ' = ' + value.replace('\n', ' ') + '\n'
+                to_be_inlined.append(name)
+        return header, to_be_inlined
+
+    def _calculate_definition(self, primary, pyname, call, host_vars, returns):
+
+        header, to_be_inlined = self._calculate_header(primary, pyname, call)
+
+        source = header + self.body
+        mod = libutils.get_string_module(self.project, source)
+        name_dict = mod.get_scope().get_names()
+        all_names = [x for x in name_dict if
+                     not isinstance(name_dict[x],
+                                    rope.base.builtins.BuiltinName)]
+
+        # If there is a name conflict, all variable names
+        # inside the inlined function are renamed
+        if len(set(all_names).intersection(set(host_vars))) > 0:
+
+            prefix = next(_DefinitionGenerator.unique_prefix)
+            guest = libutils.get_string_module(self.project, source,
+                                               self.resource)
+
+            to_be_inlined = [prefix + item for item in to_be_inlined]
+            for item in all_names:
+                pyname = guest[item]
+                occurrence_finder = occurrences.create_finder(self.project,
+                                                              item, pyname)
+                source = rename.rename_in_module(occurrence_finder,
+                                                 prefix + item, pymodule=guest)
+                guest = libutils.get_string_module(
+                    self.project, source, self.resource)
+
+        #parameters not reassigned inside the functions are now inlined.
+        for name in to_be_inlined:
+            pymodule = libutils.get_string_module(
+                self.project, source, self.resource)
+            pyname = pymodule[name]
+            source = _inline_variable(self.project, pymodule, pyname, name)
+
+        return self._replace_returns_with(source, returns)
+
+    def _replace_returns_with(self, source, returns):
+        result = []
+        returned = None
+        last_changed = 0
+        for match in _DefinitionGenerator._get_return_pattern().finditer(
+                source):
+            for key, value in match.groupdict().items():
+                if value and key == 'return':
+                    result.append(source[last_changed:match.start('return')])
+                    if returns:
+                        self._check_nothing_after_return(source,
+                                                         match.end('return'))
+                        beg_idx = match.end('return')
+                        returned = _join_lines(
+                            source[beg_idx:len(source)].splitlines())
+                        last_changed = len(source)
+                    else:
+                        current = match.end('return')
+                        while current < len(source) and \
+                                source[current] in ' \t':
+                            current += 1
+                        last_changed = current
+                        if current == len(source) or source[current] == '\n':
+                            result.append('pass')
+        result.append(source[last_changed:])
+        return ''.join(result), returned
+
+    def _check_nothing_after_return(self, source, offset):
+        lines = codeanalyze.SourceLinesAdapter(source)
+        lineno = lines.get_line_number(offset)
+        logical_lines = codeanalyze.LogicalLineFinder(lines)
+        lineno = logical_lines.logical_line_in(lineno)[1]
+        if source[lines.get_line_end(lineno):len(source)].strip() != '':
+            raise rope.base.exceptions.RefactoringError(
+                'Cannot inline functions with statements ' +
+                'after return statement.')
+
+    @classmethod
+    def _get_return_pattern(cls):
+        if not hasattr(cls, '_return_pattern'):
+            def named_pattern(name, list_):
+                return "(?P<%s>" % name + "|".join(list_) + ")"
+            comment_pattern = named_pattern('comment', [r'#[^\n]*'])
+            string_pattern = named_pattern('string',
+                                           [codeanalyze.get_string_pattern()])
+            return_pattern = r'\b(?P<return>return)\b'
+            cls._return_pattern = re.compile(comment_pattern + "|" +
+                                             string_pattern + "|" +
+                                             return_pattern)
+        return cls._return_pattern
+
+
+class _InlineFunctionCallsForModuleHandle(object):
+
+    def __init__(self, project, resource,
+                 definition_generator, aim_offset=None):
+        """Inlines occurrences
+
+        If `aim` is not `None` only the occurrences that intersect
+        `aim` offset will be inlined.
+
+        """
+        self.project = project
+        self.generator = definition_generator
+        self.resource = resource
+        self.aim = aim_offset
+
+    def occurred_inside_skip(self, change_collector, occurrence):
+        if not occurrence.is_defined():
+            raise rope.base.exceptions.RefactoringError(
+                'Cannot inline functions that reference themselves')
+
+    def occurred_outside_skip(self, change_collector, occurrence):
+        start, end = occurrence.get_primary_range()
+        # we remove out of date imports later
+        if occurrence.is_in_import_statement():
+            return
+        # the function is referenced outside an import statement
+        if not occurrence.is_called():
+            raise rope.base.exceptions.RefactoringError(
+                'Reference to inlining function other than function call'
+                ' in <file: %s, offset: %d>' % (self.resource.path, start))
+        if self.aim is not None and (self.aim < start or self.aim > end):
+            return
+        end_parens = self._find_end_parens(self.source, end - 1)
+        lineno = self.lines.get_line_number(start)
+        start_line, end_line = self.pymodule.logical_lines.\
+            logical_line_in(lineno)
+        line_start = self.lines.get_line_start(start_line)
+        line_end = self.lines.get_line_end(end_line)
+
+        returns = self.source[line_start:start].strip() != '' or \
+            self.source[end_parens:line_end].strip() != ''
+        indents = sourceutils.get_indents(self.lines, start_line)
+        primary, pyname = occurrence.get_primary_and_pyname()
+
+        host = self.pymodule
+        scope = host.scope.get_inner_scope_for_line(lineno)
+        definition, returned = self.generator.get_definition(
+            primary, pyname, self.source[start:end_parens], scope.get_names(),
+            returns=returns)
+
+        end = min(line_end + 1, len(self.source))
+        change_collector.add_change(
+            line_start, end, sourceutils.fix_indentation(definition, indents))
+        if returns:
+            name = returned
+            if name is None:
+                name = 'None'
+            change_collector.add_change(
+                line_end, end, self.source[line_start:start] + name +
+                self.source[end_parens:end])
+
+    def _find_end_parens(self, source, offset):
+        finder = worder.Worder(source)
+        return finder.get_word_parens_range(offset)[1]
+
+    @property
+    @utils.saveit
+    def pymodule(self):
+        return self.project.get_pymodule(self.resource)
+
+    @property
+    @utils.saveit
+    def source(self):
+        if self.resource is not None:
+            return self.resource.read()
+        else:
+            return self.pymodule.source_code
+
+    @property
+    @utils.saveit
+    def lines(self):
+        return self.pymodule.lines
+
+
+def _inline_variable(project, pymodule, pyname, name,
+                     remove=True, region=None, docs=False):
+    definition = _getvardef(pymodule, pyname)
+    start, end = _assigned_lineno(pymodule, pyname)
+
+    occurrence_finder = occurrences.create_finder(project, name, pyname,
+                                                  docs=docs)
+    changed_source = rename.rename_in_module(
+        occurrence_finder, definition, pymodule=pymodule,
+        replace_primary=True, writes=False, region=region)
+    if changed_source is None:
+        changed_source = pymodule.source_code
+    if remove:
+        lines = codeanalyze.SourceLinesAdapter(changed_source)
+        source = changed_source[:lines.get_line_start(start)] + \
+            changed_source[lines.get_line_end(end) + 1:]
+    else:
+        source = changed_source
+    return source
+
+
+def _getvardef(pymodule, pyname):
+    assignment = pyname.assignments[0]
+    lines = pymodule.lines
+    start, end = _assigned_lineno(pymodule, pyname)
+    definition_with_assignment = _join_lines(
+        [lines.get_line(n) for n in range(start, end + 1)])
+    if assignment.levels:
+        raise rope.base.exceptions.RefactoringError(
+            'Cannot inline tuple assignments.')
+    definition = definition_with_assignment[definition_with_assignment.
+                                            index('=') + 1:].strip()
+    return definition
+
+
+def _assigned_lineno(pymodule, pyname):
+    definition_line = pyname.assignments[0].ast_node.lineno
+    return pymodule.logical_lines.logical_line_in(definition_line)
+
+
+def _add_imports(project, source, resource, imports):
+    if not imports:
+        return source
+    pymodule = libutils.get_string_module(project, source, resource)
+    module_import = importutils.get_module_imports(project, pymodule)
+    for import_info in imports:
+        module_import.add_import(import_info)
+    source = module_import.get_changed_source()
+    pymodule = libutils.get_string_module(project, source, resource)
+    import_tools = importutils.ImportTools(project)
+    return import_tools.organize_imports(pymodule, unused=False, sort=False)
+
+
+def _get_pyname(project, resource, offset):
+    pymodule = project.get_pymodule(resource)
+    pyname = evaluate.eval_location(pymodule, offset)
+    if isinstance(pyname, pynames.ImportedName):
+        pyname = pyname._get_imported_pyname()
+    return pyname
+
+
+def _remove_from(project, pyname, source, resource):
+    pymodule = libutils.get_string_module(project, source, resource)
+    module_import = importutils.get_module_imports(project, pymodule)
+    module_import.remove_pyname(pyname)
+    return module_import.get_changed_source()
diff --git a/venv/Lib/site-packages/rope/refactor/introduce_factory.py b/venv/Lib/site-packages/rope/refactor/introduce_factory.py
new file mode 100644
index 0000000000000000000000000000000000000000..7532e361a808543b65c0bb9768964901ff90e15b
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/introduce_factory.py
@@ -0,0 +1,135 @@
+import rope.base.exceptions
+import rope.base.pyobjects
+from rope.base import libutils
+from rope.base import taskhandle, evaluate
+from rope.base.change import (ChangeSet, ChangeContents)
+from rope.refactor import rename, occurrences, sourceutils, importutils
+
+
+class IntroduceFactory(object):
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        self.offset = offset
+
+        this_pymodule = self.project.get_pymodule(resource)
+        self.old_pyname = evaluate.eval_location(this_pymodule, offset)
+        if self.old_pyname is None or \
+                not isinstance(self.old_pyname.get_object(),
+                               rope.base.pyobjects.PyClass):
+            raise rope.base.exceptions.RefactoringError(
+                'Introduce factory should be performed on a class.')
+        self.old_name = self.old_pyname.get_object().get_name()
+        self.pymodule = self.old_pyname.get_object().get_module()
+        self.resource = self.pymodule.get_resource()
+
+    def get_changes(self, factory_name, global_factory=False, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        """Get the changes this refactoring makes
+
+        `factory_name` indicates the name of the factory function to
+        be added.  If `global_factory` is `True` the factory will be
+        global otherwise a static method is added to the class.
+
+        `resources` can be a list of `rope.base.resource.File`\s that
+        this refactoring should be applied on; if `None` all python
+        files in the project are searched.
+
+        """
+        if resources is None:
+            resources = self.project.get_python_files()
+        changes = ChangeSet('Introduce factory method <%s>' % factory_name)
+        job_set = task_handle.create_jobset('Collecting Changes',
+                                            len(resources))
+        self._change_module(resources, changes, factory_name,
+                            global_factory, job_set)
+        return changes
+
+    def get_name(self):
+        """Return the name of the class"""
+        return self.old_name
+
+    def _change_module(self, resources, changes,
+                       factory_name, global_, job_set):
+        if global_:
+            replacement = '__rope_factory_%s_' % factory_name
+        else:
+            replacement = self._new_function_name(factory_name, global_)
+
+        for file_ in resources:
+            job_set.started_job(file_.path)
+            if file_ == self.resource:
+                self._change_resource(changes, factory_name, global_)
+                job_set.finished_job()
+                continue
+            changed_code = self._rename_occurrences(file_, replacement,
+                                                    global_)
+            if changed_code is not None:
+                if global_:
+                    new_pymodule = libutils.get_string_module(
+                        self.project, changed_code, self.resource)
+                    modname = libutils.modname(self.resource)
+                    changed_code, imported = importutils.add_import(
+                        self.project, new_pymodule, modname, factory_name)
+                    changed_code = changed_code.replace(replacement, imported)
+                changes.add_change(ChangeContents(file_, changed_code))
+            job_set.finished_job()
+
+    def _change_resource(self, changes, factory_name, global_):
+        class_scope = self.old_pyname.get_object().get_scope()
+        source_code = self._rename_occurrences(
+            self.resource, self._new_function_name(factory_name,
+                                                   global_), global_)
+        if source_code is None:
+            source_code = self.pymodule.source_code
+        else:
+            self.pymodule = libutils.get_string_module(
+                self.project, source_code, resource=self.resource)
+        lines = self.pymodule.lines
+        start = self._get_insertion_offset(class_scope, lines)
+        result = source_code[:start]
+        result += self._get_factory_method(lines, class_scope,
+                                           factory_name, global_)
+        result += source_code[start:]
+        changes.add_change(ChangeContents(self.resource, result))
+
+    def _get_insertion_offset(self, class_scope, lines):
+        start_line = class_scope.get_end()
+        if class_scope.get_scopes():
+            start_line = class_scope.get_scopes()[-1].get_end()
+        start = lines.get_line_end(start_line) + 1
+        return start
+
+    def _get_factory_method(self, lines, class_scope,
+                            factory_name, global_):
+        unit_indents = ' ' * sourceutils.get_indent(self.project)
+        if global_:
+            if self._get_scope_indents(lines, class_scope) > 0:
+                raise rope.base.exceptions.RefactoringError(
+                    'Cannot make global factory method for nested classes.')
+            return ('\ndef %s(*args, **kwds):\n%sreturn %s(*args, **kwds)\n' %
+                    (factory_name, unit_indents, self.old_name))
+        unindented_factory = \
+            ('@staticmethod\ndef %s(*args, **kwds):\n' % factory_name +
+             '%sreturn %s(*args, **kwds)\n' % (unit_indents, self.old_name))
+        indents = self._get_scope_indents(lines, class_scope) + \
+            sourceutils.get_indent(self.project)
+        return '\n' + sourceutils.indent_lines(unindented_factory, indents)
+
+    def _get_scope_indents(self, lines, scope):
+        return sourceutils.get_indents(lines, scope.get_start())
+
+    def _new_function_name(self, factory_name, global_):
+        if global_:
+            return factory_name
+        else:
+            return self.old_name + '.' + factory_name
+
+    def _rename_occurrences(self, file_, changed_name, global_factory):
+        finder = occurrences.create_finder(self.project, self.old_name,
+                                           self.old_pyname, only_calls=True)
+        result = rename.rename_in_module(finder, changed_name, resource=file_,
+                                         replace_primary=global_factory)
+        return result
+
+IntroduceFactoryRefactoring = IntroduceFactory
diff --git a/venv/Lib/site-packages/rope/refactor/introduce_parameter.py b/venv/Lib/site-packages/rope/refactor/introduce_parameter.py
new file mode 100644
index 0000000000000000000000000000000000000000..43d6f755b1170bf720e0a5d4558a1810278f29cd
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/introduce_parameter.py
@@ -0,0 +1,96 @@
+import rope.base.change
+from rope.base import exceptions, evaluate, worder, codeanalyze
+from rope.refactor import functionutils, sourceutils, occurrences
+
+
+class IntroduceParameter(object):
+    """Introduce parameter refactoring
+
+    This refactoring adds a new parameter to a function and replaces
+    references to an expression in it with the new parameter.
+
+    The parameter finding part is different from finding similar
+    pieces in extract refactorings.  In this refactoring parameters
+    are found based on the object they reference to.  For instance
+    in::
+
+      class A(object):
+          var = None
+
+      class B(object):
+          a = A()
+
+      b = B()
+      a = b.a
+
+      def f(a):
+          x = b.a.var + a.var
+
+    using this refactoring on ``a.var`` with ``p`` as the new
+    parameter name, will result in::
+
+      def f(p=a.var):
+          x = p + p
+
+    """
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        self.resource = resource
+        self.offset = offset
+        self.pymodule = self.project.get_pymodule(self.resource)
+        scope = self.pymodule.get_scope().get_inner_scope_for_offset(offset)
+        if scope.get_kind() != 'Function':
+            raise exceptions.RefactoringError(
+                'Introduce parameter should be performed inside functions')
+        self.pyfunction = scope.pyobject
+        self.name, self.pyname = self._get_name_and_pyname()
+        if self.pyname is None:
+            raise exceptions.RefactoringError(
+                'Cannot find the definition of <%s>' % self.name)
+
+    def _get_primary(self):
+        word_finder = worder.Worder(self.resource.read())
+        return word_finder.get_primary_at(self.offset)
+
+    def _get_name_and_pyname(self):
+        return (worder.get_name_at(self.resource, self.offset),
+                evaluate.eval_location(self.pymodule, self.offset))
+
+    def get_changes(self, new_parameter):
+        definition_info = functionutils.DefinitionInfo.read(self.pyfunction)
+        definition_info.args_with_defaults.append((new_parameter,
+                                                   self._get_primary()))
+        collector = codeanalyze.ChangeCollector(self.resource.read())
+        header_start, header_end = self._get_header_offsets()
+        body_start, body_end = sourceutils.get_body_region(self.pyfunction)
+        collector.add_change(header_start, header_end,
+                             definition_info.to_string())
+        self._change_function_occurances(collector, body_start,
+                                         body_end, new_parameter)
+        changes = rope.base.change.ChangeSet('Introduce parameter <%s>' %
+                                             new_parameter)
+        change = rope.base.change.ChangeContents(self.resource,
+                                                 collector.get_changed())
+        changes.add_change(change)
+        return changes
+
+    def _get_header_offsets(self):
+        lines = self.pymodule.lines
+        start_line = self.pyfunction.get_scope().get_start()
+        end_line = self.pymodule.logical_lines.\
+            logical_line_in(start_line)[1]
+        start = lines.get_line_start(start_line)
+        end = lines.get_line_end(end_line)
+        start = self.pymodule.source_code.find('def', start) + 4
+        end = self.pymodule.source_code.rfind(':', start, end)
+        return start, end
+
+    def _change_function_occurances(self, collector, function_start,
+                                    function_end, new_name):
+        finder = occurrences.create_finder(self.project, self.name,
+                                           self.pyname)
+        for occurrence in finder.find_occurrences(resource=self.resource):
+            start, end = occurrence.get_primary_range()
+            if function_start <= start < function_end:
+                collector.add_change(start, end, new_name)
diff --git a/venv/Lib/site-packages/rope/refactor/localtofield.py b/venv/Lib/site-packages/rope/refactor/localtofield.py
new file mode 100644
index 0000000000000000000000000000000000000000..f276070f71fab99a7efadeed8e91c2437c201328
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/localtofield.py
@@ -0,0 +1,49 @@
+from rope.base import pynames, evaluate, exceptions, worder
+from rope.refactor.rename import Rename
+
+
+class LocalToField(object):
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        self.resource = resource
+        self.offset = offset
+
+    def get_changes(self):
+        name = worder.get_name_at(self.resource, self.offset)
+        this_pymodule = self.project.get_pymodule(self.resource)
+        pyname = evaluate.eval_location(this_pymodule, self.offset)
+        if not self._is_a_method_local(pyname):
+            raise exceptions.RefactoringError(
+                'Convert local variable to field should be performed on \n'
+                'a local variable of a method.')
+
+        pymodule, lineno = pyname.get_definition_location()
+        function_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+        # Not checking redefinition
+        #self._check_redefinition(name, function_scope)
+
+        new_name = self._get_field_name(function_scope.pyobject, name)
+        changes = Rename(self.project, self.resource, self.offset).\
+            get_changes(new_name, resources=[self.resource])
+        return changes
+
+    def _check_redefinition(self, name, function_scope):
+        class_scope = function_scope.parent
+        if name in class_scope.pyobject:
+            raise exceptions.RefactoringError(
+                'The field %s already exists' % name)
+
+    def _get_field_name(self, pyfunction, name):
+        self_name = pyfunction.get_param_names()[0]
+        new_name = self_name + '.' + name
+        return new_name
+
+    def _is_a_method_local(self, pyname):
+        pymodule, lineno = pyname.get_definition_location()
+        holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+        parent = holding_scope.parent
+        return isinstance(pyname, pynames.AssignedName) and \
+            pyname in holding_scope.get_names().values() and \
+            holding_scope.get_kind() == 'Function' and \
+            parent is not None and parent.get_kind() == 'Class'
diff --git a/venv/Lib/site-packages/rope/refactor/method_object.py b/venv/Lib/site-packages/rope/refactor/method_object.py
new file mode 100644
index 0000000000000000000000000000000000000000..29ce429db6115a389cda2b8adf6b7e0d194324f0
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/method_object.py
@@ -0,0 +1,90 @@
+import warnings
+
+from rope.base import libutils
+from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze
+from rope.refactor import sourceutils, occurrences, rename
+
+
+class MethodObject(object):
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        this_pymodule = self.project.get_pymodule(resource)
+        pyname = evaluate.eval_location(this_pymodule, offset)
+        if pyname is None or not isinstance(pyname.get_object(),
+                                            pyobjects.PyFunction):
+            raise exceptions.RefactoringError(
+                'Replace method with method object refactoring should be '
+                'performed on a function.')
+        self.pyfunction = pyname.get_object()
+        self.pymodule = self.pyfunction.get_module()
+        self.resource = self.pymodule.get_resource()
+
+    def get_new_class(self, name):
+        body = sourceutils.fix_indentation(
+            self._get_body(), sourceutils.get_indent(self.project) * 2)
+        return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \
+               (name, self._get_init(),
+                ' ' * sourceutils.get_indent(self.project), body)
+
+    def get_changes(self, classname=None, new_class_name=None):
+        if new_class_name is not None:
+            warnings.warn(
+                'new_class_name parameter is deprecated; use classname',
+                DeprecationWarning, stacklevel=2)
+            classname = new_class_name
+        collector = codeanalyze.ChangeCollector(self.pymodule.source_code)
+        start, end = sourceutils.get_body_region(self.pyfunction)
+        indents = sourceutils.get_indents(
+            self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \
+            sourceutils.get_indent(self.project)
+        new_contents = ' ' * indents + 'return %s(%s)()\n' % \
+                       (classname, ', '.join(self._get_parameter_names()))
+        collector.add_change(start, end, new_contents)
+        insertion = self._get_class_insertion_point()
+        collector.add_change(insertion, insertion,
+                             '\n\n' + self.get_new_class(classname))
+        changes = change.ChangeSet(
+            'Replace method with method object refactoring')
+        changes.add_change(change.ChangeContents(self.resource,
+                                                 collector.get_changed()))
+        return changes
+
+    def _get_class_insertion_point(self):
+        current = self.pyfunction
+        while current.parent != self.pymodule:
+            current = current.parent
+        end = self.pymodule.lines.get_line_end(current.get_scope().get_end())
+        return min(end + 1, len(self.pymodule.source_code))
+
+    def _get_body(self):
+        body = sourceutils.get_body(self.pyfunction)
+        for param in self._get_parameter_names():
+            body = param + ' = None\n' + body
+            pymod = libutils.get_string_module(
+                self.project, body, self.resource)
+            pyname = pymod[param]
+            finder = occurrences.create_finder(self.project, param, pyname)
+            result = rename.rename_in_module(finder, 'self.' + param,
+                                             pymodule=pymod)
+            body = result[result.index('\n') + 1:]
+        return body
+
+    def _get_init(self):
+        params = self._get_parameter_names()
+        indents = ' ' * sourceutils.get_indent(self.project)
+        if not params:
+            return ''
+        header = indents + 'def __init__(self'
+        body = ''
+        for arg in params:
+            new_name = arg
+            if arg == 'self':
+                new_name = 'host'
+            header += ', %s' % new_name
+            body += indents * 2 + 'self.%s = %s\n' % (arg, new_name)
+        header += '):'
+        return '%s\n%s\n' % (header, body)
+
+    def _get_parameter_names(self):
+        return self.pyfunction.get_param_names()
diff --git a/venv/Lib/site-packages/rope/refactor/move.py b/venv/Lib/site-packages/rope/refactor/move.py
new file mode 100644
index 0000000000000000000000000000000000000000..ce618277e52ca594558b0b6f876f676b57eba7b8
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/move.py
@@ -0,0 +1,784 @@
+"""A module containing classes for move refactoring
+
+`create_move()` is a factory for creating move refactoring objects
+based on inputs.
+
+"""
+from rope.base import (pyobjects, codeanalyze, exceptions, pynames,
+                       taskhandle, evaluate, worder, libutils)
+from rope.base.change import ChangeSet, ChangeContents, MoveResource
+from rope.refactor import importutils, rename, occurrences, sourceutils, \
+    functionutils
+
+
+def create_move(project, resource, offset=None):
+    """A factory for creating Move objects
+
+    Based on `resource` and `offset`, return one of `MoveModule`,
+    `MoveGlobal` or `MoveMethod` for performing move refactoring.
+
+    """
+    if offset is None:
+        return MoveModule(project, resource)
+    this_pymodule = project.get_pymodule(resource)
+    pyname = evaluate.eval_location(this_pymodule, offset)
+    if pyname is not None:
+        pyobject = pyname.get_object()
+        if isinstance(pyobject, pyobjects.PyModule) or \
+           isinstance(pyobject, pyobjects.PyPackage):
+            return MoveModule(project, pyobject.get_resource())
+        if isinstance(pyobject, pyobjects.PyFunction) and \
+           isinstance(pyobject.parent, pyobjects.PyClass):
+            return MoveMethod(project, resource, offset)
+        if isinstance(pyobject, pyobjects.PyDefinedObject) and \
+           isinstance(pyobject.parent, pyobjects.PyModule) or \
+           isinstance(pyname, pynames.AssignedName):
+            return MoveGlobal(project, resource, offset)
+    raise exceptions.RefactoringError(
+        'Move only works on global classes/functions/variables, modules and '
+        'methods.')
+
+
+class MoveMethod(object):
+    """For moving methods
+
+    It makes a new method in the destination class and changes
+    the body of the old method to call the new method.  You can
+    inline the old method to change all of its occurrences.
+
+    """
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        this_pymodule = self.project.get_pymodule(resource)
+        pyname = evaluate.eval_location(this_pymodule, offset)
+        self.method_name = worder.get_name_at(resource, offset)
+        self.pyfunction = pyname.get_object()
+        if self.pyfunction.get_kind() != 'method':
+            raise exceptions.RefactoringError('Only normal methods'
+                                              ' can be moved.')
+
+    def get_changes(self, dest_attr, new_name=None, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        """Return the changes needed for this refactoring
+
+        Parameters:
+
+        - `dest_attr`: the name of the destination attribute
+        - `new_name`: the name of the new method; if `None` uses
+          the old name
+        - `resources` can be a list of `rope.base.resources.File`\s to
+          apply this refactoring on.  If `None`, the restructuring
+          will be applied to all python files.
+
+        """
+        changes = ChangeSet('Moving method <%s>' % self.method_name)
+        if resources is None:
+            resources = self.project.get_python_files()
+        if new_name is None:
+            new_name = self.get_method_name()
+        resource1, start1, end1, new_content1 = \
+            self._get_changes_made_by_old_class(dest_attr, new_name)
+        collector1 = codeanalyze.ChangeCollector(resource1.read())
+        collector1.add_change(start1, end1, new_content1)
+
+        resource2, start2, end2, new_content2 = \
+            self._get_changes_made_by_new_class(dest_attr, new_name)
+        if resource1 == resource2:
+            collector1.add_change(start2, end2, new_content2)
+        else:
+            collector2 = codeanalyze.ChangeCollector(resource2.read())
+            collector2.add_change(start2, end2, new_content2)
+            result = collector2.get_changed()
+            import_tools = importutils.ImportTools(self.project)
+            new_imports = self._get_used_imports(import_tools)
+            if new_imports:
+                goal_pymodule = libutils.get_string_module(
+                    self.project, result, resource2)
+                result = _add_imports_to_module(
+                    import_tools, goal_pymodule, new_imports)
+            if resource2 in resources:
+                changes.add_change(ChangeContents(resource2, result))
+
+        if resource1 in resources:
+            changes.add_change(ChangeContents(resource1,
+                                              collector1.get_changed()))
+        return changes
+
+    def get_method_name(self):
+        return self.method_name
+
+    def _get_used_imports(self, import_tools):
+        return importutils.get_imports(self.project, self.pyfunction)
+
+    def _get_changes_made_by_old_class(self, dest_attr, new_name):
+        pymodule = self.pyfunction.get_module()
+        indents = self._get_scope_indents(self.pyfunction)
+        body = 'return self.%s.%s(%s)\n' % (
+            dest_attr, new_name, self._get_passed_arguments_string())
+        region = sourceutils.get_body_region(self.pyfunction)
+        return (pymodule.get_resource(), region[0], region[1],
+                sourceutils.fix_indentation(body, indents))
+
+    def _get_scope_indents(self, pyobject):
+        pymodule = pyobject.get_module()
+        return sourceutils.get_indents(
+            pymodule.lines, pyobject.get_scope().get_start()) + \
+            sourceutils.get_indent(self.project)
+
+    def _get_changes_made_by_new_class(self, dest_attr, new_name):
+        old_pyclass = self.pyfunction.parent
+        if dest_attr not in old_pyclass:
+            raise exceptions.RefactoringError(
+                'Destination attribute <%s> not found' % dest_attr)
+        pyclass = old_pyclass[dest_attr].get_object().get_type()
+        if not isinstance(pyclass, pyobjects.PyClass):
+            raise exceptions.RefactoringError(
+                'Unknown class type for attribute <%s>' % dest_attr)
+        pymodule = pyclass.get_module()
+        resource = pyclass.get_module().get_resource()
+        start, end = sourceutils.get_body_region(pyclass)
+        pre_blanks = '\n'
+        if pymodule.source_code[start:end].strip() != 'pass':
+            pre_blanks = '\n\n'
+            start = end
+        indents = self._get_scope_indents(pyclass)
+        body = pre_blanks + sourceutils.fix_indentation(
+            self.get_new_method(new_name), indents)
+        return resource, start, end, body
+
+    def get_new_method(self, name):
+        return '%s\n%s' % (
+            self._get_new_header(name),
+            sourceutils.fix_indentation(self._get_body(),
+                                        sourceutils.get_indent(self.project)))
+
+    def _get_unchanged_body(self):
+        return sourceutils.get_body(self.pyfunction)
+
+    def _get_body(self, host='host'):
+        self_name = self._get_self_name()
+        body = self_name + ' = None\n' + self._get_unchanged_body()
+        pymodule = libutils.get_string_module(self.project, body)
+        finder = occurrences.create_finder(
+            self.project, self_name, pymodule[self_name])
+        result = rename.rename_in_module(finder, host, pymodule=pymodule)
+        if result is None:
+            result = body
+        return result[result.index('\n') + 1:]
+
+    def _get_self_name(self):
+        return self.pyfunction.get_param_names()[0]
+
+    def _get_new_header(self, name):
+        header = 'def %s(self' % name
+        if self._is_host_used():
+            header += ', host'
+        definition_info = functionutils.DefinitionInfo.read(self.pyfunction)
+        others = definition_info.arguments_to_string(1)
+        if others:
+            header += ', ' + others
+        return header + '):'
+
+    def _get_passed_arguments_string(self):
+        result = ''
+        if self._is_host_used():
+            result = 'self'
+        definition_info = functionutils.DefinitionInfo.read(self.pyfunction)
+        others = definition_info.arguments_to_string(1)
+        if others:
+            if result:
+                result += ', '
+            result += others
+        return result
+
+    def _is_host_used(self):
+        return self._get_body('__old_self') != self._get_unchanged_body()
+
+
+class MoveGlobal(object):
+    """For moving global function and classes"""
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        this_pymodule = self.project.get_pymodule(resource)
+        self.old_pyname = evaluate.eval_location(this_pymodule, offset)
+        if self.old_pyname is None:
+            raise exceptions.RefactoringError(
+                'Move refactoring should be performed on a '
+                'class/function/variable.')
+        if self._is_variable(self.old_pyname):
+            self.old_name = worder.get_name_at(resource, offset)
+            pymodule = this_pymodule
+        else:
+            self.old_name = self.old_pyname.get_object().get_name()
+            pymodule = self.old_pyname.get_object().get_module()
+        self._check_exceptional_conditions()
+        self.source = pymodule.get_resource()
+        self.tools = _MoveTools(self.project, self.source,
+                                self.old_pyname, self.old_name)
+        self.import_tools = self.tools.import_tools
+
+    def _import_filter(self, stmt):
+      module_name = libutils.modname(self.source)
+
+      if isinstance(stmt.import_info, importutils.NormalImport):
+          # Affect any statement that imports the source module
+          return any(module_name == name
+                     for name, alias in stmt.import_info.names_and_aliases)
+      elif isinstance(stmt.import_info, importutils.FromImport):
+          # Affect statements importing from the source package
+          if '.' in module_name:
+              package_name, basename = module_name.rsplit('.', 1)
+              if (stmt.import_info.module_name == package_name and
+                  any(basename == name
+                      for name, alias in stmt.import_info.names_and_aliases)):
+                  return True
+          return stmt.import_info.module_name == module_name
+      return False
+
+    def _check_exceptional_conditions(self):
+        if self._is_variable(self.old_pyname):
+            pymodule = self.old_pyname.get_definition_location()[0]
+            try:
+                pymodule.get_scope().get_name(self.old_name)
+            except exceptions.NameNotFoundError:
+                self._raise_refactoring_error()
+        elif not (isinstance(self.old_pyname.get_object(),
+                             pyobjects.PyDefinedObject) and
+                  self._is_global(self.old_pyname.get_object())):
+            self._raise_refactoring_error()
+
+    def _raise_refactoring_error(self):
+        raise exceptions.RefactoringError(
+            'Move refactoring should be performed on a global class, function '
+            'or variable.')
+
+    def _is_global(self, pyobject):
+        return pyobject.get_scope().parent == pyobject.get_module().get_scope()
+
+    def _is_variable(self, pyname):
+      return isinstance(pyname, pynames.AssignedName)
+
+    def get_changes(self, dest, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        if resources is None:
+            resources = self.project.get_python_files()
+        if dest is None or not dest.exists():
+            raise exceptions.RefactoringError(
+                'Move destination does not exist.')
+        if dest.is_folder() and dest.has_child('__init__.py'):
+            dest = dest.get_child('__init__.py')
+        if dest.is_folder():
+            raise exceptions.RefactoringError(
+                'Move destination for non-modules should not be folders.')
+        if self.source == dest:
+            raise exceptions.RefactoringError(
+                'Moving global elements to the same module.')
+        return self._calculate_changes(dest, resources, task_handle)
+
+    def _calculate_changes(self, dest, resources, task_handle):
+        changes = ChangeSet('Moving global <%s>' % self.old_name)
+        job_set = task_handle.create_jobset('Collecting Changes',
+                                            len(resources))
+        for file_ in resources:
+            job_set.started_job(file_.path)
+            if file_ == self.source:
+                changes.add_change(self._source_module_changes(dest))
+            elif file_ == dest:
+                changes.add_change(self._dest_module_changes(dest))
+            elif self.tools.occurs_in_module(resource=file_):
+                pymodule = self.project.get_pymodule(file_)
+                # Changing occurrences
+                placeholder = '__rope_renaming_%s_' % self.old_name
+                source = self.tools.rename_in_module(placeholder,
+                                                     resource=file_)
+                should_import = source is not None
+                # Removing out of date imports
+                pymodule = self.tools.new_pymodule(pymodule, source)
+                source = self.import_tools.organize_imports(
+                    pymodule, sort=False, import_filter=self._import_filter)
+                # Adding new import
+                if should_import:
+                    pymodule = self.tools.new_pymodule(pymodule, source)
+                    source, imported = importutils.add_import(
+                        self.project, pymodule, self._new_modname(dest),
+                        self.old_name)
+                    source = source.replace(placeholder, imported)
+                source = self.tools.new_source(pymodule, source)
+                if source != file_.read():
+                    changes.add_change(ChangeContents(file_, source))
+            job_set.finished_job()
+        return changes
+
+    def _source_module_changes(self, dest):
+        placeholder = '__rope_moving_%s_' % self.old_name
+        handle = _ChangeMoveOccurrencesHandle(placeholder)
+        occurrence_finder = occurrences.create_finder(
+            self.project, self.old_name, self.old_pyname)
+        start, end = self._get_moving_region()
+        renamer = ModuleSkipRenamer(occurrence_finder, self.source,
+                                    handle, start, end)
+        source = renamer.get_changed_module()
+        pymodule = libutils.get_string_module(self.project, source, self.source)
+        source = self.import_tools.organize_imports(pymodule, sort=False)
+        if handle.occurred:
+            pymodule = libutils.get_string_module(
+                self.project, source, self.source)
+            # Adding new import
+            source, imported = importutils.add_import(
+                self.project, pymodule, self._new_modname(dest), self.old_name)
+            source = source.replace(placeholder, imported)
+        return ChangeContents(self.source, source)
+
+    def _new_modname(self, dest):
+        return libutils.modname(dest)
+
+    def _dest_module_changes(self, dest):
+        # Changing occurrences
+        pymodule = self.project.get_pymodule(dest)
+        source = self.tools.rename_in_module(self.old_name, pymodule)
+        pymodule = self.tools.new_pymodule(pymodule, source)
+
+        moving, imports = self._get_moving_element_with_imports()
+        pymodule, has_changed = self._add_imports2(pymodule, imports)
+
+        module_with_imports = self.import_tools.module_imports(pymodule)
+        source = pymodule.source_code
+        lineno = 0
+        if module_with_imports.imports:
+            lineno = module_with_imports.imports[-1].end_line - 1
+        else:
+            while lineno < pymodule.lines.length() and \
+                    pymodule.lines.get_line(lineno + 1).\
+                    lstrip().startswith('#'):
+                lineno += 1
+        if lineno > 0:
+            cut = pymodule.lines.get_line_end(lineno) + 1
+            result = source[:cut] + '\n\n' + moving + source[cut:]
+        else:
+            result = moving + source
+
+        # Organizing imports
+        source = result
+        pymodule = libutils.get_string_module(self.project, source, dest)
+        source = self.import_tools.organize_imports(pymodule, sort=False,
+                                                    unused=False)
+        # Remove unused imports of the old module
+        pymodule = libutils.get_string_module(self.project, source, dest)
+        source = self.import_tools.organize_imports(
+            pymodule, sort=False, selfs=False, unused=True,
+            import_filter=self._import_filter)
+        return ChangeContents(dest, source)
+
+    def _get_moving_element_with_imports(self):
+        return moving_code_with_imports(
+            self.project, self.source, self._get_moving_element())
+
+    def _get_module_with_imports(self, source_code, resource):
+        pymodule = libutils.get_string_module(
+            self.project, source_code, resource)
+        return self.import_tools.module_imports(pymodule)
+
+    def _get_moving_element(self):
+        start, end = self._get_moving_region()
+        moving = self.source.read()[start:end]
+        return moving.rstrip() + '\n'
+
+    def _get_moving_region(self):
+        pymodule = self.project.get_pymodule(self.source)
+        lines = pymodule.lines
+        if self._is_variable(self.old_pyname):
+            logical_lines = pymodule.logical_lines
+            lineno = logical_lines.logical_line_in(
+                self.old_pyname.get_definition_location()[1])[0]
+            start = lines.get_line_start(lineno)
+            end_line = logical_lines.logical_line_in(lineno)[1]
+        else:
+            scope = self.old_pyname.get_object().get_scope()
+            start = lines.get_line_start(scope.get_start())
+            end_line = scope.get_end()
+
+        # Include comment lines before the definition
+        start_line = lines.get_line_number(start)
+        while start_line > 1 and lines.get_line(start_line - 1).startswith('#'):
+          start_line -= 1
+        start = lines.get_line_start(start_line)
+
+        while end_line < lines.length() and \
+                lines.get_line(end_line + 1).strip() == '':
+            end_line += 1
+        end = min(lines.get_line_end(end_line) + 1, len(pymodule.source_code))
+        return start, end
+
+    def _add_imports2(self, pymodule, new_imports):
+        source = self.tools.add_imports(pymodule, new_imports)
+        if source is None:
+            return pymodule, False
+        else:
+            resource = pymodule.get_resource()
+            pymodule = libutils.get_string_module(
+                self.project, source, resource)
+            return pymodule, True
+
+
+class MoveModule(object):
+    """For moving modules and packages"""
+
+    def __init__(self, project, resource):
+        self.project = project
+        if not resource.is_folder() and resource.name == '__init__.py':
+            resource = resource.parent
+        if resource.is_folder() and not resource.has_child('__init__.py'):
+            raise exceptions.RefactoringError(
+                'Cannot move non-package folder.')
+        dummy_pymodule = libutils.get_string_module(self.project, '')
+        self.old_pyname = pynames.ImportedModule(dummy_pymodule,
+                                                 resource=resource)
+        self.source = self.old_pyname.get_object().get_resource()
+        if self.source.is_folder():
+            self.old_name = self.source.name
+        else:
+            self.old_name = self.source.name[:-3]
+        self.tools = _MoveTools(self.project, self.source,
+                                self.old_pyname, self.old_name)
+        self.import_tools = self.tools.import_tools
+
+    def get_changes(self, dest, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        if resources is None:
+            resources = self.project.get_python_files()
+        if dest is None or not dest.is_folder():
+            raise exceptions.RefactoringError(
+                'Move destination for modules should be packages.')
+        return self._calculate_changes(dest, resources, task_handle)
+
+    def _calculate_changes(self, dest, resources, task_handle):
+        changes = ChangeSet('Moving module <%s>' % self.old_name)
+        job_set = task_handle.create_jobset('Collecting changes',
+                                            len(resources))
+        for module in resources:
+            job_set.started_job(module.path)
+            if module == self.source:
+                self._change_moving_module(changes, dest)
+            else:
+                source = self._change_occurrences_in_module(dest,
+                                                            resource=module)
+                if source is not None:
+                    changes.add_change(ChangeContents(module, source))
+            job_set.finished_job()
+        if self.project == self.source.project:
+            changes.add_change(MoveResource(self.source, dest.path))
+        return changes
+
+    def _new_modname(self, dest):
+        destname = libutils.modname(dest)
+        if destname:
+            return destname + '.' + self.old_name
+        return self.old_name
+
+    def _new_import(self, dest):
+        return importutils.NormalImport([(self._new_modname(dest), None)])
+
+    def _change_moving_module(self, changes, dest):
+        if not self.source.is_folder():
+            pymodule = self.project.get_pymodule(self.source)
+            source = self.import_tools.relatives_to_absolutes(pymodule)
+            pymodule = self.tools.new_pymodule(pymodule, source)
+            source = self._change_occurrences_in_module(dest, pymodule)
+            source = self.tools.new_source(pymodule, source)
+            if source != self.source.read():
+                changes.add_change(ChangeContents(self.source, source))
+
+    def _change_occurrences_in_module(self, dest, pymodule=None,
+                                      resource=None):
+        if not self.tools.occurs_in_module(pymodule=pymodule,
+                                           resource=resource):
+            return
+        if pymodule is None:
+            pymodule = self.project.get_pymodule(resource)
+        new_name = self._new_modname(dest)
+        module_imports = importutils.get_module_imports(self.project, pymodule)
+        changed = False
+        source = None
+        if libutils.modname(dest):
+            changed = self._change_import_statements(dest, new_name,
+                                                     module_imports)
+            if changed:
+                source = module_imports.get_changed_source()
+                source = self.tools.new_source(pymodule, source)
+                pymodule = self.tools.new_pymodule(pymodule, source)
+
+        new_import = self._new_import(dest)
+        source = self.tools.rename_in_module(
+            new_name, imports=True, pymodule=pymodule,
+            resource=resource if not changed else None)
+        should_import = self.tools.occurs_in_module(
+            pymodule=pymodule, resource=resource, imports=False)
+        pymodule = self.tools.new_pymodule(pymodule, source)
+        source = self.tools.remove_old_imports(pymodule)
+        if should_import:
+            pymodule = self.tools.new_pymodule(pymodule, source)
+            source = self.tools.add_imports(pymodule, [new_import])
+        source = self.tools.new_source(pymodule, source)
+        if source is not None and source != pymodule.resource.read():
+            return source
+        return None
+
+    def _change_import_statements(self, dest, new_name, module_imports):
+        moving_module = self.source
+        parent_module = moving_module.parent
+
+        changed = False
+        for import_stmt in module_imports.imports:
+            if not any(name_and_alias[0] == self.old_name
+                       for name_and_alias in
+                       import_stmt.import_info.names_and_aliases) and \
+               not any(name_and_alias[0] == libutils.modname(self.source)
+                       for name_and_alias in
+                       import_stmt.import_info.names_and_aliases):
+                continue
+
+            # Case 1: Look for normal imports of the moving module.
+            if isinstance(import_stmt.import_info, importutils.NormalImport):
+                continue
+
+            # Case 2: The moving module is from-imported.
+            changed = self._handle_moving_in_from_import_stmt(
+                dest, import_stmt, module_imports, parent_module) or changed
+
+            # Case 3: Names are imported from the moving module.
+            context = importutils.importinfo.ImportContext(self.project, None)
+            if not import_stmt.import_info.is_empty() and \
+               import_stmt.import_info.get_imported_resource(context) == \
+                    moving_module:
+                import_stmt.import_info = importutils.FromImport(
+                    new_name, import_stmt.import_info.level,
+                    import_stmt.import_info.names_and_aliases)
+                changed = True
+
+        return changed
+
+    def _handle_moving_in_from_import_stmt(self, dest, import_stmt,
+                                           module_imports, parent_module):
+        changed = False
+        context = importutils.importinfo.ImportContext(self.project, None)
+        if import_stmt.import_info.get_imported_resource(context) == \
+                parent_module:
+            imports = import_stmt.import_info.names_and_aliases
+            new_imports = []
+            for name, alias in imports:
+                # The moving module was imported.
+                if name == self.old_name:
+                    changed = True
+                    new_import = importutils.FromImport(
+                        libutils.modname(dest), 0,
+                        [(self.old_name, alias)])
+                    module_imports.add_import(new_import)
+                else:
+                    new_imports.append((name, alias))
+
+            # Update the imports if the imported names were changed.
+            if new_imports != imports:
+                changed = True
+                if new_imports:
+                    import_stmt.import_info = importutils.FromImport(
+                        import_stmt.import_info.module_name,
+                        import_stmt.import_info.level,
+                        new_imports)
+                else:
+                    import_stmt.empty_import()
+        return changed
+
+
+class _ChangeMoveOccurrencesHandle(object):
+
+    def __init__(self, new_name):
+        self.new_name = new_name
+        self.occurred = False
+
+    def occurred_inside_skip(self, change_collector, occurrence):
+        pass
+
+    def occurred_outside_skip(self, change_collector, occurrence):
+        start, end = occurrence.get_primary_range()
+        change_collector.add_change(start, end, self.new_name)
+        self.occurred = True
+
+
+class _MoveTools(object):
+
+    def __init__(self, project, source, pyname, old_name):
+        self.project = project
+        self.source = source
+        self.old_pyname = pyname
+        self.old_name = old_name
+        self.import_tools = importutils.ImportTools(self.project)
+
+    def remove_old_imports(self, pymodule):
+        old_source = pymodule.source_code
+        module_with_imports = self.import_tools.module_imports(pymodule)
+
+        class CanSelect(object):
+            changed = False
+            old_name = self.old_name
+            old_pyname = self.old_pyname
+
+            def __call__(self, name):
+                try:
+                    if name == self.old_name and \
+                       pymodule[name].get_object() == \
+                       self.old_pyname.get_object():
+                        self.changed = True
+                        return False
+                except exceptions.AttributeNotFoundError:
+                    pass
+                return True
+        can_select = CanSelect()
+        module_with_imports.filter_names(can_select)
+        new_source = module_with_imports.get_changed_source()
+        if old_source != new_source:
+            return new_source
+
+    def rename_in_module(self, new_name, pymodule=None,
+                         imports=False, resource=None):
+        occurrence_finder = self._create_finder(imports)
+        source = rename.rename_in_module(
+            occurrence_finder, new_name, replace_primary=True,
+            pymodule=pymodule, resource=resource)
+        return source
+
+    def occurs_in_module(self, pymodule=None, resource=None, imports=True):
+        finder = self._create_finder(imports)
+        for occurrence in finder.find_occurrences(pymodule=pymodule,
+                                                  resource=resource):
+            return True
+        return False
+
+    def _create_finder(self, imports):
+        return occurrences.create_finder(self.project, self.old_name,
+                                         self.old_pyname, imports=imports,
+                                         keywords=False)
+
+    def new_pymodule(self, pymodule, source):
+        if source is not None:
+            return libutils.get_string_module(
+                self.project, source, pymodule.get_resource())
+        return pymodule
+
+    def new_source(self, pymodule, source):
+        if source is None:
+            return pymodule.source_code
+        return source
+
+    def add_imports(self, pymodule, new_imports):
+        return _add_imports_to_module(self.import_tools, pymodule, new_imports)
+
+
+def _add_imports_to_module(import_tools, pymodule, new_imports):
+    module_with_imports = import_tools.module_imports(pymodule)
+    for new_import in new_imports:
+        module_with_imports.add_import(new_import)
+    return module_with_imports.get_changed_source()
+
+
+def moving_code_with_imports(project, resource, source):
+    import_tools = importutils.ImportTools(project)
+    pymodule = libutils.get_string_module(project, source, resource)
+
+    # Strip comment prefix, if any. These need to stay before the moving
+    # section, but imports would be added between them.
+    lines = codeanalyze.SourceLinesAdapter(source)
+    start = 1
+    while start < lines.length() and lines.get_line(start).startswith('#'):
+        start += 1
+    moving_prefix = source[:lines.get_line_start(start)]
+    pymodule = libutils.get_string_module(
+        project, source[lines.get_line_start(start):], resource)
+
+    origin = project.get_pymodule(resource)
+
+    imports = []
+    for stmt in import_tools.module_imports(origin).imports:
+        imports.append(stmt.import_info)
+
+    back_names = []
+    for name in origin:
+        if name not in pymodule:
+            back_names.append(name)
+    imports.append(import_tools.get_from_import(resource, back_names))
+
+    source = _add_imports_to_module(import_tools, pymodule, imports)
+    pymodule = libutils.get_string_module(project, source, resource)
+
+    source = import_tools.relatives_to_absolutes(pymodule)
+    pymodule = libutils.get_string_module(project, source, resource)
+    source = import_tools.organize_imports(pymodule, selfs=False)
+    pymodule = libutils.get_string_module(project, source, resource)
+
+    # extracting imports after changes
+    module_imports = import_tools.module_imports(pymodule)
+    imports = [import_stmt.import_info
+               for import_stmt in module_imports.imports]
+    start = 1
+    if module_imports.imports:
+        start = module_imports.imports[-1].end_line
+    lines = codeanalyze.SourceLinesAdapter(source)
+    while start < lines.length() and not lines.get_line(start).strip():
+        start += 1
+
+    # Reinsert the prefix which was removed at the beginning
+    moving = moving_prefix + source[lines.get_line_start(start):]
+    return moving, imports
+
+
+class ModuleSkipRenamerHandle(object):
+
+    def occurred_outside_skip(self, change_collector, occurrence):
+        pass
+
+    def occurred_inside_skip(self, change_collector, occurrence):
+        pass
+
+
+class ModuleSkipRenamer(object):
+    """Rename occurrences in a module
+
+    This class can be used when you want to treat a region in a file
+    separately from other parts when renaming.
+
+    """
+
+    def __init__(self, occurrence_finder, resource, handle=None,
+                 skip_start=0, skip_end=0, replacement=''):
+        """Constructor
+
+        if replacement is `None` the region is not changed.  Otherwise
+        it is replaced with `replacement`.
+
+        """
+        self.occurrence_finder = occurrence_finder
+        self.resource = resource
+        self.skip_start = skip_start
+        self.skip_end = skip_end
+        self.replacement = replacement
+        self.handle = handle
+        if self.handle is None:
+            self.handle = ModuleSkipRenamerHandle()
+
+    def get_changed_module(self):
+        source = self.resource.read()
+        change_collector = codeanalyze.ChangeCollector(source)
+        if self.replacement is not None:
+            change_collector.add_change(self.skip_start, self.skip_end,
+                                        self.replacement)
+        for occurrence in self.occurrence_finder.find_occurrences(
+                self.resource):
+            start, end = occurrence.get_primary_range()
+            if self.skip_start <= start < self.skip_end:
+                self.handle.occurred_inside_skip(change_collector, occurrence)
+            else:
+                self.handle.occurred_outside_skip(change_collector, occurrence)
+        result = change_collector.get_changed()
+        if result is not None and result != source:
+            return result
diff --git a/venv/Lib/site-packages/rope/refactor/multiproject.py b/venv/Lib/site-packages/rope/refactor/multiproject.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac243bdafcea6a7fd01cbe547a4a94ac04dfa7e5
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/multiproject.py
@@ -0,0 +1,78 @@
+"""This module can be used for performing cross-project refactorings
+
+See the "cross-project refactorings" section of ``docs/library.rst``
+file.
+
+"""
+
+from rope.base import resources, libutils
+
+
+class MultiProjectRefactoring(object):
+
+    def __init__(self, refactoring, projects, addpath=True):
+        """Create a multiproject proxy for the main refactoring
+
+        `projects` are other project.
+
+        """
+        self.refactoring = refactoring
+        self.projects = projects
+        self.addpath = addpath
+
+    def __call__(self, project, *args, **kwds):
+        """Create the refactoring"""
+        return _MultiRefactoring(self.refactoring, self.projects,
+                                 self.addpath, project, *args, **kwds)
+
+
+class _MultiRefactoring(object):
+
+    def __init__(self, refactoring, other_projects, addpath,
+                 project, *args, **kwds):
+        self.refactoring = refactoring
+        self.projects = [project] + other_projects
+        for other_project in other_projects:
+            for folder in self.project.get_source_folders():
+                other_project.get_prefs().add('python_path', folder.real_path)
+        self.refactorings = []
+        for other in self.projects:
+            args, kwds = self._resources_for_args(other, args, kwds)
+            self.refactorings.append(
+                self.refactoring(other, *args, **kwds))
+
+    def get_all_changes(self, *args, **kwds):
+        """Get a project to changes dict"""
+        result = []
+        for project, refactoring in zip(self.projects, self.refactorings):
+            args, kwds = self._resources_for_args(project, args, kwds)
+            result.append((project, refactoring.get_changes(*args, **kwds)))
+        return result
+
+    def __getattr__(self, name):
+        return getattr(self.main_refactoring, name)
+
+    def _resources_for_args(self, project, args, kwds):
+        newargs = [self._change_project_resource(project, arg) for arg in args]
+        newkwds = dict((name, self._change_project_resource(project, value))
+                       for name, value in kwds.items())
+        return newargs, newkwds
+
+    def _change_project_resource(self, project, obj):
+        if isinstance(obj, resources.Resource) and \
+           obj.project != project:
+            return libutils.path_to_resource(project, obj.real_path)
+        return obj
+
+    @property
+    def project(self):
+        return self.projects[0]
+
+    @property
+    def main_refactoring(self):
+        return self.refactorings[0]
+
+
+def perform(project_changes):
+    for project, changes in project_changes:
+        project.do(changes)
diff --git a/venv/Lib/site-packages/rope/refactor/occurrences.py b/venv/Lib/site-packages/rope/refactor/occurrences.py
new file mode 100644
index 0000000000000000000000000000000000000000..dfc2d685d7d858b5b6280f62a916ae6b94954577
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/occurrences.py
@@ -0,0 +1,402 @@
+"""Find occurrences of a name in a project.
+
+This module consists of a `Finder` that finds all occurrences of a name
+in a project. The `Finder.find_occurrences()` method is a generator that
+yields `Occurrence` instances for each occurrence of the name. To create
+a `Finder` object, use the `create_finder()` function:
+
+    finder = occurrences.create_finder(project, 'foo', pyname)
+    for occurrence in finder.find_occurrences():
+        pass
+
+It's possible to filter the occurrences. They can be specified when
+calling the `create_finder()` function.
+
+  * `only_calls`: If True, return only those instances where the name is
+    a function that's being called.
+
+  * `imports`: If False, don't return instances that are in import
+    statements.
+
+  * `unsure`: If a prediate function, return instances where we don't
+    know what the name references. It also filters based on the
+    predicate function.
+
+  * `docs`: If True, it will search for occurrences in regions normally
+    ignored. E.g., strings and comments.
+
+  * `in_hierarchy`: If True, it will find occurrences if the name is in
+    the class's hierarchy.
+
+  * `instance`: Used only when you want implicit interfaces to be
+    considered.
+
+  * `keywords`: If False, don't return instances that are the names of keyword
+    arguments
+"""
+
+import re
+
+from rope.base import codeanalyze
+from rope.base import evaluate
+from rope.base import exceptions
+from rope.base import pynames
+from rope.base import pyobjects
+from rope.base import utils
+from rope.base import worder
+
+
+class Finder(object):
+    """For finding occurrences of a name
+
+    The constructor takes a `filters` argument.  It should be a list
+    of functions that take a single argument.  For each possible
+    occurrence, these functions are called in order with the an
+    instance of `Occurrence`:
+
+      * If it returns `None` other filters are tried.
+      * If it returns `True`, the occurrence will be a match.
+      * If it returns `False`, the occurrence will be skipped.
+      * If all of the filters return `None`, it is skipped also.
+
+    """
+
+    def __init__(self, project, name, filters=[lambda o: True], docs=False):
+        self.project = project
+        self.name = name
+        self.docs = docs
+        self.filters = filters
+        self._textual_finder = _TextualFinder(name, docs=docs)
+
+    def find_occurrences(self, resource=None, pymodule=None):
+        """Generate `Occurrence` instances"""
+        tools = _OccurrenceToolsCreator(self.project, resource=resource,
+                                        pymodule=pymodule, docs=self.docs)
+        for offset in self._textual_finder.find_offsets(tools.source_code):
+            occurrence = Occurrence(tools, offset)
+            for filter in self.filters:
+                result = filter(occurrence)
+                if result is None:
+                    continue
+                if result:
+                    yield occurrence
+                break
+
+
+def create_finder(project, name, pyname, only_calls=False, imports=True,
+                  unsure=None, docs=False, instance=None, in_hierarchy=False,
+                  keywords=True):
+    """A factory for `Finder`
+
+    Based on the arguments it creates a list of filters.  `instance`
+    argument is needed only when you want implicit interfaces to be
+    considered.
+
+    """
+    pynames_ = set([pyname])
+    filters = []
+    if only_calls:
+        filters.append(CallsFilter())
+    if not imports:
+        filters.append(NoImportsFilter())
+    if not keywords:
+        filters.append(NoKeywordsFilter())
+    if isinstance(instance, pynames.ParameterName):
+        for pyobject in instance.get_objects():
+            try:
+                pynames_.add(pyobject[name])
+            except exceptions.AttributeNotFoundError:
+                pass
+    for pyname in pynames_:
+        filters.append(PyNameFilter(pyname))
+        if in_hierarchy:
+            filters.append(InHierarchyFilter(pyname))
+    if unsure:
+        filters.append(UnsureFilter(unsure))
+    return Finder(project, name, filters=filters, docs=docs)
+
+
+class Occurrence(object):
+
+    def __init__(self, tools, offset):
+        self.tools = tools
+        self.offset = offset
+        self.resource = tools.resource
+
+    @utils.saveit
+    def get_word_range(self):
+        return self.tools.word_finder.get_word_range(self.offset)
+
+    @utils.saveit
+    def get_primary_range(self):
+        return self.tools.word_finder.get_primary_range(self.offset)
+
+    @utils.saveit
+    def get_pyname(self):
+        try:
+            return self.tools.name_finder.get_pyname_at(self.offset)
+        except exceptions.BadIdentifierError:
+            pass
+
+    @utils.saveit
+    def get_primary_and_pyname(self):
+        try:
+            return self.tools.name_finder.get_primary_and_pyname_at(
+                self.offset)
+        except exceptions.BadIdentifierError:
+            pass
+
+    @utils.saveit
+    def is_in_import_statement(self):
+        return (self.tools.word_finder.is_from_statement(self.offset) or
+                self.tools.word_finder.is_import_statement(self.offset))
+
+    def is_called(self):
+        return self.tools.word_finder.is_a_function_being_called(self.offset)
+
+    def is_defined(self):
+        return self.tools.word_finder.is_a_class_or_function_name_in_header(
+            self.offset)
+
+    def is_a_fixed_primary(self):
+        return self.tools.word_finder.is_a_class_or_function_name_in_header(
+            self.offset) or \
+            self.tools.word_finder.is_a_name_after_from_import(self.offset)
+
+    def is_written(self):
+        return self.tools.word_finder.is_assigned_here(self.offset)
+
+    def is_unsure(self):
+        return unsure_pyname(self.get_pyname())
+
+    def is_function_keyword_parameter(self):
+        return self.tools.word_finder.is_function_keyword_parameter(
+            self.offset)
+
+    @property
+    @utils.saveit
+    def lineno(self):
+        offset = self.get_word_range()[0]
+        return self.tools.pymodule.lines.get_line_number(offset)
+
+
+def same_pyname(expected, pyname):
+    """Check whether `expected` and `pyname` are the same"""
+    if expected is None or pyname is None:
+        return False
+    if expected == pyname:
+        return True
+    if type(expected) not in (pynames.ImportedModule, pynames.ImportedName) \
+        and type(pyname) not in \
+            (pynames.ImportedModule, pynames.ImportedName):
+        return False
+    return expected.get_definition_location() == \
+        pyname.get_definition_location() and \
+        expected.get_object() == pyname.get_object()
+
+
+def unsure_pyname(pyname, unbound=True):
+    """Return `True` if we don't know what this name references"""
+    if pyname is None:
+        return True
+    if unbound and not isinstance(pyname, pynames.UnboundName):
+        return False
+    if pyname.get_object() == pyobjects.get_unknown():
+        return True
+
+
+class PyNameFilter(object):
+    """For finding occurrences of a name."""
+
+    def __init__(self, pyname):
+        self.pyname = pyname
+
+    def __call__(self, occurrence):
+        if same_pyname(self.pyname, occurrence.get_pyname()):
+            return True
+
+
+class InHierarchyFilter(object):
+    """Finds the occurrence if the name is in the class's hierarchy."""
+
+    def __init__(self, pyname, implementations_only=False):
+        self.pyname = pyname
+        self.impl_only = implementations_only
+        self.pyclass = self._get_containing_class(pyname)
+        if self.pyclass is not None:
+            self.name = pyname.get_object().get_name()
+            self.roots = self._get_root_classes(self.pyclass, self.name)
+        else:
+            self.roots = None
+
+    def __call__(self, occurrence):
+        if self.roots is None:
+            return
+        pyclass = self._get_containing_class(occurrence.get_pyname())
+        if pyclass is not None:
+            roots = self._get_root_classes(pyclass, self.name)
+            if self.roots.intersection(roots):
+                return True
+
+    def _get_containing_class(self, pyname):
+        if isinstance(pyname, pynames.DefinedName):
+            scope = pyname.get_object().get_scope()
+            parent = scope.parent
+            if parent is not None and parent.get_kind() == 'Class':
+                return parent.pyobject
+
+    def _get_root_classes(self, pyclass, name):
+        if self.impl_only and pyclass == self.pyclass:
+            return set([pyclass])
+        result = set()
+        for superclass in pyclass.get_superclasses():
+            if name in superclass:
+                result.update(self._get_root_classes(superclass, name))
+        if not result:
+            return set([pyclass])
+        return result
+
+
+class UnsureFilter(object):
+    """Occurrences where we don't knoow what the name references."""
+
+    def __init__(self, unsure):
+        self.unsure = unsure
+
+    def __call__(self, occurrence):
+        if occurrence.is_unsure() and self.unsure(occurrence):
+            return True
+
+
+class NoImportsFilter(object):
+    """Don't include import statements as occurrences."""
+
+    def __call__(self, occurrence):
+        if occurrence.is_in_import_statement():
+            return False
+
+
+class CallsFilter(object):
+    """Filter out non-call occurrences."""
+
+    def __call__(self, occurrence):
+        if not occurrence.is_called():
+            return False
+
+
+class NoKeywordsFilter(object):
+    """Filter out keyword parameters."""
+
+    def __call__(self, occurrence):
+        if occurrence.is_function_keyword_parameter():
+            return False
+
+
+class _TextualFinder(object):
+
+    def __init__(self, name, docs=False):
+        self.name = name
+        self.docs = docs
+        self.comment_pattern = _TextualFinder.any('comment', [r'#[^\n]*'])
+        self.string_pattern = _TextualFinder.any(
+            'string', [codeanalyze.get_string_pattern()])
+        self.pattern = self._get_occurrence_pattern(self.name)
+
+    def find_offsets(self, source):
+        if not self._fast_file_query(source):
+            return
+        if self.docs:
+            searcher = self._normal_search
+        else:
+            searcher = self._re_search
+        for matched in searcher(source):
+            yield matched
+
+    def _re_search(self, source):
+        for match in self.pattern.finditer(source):
+            for key, value in match.groupdict().items():
+                if value and key == 'occurrence':
+                    yield match.start(key)
+
+    def _normal_search(self, source):
+        current = 0
+        while True:
+            try:
+                found = source.index(self.name, current)
+                current = found + len(self.name)
+                if (found == 0 or
+                        not self._is_id_char(source[found - 1])) and \
+                    (current == len(source) or
+                        not self._is_id_char(source[current])):
+                    yield found
+            except ValueError:
+                break
+
+    def _is_id_char(self, c):
+        return c.isalnum() or c == '_'
+
+    def _fast_file_query(self, source):
+        try:
+            source.index(self.name)
+            return True
+        except ValueError:
+            return False
+
+    def _get_source(self, resource, pymodule):
+        if resource is not None:
+            return resource.read()
+        else:
+            return pymodule.source_code
+
+    def _get_occurrence_pattern(self, name):
+        occurrence_pattern = _TextualFinder.any('occurrence',
+                                                ['\\b' + name + '\\b'])
+        pattern = re.compile(occurrence_pattern + '|' + self.comment_pattern +
+                             '|' + self.string_pattern)
+        return pattern
+
+    @staticmethod
+    def any(name, list_):
+        return '(?P<%s>' % name + '|'.join(list_) + ')'
+
+
+class _OccurrenceToolsCreator(object):
+
+    def __init__(self, project, resource=None, pymodule=None, docs=False):
+        self.project = project
+        self.__resource = resource
+        self.__pymodule = pymodule
+        self.docs = docs
+
+    @property
+    @utils.saveit
+    def name_finder(self):
+        return evaluate.ScopeNameFinder(self.pymodule)
+
+    @property
+    @utils.saveit
+    def source_code(self):
+        if self.__resource is not None:
+            return self.resource.read()
+        else:
+            return self.pymodule.source_code
+
+    @property
+    @utils.saveit
+    def word_finder(self):
+        return worder.Worder(self.source_code, self.docs)
+
+    @property
+    @utils.saveit
+    def resource(self):
+        if self.__resource is not None:
+            return self.__resource
+        if self.__pymodule is not None:
+            return self.__pymodule.resource
+
+    @property
+    @utils.saveit
+    def pymodule(self):
+        if self.__pymodule is not None:
+            return self.__pymodule
+        return self.project.get_pymodule(self.resource)
diff --git a/venv/Lib/site-packages/rope/refactor/patchedast.py b/venv/Lib/site-packages/rope/refactor/patchedast.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e0522dd98676b1a671f32722c68d29748b1cbc4
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/patchedast.py
@@ -0,0 +1,852 @@
+import collections
+import re
+import warnings
+
+from rope.base import ast, codeanalyze, exceptions
+from rope.base.utils import pycompat
+
+try:
+    basestring
+except NameError:
+    basestring = (str, bytes)
+
+
+def get_patched_ast(source, sorted_children=False):
+    """Adds ``region`` and ``sorted_children`` fields to nodes
+
+    Adds ``sorted_children`` field only if `sorted_children` is True.
+
+    """
+    return patch_ast(ast.parse(source), source, sorted_children)
+
+
+def patch_ast(node, source, sorted_children=False):
+    """Patches the given node
+
+    After calling, each node in `node` will have a new field named
+    `region` that is a tuple containing the start and end offsets
+    of the code that generated it.
+
+    If `sorted_children` is true, a `sorted_children` field will
+    be created for each node, too.  It is a list containing child
+    nodes as well as whitespaces and comments that occur between
+    them.
+
+    """
+    if hasattr(node, 'region'):
+        return node
+    walker = _PatchingASTWalker(source, children=sorted_children)
+    ast.call_for_nodes(node, walker)
+    return node
+
+
+def node_region(patched_ast_node):
+    """Get the region of a patched ast node"""
+    return patched_ast_node.region
+
+
+def write_ast(patched_ast_node):
+    """Extract source form a patched AST node with `sorted_children` field
+
+    If the node is patched with sorted_children turned off you can use
+    `node_region` function for obtaining code using module source code.
+    """
+    result = []
+    for child in patched_ast_node.sorted_children:
+        if isinstance(child, ast.AST):
+            result.append(write_ast(child))
+        else:
+            result.append(child)
+    return ''.join(result)
+
+
+class MismatchedTokenError(exceptions.RopeError):
+    pass
+
+
+class _PatchingASTWalker(object):
+
+    def __init__(self, source, children=False):
+        self.source = _Source(source)
+        self.children = children
+        self.lines = codeanalyze.SourceLinesAdapter(source)
+        self.children_stack = []
+
+    Number = object()
+    String = object()
+    semicolon_or_as_in_except = object()
+
+    def __call__(self, node):
+        method = getattr(self, '_' + node.__class__.__name__, None)
+        if method is not None:
+            return method(node)
+        # ???: Unknown node; what should we do here?
+        warnings.warn('Unknown node type <%s>; please report!'
+                      % node.__class__.__name__, RuntimeWarning)
+        node.region = (self.source.offset, self.source.offset)
+        if self.children:
+            node.sorted_children = ast.get_children(node)
+
+    def _handle(self, node, base_children, eat_parens=False, eat_spaces=False):
+        if hasattr(node, 'region'):
+            # ???: The same node was seen twice; what should we do?
+            warnings.warn(
+                'Node <%s> has been already patched; please report!' %
+                node.__class__.__name__, RuntimeWarning)
+            return
+        base_children = collections.deque(base_children)
+        self.children_stack.append(base_children)
+        children = collections.deque()
+        formats = []
+        suspected_start = self.source.offset
+        start = suspected_start
+        first_token = True
+        while base_children:
+            child = base_children.popleft()
+            if child is None:
+                continue
+            offset = self.source.offset
+            if isinstance(child, ast.AST):
+                ast.call_for_nodes(child, self)
+                token_start = child.region[0]
+            else:
+                if child is self.String:
+                    region = self.source.consume_string(
+                        end=self._find_next_statement_start())
+                elif child is self.Number:
+                    region = self.source.consume_number()
+                elif child == '!=':
+                    # INFO: This has been added to handle deprecated ``<>``
+                    region = self.source.consume_not_equal()
+                elif child == self.semicolon_or_as_in_except:
+                    # INFO: This has been added to handle deprecated
+                    # semicolon in except
+                    region = self.source.consume_except_as_or_semicolon()
+                else:
+                    region = self.source.consume(child)
+                child = self.source[region[0]:region[1]]
+                token_start = region[0]
+            if not first_token:
+                formats.append(self.source[offset:token_start])
+                if self.children:
+                    children.append(self.source[offset:token_start])
+            else:
+                first_token = False
+                start = token_start
+            if self.children:
+                children.append(child)
+        start = self._handle_parens(children, start, formats)
+        if eat_parens:
+            start = self._eat_surrounding_parens(
+                children, suspected_start, start)
+        if eat_spaces:
+            if self.children:
+                children.appendleft(self.source[0:start])
+            end_spaces = self.source[self.source.offset:]
+            self.source.consume(end_spaces)
+            if self.children:
+                children.append(end_spaces)
+            start = 0
+        if self.children:
+            node.sorted_children = children
+        node.region = (start, self.source.offset)
+        self.children_stack.pop()
+
+    def _handle_parens(self, children, start, formats):
+        """Changes `children` and returns new start"""
+        opens, closes = self._count_needed_parens(formats)
+        old_end = self.source.offset
+        new_end = None
+        for i in range(closes):
+            new_end = self.source.consume(')')[1]
+        if new_end is not None:
+            if self.children:
+                children.append(self.source[old_end:new_end])
+        new_start = start
+        for i in range(opens):
+            new_start = self.source.rfind_token('(', 0, new_start)
+        if new_start != start:
+            if self.children:
+                children.appendleft(self.source[new_start:start])
+            start = new_start
+        return start
+
+    def _eat_surrounding_parens(self, children, suspected_start, start):
+        index = self.source.rfind_token('(', suspected_start, start)
+        if index is not None:
+            old_start = start
+            old_offset = self.source.offset
+            start = index
+            if self.children:
+                children.appendleft(self.source[start + 1:old_start])
+                children.appendleft('(')
+            token_start, token_end = self.source.consume(')')
+            if self.children:
+                children.append(self.source[old_offset:token_start])
+                children.append(')')
+        return start
+
+    def _count_needed_parens(self, children):
+        start = 0
+        opens = 0
+        for child in children:
+            if not isinstance(child, basestring):
+                continue
+            if child == '' or child[0] in '\'"':
+                continue
+            index = 0
+            while index < len(child):
+                if child[index] == ')':
+                    if opens > 0:
+                        opens -= 1
+                    else:
+                        start += 1
+                if child[index] == '(':
+                    opens += 1
+                if child[index] == '#':
+                    try:
+                        index = child.index('\n', index)
+                    except ValueError:
+                        break
+                index += 1
+        return start, opens
+
+    def _find_next_statement_start(self):
+        for children in reversed(self.children_stack):
+            for child in children:
+                if isinstance(child, ast.stmt):
+                    return child.col_offset \
+                        + self.lines.get_line_start(child.lineno)
+        return len(self.source.source)
+
+    _operators = {'And': 'and', 'Or': 'or', 'Add': '+', 'Sub': '-',
+                  'Mult': '*', 'Div': '/', 'Mod': '%', 'Pow': '**',
+                  'LShift': '<<', 'RShift': '>>', 'BitOr': '|', 'BitAnd': '&',
+                  'BitXor': '^', 'FloorDiv': '//', 'Invert': '~',
+                  'Not': 'not', 'UAdd': '+', 'USub': '-', 'Eq': '==',
+                  'NotEq': '!=', 'Lt': '<', 'LtE': '<=', 'Gt': '>',
+                  'GtE': '>=', 'Is': 'is', 'IsNot': 'is not', 'In': 'in',
+                  'NotIn': 'not in'}
+
+    def _get_op(self, node):
+        return self._operators[node.__class__.__name__].split(' ')
+
+    def _Attribute(self, node):
+        self._handle(node, [node.value, '.', node.attr])
+
+    def _Assert(self, node):
+        children = ['assert', node.test]
+        if node.msg:
+            children.append(',')
+            children.append(node.msg)
+        self._handle(node, children)
+
+    def _Assign(self, node):
+        children = self._child_nodes(node.targets, '=')
+        children.append('=')
+        children.append(node.value)
+        self._handle(node, children)
+
+    def _AugAssign(self, node):
+        children = [node.target]
+        children.extend(self._get_op(node.op))
+        children.extend(['=', node.value])
+        self._handle(node, children)
+
+    def _Repr(self, node):
+        self._handle(node, ['`', node.value, '`'])
+
+    def _BinOp(self, node):
+        children = [node.left] + self._get_op(node.op) + [node.right]
+        self._handle(node, children)
+
+    def _BoolOp(self, node):
+        self._handle(node, self._child_nodes(node.values,
+                                             self._get_op(node.op)[0]))
+
+    def _Break(self, node):
+        self._handle(node, ['break'])
+
+    def _Call(self, node):
+        def _arg_sort_key(node):
+          if isinstance(node, ast.keyword):
+            return (node.value.lineno, node.value.col_offset)
+          return (node.lineno, node.col_offset)
+
+        children = [node.func, '(']
+        unstarred_args = []
+        starred_and_keywords = list(node.keywords)
+        for i, arg in enumerate(node.args):
+          if hasattr(ast, 'Starred') and isinstance(arg, ast.Starred):
+            starred_and_keywords.append(arg)
+          else:
+            unstarred_args.append(arg)
+        if getattr(node, 'starargs', None):
+          starred_and_keywords.append(node.starargs)
+        starred_and_keywords.sort(key=_arg_sort_key)
+        children.extend(self._child_nodes(unstarred_args, ','))
+
+        # positional args come before keywords, *args comes after all
+        # positional args, and **kwargs comes last
+        if starred_and_keywords:
+          if len(children) > 2:
+            children.append(',')
+          for i, arg in enumerate(starred_and_keywords):
+            if arg == getattr(node, 'starargs', None):
+              children.append('*')
+            children.append(arg)
+            if i + 1 < len(starred_and_keywords):
+              children.append(',')
+
+        if getattr(node, 'kwargs', None):
+            if len(children) > 2:
+                children.append(',')
+            children.extend(['**', node.kwargs])
+        children.append(')')
+        self._handle(node, children)
+
+    def _ClassDef(self, node):
+        children = []
+        if getattr(node, 'decorator_list', None):
+            for decorator in node.decorator_list:
+                children.append('@')
+                children.append(decorator)
+        children.extend(['class', node.name])
+        if node.bases:
+            children.append('(')
+            children.extend(self._child_nodes(node.bases, ','))
+            children.append(')')
+        children.append(':')
+        children.extend(node.body)
+        self._handle(node, children)
+
+    def _Compare(self, node):
+        children = []
+        children.append(node.left)
+        for op, expr in zip(node.ops, node.comparators):
+            children.extend(self._get_op(op))
+            children.append(expr)
+        self._handle(node, children)
+
+    def _Delete(self, node):
+        self._handle(node, ['del'] + self._child_nodes(node.targets, ','))
+
+    def _Num(self, node):
+        self._handle(node, [self.Number])
+
+    def _Str(self, node):
+        self._handle(node, [self.String])
+
+    def _Continue(self, node):
+        self._handle(node, ['continue'])
+
+    def _Dict(self, node):
+        children = []
+        children.append('{')
+        if node.keys:
+            for index, (key, value) in enumerate(zip(node.keys, node.values)):
+                children.extend([key, ':', value])
+                if index < len(node.keys) - 1:
+                    children.append(',')
+        children.append('}')
+        self._handle(node, children)
+
+    def _Ellipsis(self, node):
+        self._handle(node, ['...'])
+
+    def _Expr(self, node):
+        self._handle(node, [node.value])
+
+    def _Exec(self, node):
+        children = []
+        children.extend(['exec', node.body])
+        if node.globals:
+            children.extend(['in', node.globals])
+        if node.locals:
+            children.extend([',', node.locals])
+        self._handle(node, children)
+
+    def _ExtSlice(self, node):
+        children = []
+        for index, dim in enumerate(node.dims):
+            if index > 0:
+                children.append(',')
+            children.append(dim)
+        self._handle(node, children)
+
+    def _For(self, node):
+        children = ['for', node.target, 'in', node.iter, ':']
+        children.extend(node.body)
+        if node.orelse:
+            children.extend(['else', ':'])
+            children.extend(node.orelse)
+        self._handle(node, children)
+
+    def _ImportFrom(self, node):
+        children = ['from']
+        if node.level:
+            children.append('.' * node.level)
+        # see comment at rope.base.ast.walk
+        children.extend([node.module or '',
+                         'import'])
+        children.extend(self._child_nodes(node.names, ','))
+        self._handle(node, children)
+
+    def _alias(self, node):
+        children = [node.name]
+        if node.asname:
+            children.extend(['as', node.asname])
+        self._handle(node, children)
+
+    def _FunctionDef(self, node):
+        children = []
+        try:
+            decorators = getattr(node, 'decorator_list')
+        except AttributeError:
+            decorators = getattr(node, 'decorators', None)
+        if decorators:
+            for decorator in decorators:
+                children.append('@')
+                children.append(decorator)
+        children.extend(['def', node.name, '(', node.args])
+        children.extend([')', ':'])
+        children.extend(node.body)
+        self._handle(node, children)
+
+    def _arguments(self, node):
+        children = []
+        args = list(node.args)
+        defaults = [None] * (len(args) - len(node.defaults)) + \
+            list(node.defaults)
+        for index, (arg, default) in enumerate(zip(args, defaults)):
+            if index > 0:
+                children.append(',')
+            self._add_args_to_children(children, arg, default)
+        if node.vararg is not None:
+            if args:
+                children.append(',')
+            children.extend(['*', pycompat.get_ast_arg_arg(node.vararg)])
+        if node.kwarg is not None:
+            if args or node.vararg is not None:
+                children.append(',')
+            children.extend(['**', pycompat.get_ast_arg_arg(node.kwarg)])
+        self._handle(node, children)
+
+    def _add_args_to_children(self, children, arg, default):
+        if isinstance(arg, (list, tuple)):
+            self._add_tuple_parameter(children, arg)
+        else:
+            children.append(arg)
+        if default is not None:
+            children.append('=')
+            children.append(default)
+
+    def _add_tuple_parameter(self, children, arg):
+        children.append('(')
+        for index, token in enumerate(arg):
+            if index > 0:
+                children.append(',')
+            if isinstance(token, (list, tuple)):
+                self._add_tuple_parameter(children, token)
+            else:
+                children.append(token)
+        children.append(')')
+
+    def _GeneratorExp(self, node):
+        children = [node.elt]
+        children.extend(node.generators)
+        self._handle(node, children, eat_parens=True)
+
+    def _comprehension(self, node):
+        children = ['for', node.target, 'in', node.iter]
+        if node.ifs:
+            for if_ in node.ifs:
+                children.append('if')
+                children.append(if_)
+        self._handle(node, children)
+
+    def _Global(self, node):
+        children = self._child_nodes(node.names, ',')
+        children.insert(0, 'global')
+        self._handle(node, children)
+
+    def _If(self, node):
+        if self._is_elif(node):
+            children = ['elif']
+        else:
+            children = ['if']
+        children.extend([node.test, ':'])
+        children.extend(node.body)
+        if node.orelse:
+            if len(node.orelse) == 1 and self._is_elif(node.orelse[0]):
+                pass
+            else:
+                children.extend(['else', ':'])
+            children.extend(node.orelse)
+        self._handle(node, children)
+
+    def _is_elif(self, node):
+        if not isinstance(node, ast.If):
+            return False
+        offset = self.lines.get_line_start(node.lineno) + node.col_offset
+        word = self.source[offset:offset + 4]
+        # XXX: This is a bug; the offset does not point to the first
+        alt_word = self.source[offset - 5:offset - 1]
+        return 'elif' in (word, alt_word)
+
+    def _IfExp(self, node):
+        return self._handle(node, [node.body, 'if', node.test,
+                                   'else', node.orelse])
+
+    def _Import(self, node):
+        children = ['import']
+        children.extend(self._child_nodes(node.names, ','))
+        self._handle(node, children)
+
+    def _keyword(self, node):
+        children = []
+        if node.arg is None:
+            children.append(node.value)
+        else:
+            children.extend([node.arg, '=', node.value])
+        self._handle(node, children)
+
+    def _Lambda(self, node):
+        self._handle(node, ['lambda', node.args, ':', node.body])
+
+    def _List(self, node):
+        self._handle(node, ['['] + self._child_nodes(node.elts, ',') + [']'])
+
+    def _ListComp(self, node):
+        children = ['[', node.elt]
+        children.extend(node.generators)
+        children.append(']')
+        self._handle(node, children)
+
+    def _Set(self, node):
+        if node.elts:
+            self._handle(node,
+                         ['{'] + self._child_nodes(node.elts, ',') + ['}'])
+            return
+        # Python doesn't have empty set literals
+        warnings.warn('Tried to handle empty <Set> literal; please report!',
+                      RuntimeWarning)
+        self._handle(node, ['set(', ')'])
+
+    def _SetComp(self, node):
+        children = ['{', node.elt]
+        children.extend(node.generators)
+        children.append('}')
+        self._handle(node, children)
+
+    def _DictComp(self, node):
+        children = ['{']
+        children.extend([node.key, ':', node.value])
+        children.extend(node.generators)
+        children.append('}')
+        self._handle(node, children)
+
+    def _Module(self, node):
+        self._handle(node, list(node.body), eat_spaces=True)
+
+    def _Name(self, node):
+        self._handle(node, [node.id])
+
+    def _NameConstant(self, node):
+        self._handle(node, [str(node.value)])
+
+    def _arg(self, node):
+        self._handle(node, [node.arg])
+
+    def _Pass(self, node):
+        self._handle(node, ['pass'])
+
+    def _Print(self, node):
+        children = ['print']
+        if node.dest:
+            children.extend(['>>', node.dest])
+            if node.values:
+                children.append(',')
+        children.extend(self._child_nodes(node.values, ','))
+        if not node.nl:
+            children.append(',')
+        self._handle(node, children)
+
+    def _Raise(self, node):
+
+        def get_python3_raise_children(node):
+            children = ['raise']
+            if node.exc:
+                children.append(node.exc)
+            if node.cause:
+                children.append(node.cause)
+            return children
+
+        def get_python2_raise_children(node):
+            children = ['raise']
+            if node.type:
+                children.append(node.type)
+            if node.inst:
+                children.append(',')
+                children.append(node.inst)
+            if node.tback:
+                children.append(',')
+                children.append(node.tback)
+            return children
+        if pycompat.PY2:
+            children = get_python2_raise_children(node)
+        else:
+            children = get_python3_raise_children(node)
+        self._handle(node, children)
+
+    def _Return(self, node):
+        children = ['return']
+        if node.value:
+            children.append(node.value)
+        self._handle(node, children)
+
+    def _Sliceobj(self, node):
+        children = []
+        for index, slice in enumerate(node.nodes):
+            if index > 0:
+                children.append(':')
+            if slice:
+                children.append(slice)
+        self._handle(node, children)
+
+    def _Index(self, node):
+        self._handle(node, [node.value])
+
+    def _Subscript(self, node):
+        self._handle(node, [node.value, '[', node.slice, ']'])
+
+    def _Slice(self, node):
+        children = []
+        if node.lower:
+            children.append(node.lower)
+        children.append(':')
+        if node.upper:
+            children.append(node.upper)
+        if node.step:
+            children.append(':')
+            children.append(node.step)
+        self._handle(node, children)
+
+    def _TryFinally(self, node):
+        # @todo fixme
+        is_there_except_handler = False
+        not_empty_body = True
+        if len(node.finalbody) == 1:
+            if pycompat.PY2:
+                is_there_except_handler = isinstance(node.body[0], ast.TryExcept)
+                not_empty_body = not bool(len(node.body))
+            elif pycompat.PY3:
+                try:
+                    is_there_except_handler = isinstance(node.handlers[0], ast.ExceptHandler)
+                    not_empty_body = True
+                except IndexError:
+                    pass
+        children = []
+        if not_empty_body or not is_there_except_handler:
+            children.extend(['try', ':'])
+        children.extend(node.body)
+        if pycompat.PY3:
+            children.extend(node.handlers)
+        children.extend(['finally', ':'])
+        children.extend(node.finalbody)
+        self._handle(node, children)
+
+    def _TryExcept(self, node):
+        children = ['try', ':']
+        children.extend(node.body)
+        children.extend(node.handlers)
+        if node.orelse:
+            children.extend(['else', ':'])
+            children.extend(node.orelse)
+        self._handle(node, children)
+
+    def _Try(self, node):
+        if len(node.finalbody):
+            self._TryFinally(node)
+        else:
+            self._TryExcept(node)
+
+    def _ExceptHandler(self, node):
+        self._excepthandler(node)
+
+    def _excepthandler(self, node):
+        # self._handle(node, [self.semicolon_or_as_in_except])
+        children = ['except']
+        if node.type:
+            children.append(node.type)
+        if node.name:
+            children.append(self.semicolon_or_as_in_except)
+            children.append(node.name)
+        children.append(':')
+        children.extend(node.body)
+
+        self._handle(node, children)
+
+    def _Tuple(self, node):
+        if node.elts:
+            self._handle(node, self._child_nodes(node.elts, ','),
+                         eat_parens=True)
+        else:
+            self._handle(node, ['(', ')'])
+
+    def _UnaryOp(self, node):
+        children = self._get_op(node.op)
+        children.append(node.operand)
+        self._handle(node, children)
+
+    def _Yield(self, node):
+        children = ['yield']
+        if node.value:
+            children.append(node.value)
+        self._handle(node, children)
+
+    def _While(self, node):
+        children = ['while', node.test, ':']
+        children.extend(node.body)
+        if node.orelse:
+            children.extend(['else', ':'])
+            children.extend(node.orelse)
+        self._handle(node, children)
+
+    def _With(self, node):
+        children = []
+        for item in pycompat.get_ast_with_items(node):
+            children.extend(['with', item.context_expr])
+            if item.optional_vars:
+                children.extend(['as', item.optional_vars])
+        children.append(':')
+        children.extend(node.body)
+        self._handle(node, children)
+
+    def _child_nodes(self, nodes, separator):
+        children = []
+        for index, child in enumerate(nodes):
+            children.append(child)
+            if index < len(nodes) - 1:
+                children.append(separator)
+        return children
+
+    def _Starred(self, node):
+        self._handle(node, [node.value])
+
+class _Source(object):
+
+    def __init__(self, source):
+        self.source = source
+        self.offset = 0
+
+    def consume(self, token):
+        try:
+            while True:
+                new_offset = self.source.index(token, self.offset)
+                if self._good_token(token, new_offset):
+                    break
+                else:
+                    self._skip_comment()
+        except (ValueError, TypeError):
+            raise MismatchedTokenError(
+                'Token <%s> at %s cannot be matched' %
+                (token, self._get_location()))
+        self.offset = new_offset + len(token)
+        return (new_offset, self.offset)
+
+    def consume_string(self, end=None):
+        if _Source._string_pattern is None:
+            original = codeanalyze.get_string_pattern()
+            pattern = r'(%s)((\s|\\\n|#[^\n]*\n)*(%s))*' % \
+                      (original, original)
+            _Source._string_pattern = re.compile(pattern)
+        repattern = _Source._string_pattern
+        return self._consume_pattern(repattern, end)
+
+    def consume_number(self):
+        if _Source._number_pattern is None:
+            _Source._number_pattern = re.compile(
+                self._get_number_pattern())
+        repattern = _Source._number_pattern
+        return self._consume_pattern(repattern)
+
+    def consume_not_equal(self):
+        if _Source._not_equals_pattern is None:
+            _Source._not_equals_pattern = re.compile(r'<>|!=')
+        repattern = _Source._not_equals_pattern
+        return self._consume_pattern(repattern)
+
+    def consume_except_as_or_semicolon(self):
+        repattern = re.compile(r'as|,')
+        return self._consume_pattern(repattern)
+
+    def _good_token(self, token, offset, start=None):
+        """Checks whether consumed token is in comments"""
+        if start is None:
+            start = self.offset
+        try:
+            comment_index = self.source.rindex('#', start, offset)
+        except ValueError:
+            return True
+        try:
+            new_line_index = self.source.rindex('\n', start, offset)
+        except ValueError:
+            return False
+        return comment_index < new_line_index
+
+    def _skip_comment(self):
+        self.offset = self.source.index('\n', self.offset + 1)
+
+    def _get_location(self):
+        lines = self.source[:self.offset].split('\n')
+        return (len(lines), len(lines[-1]))
+
+    def _consume_pattern(self, repattern, end=None):
+        while True:
+            if end is None:
+                end = len(self.source)
+            match = repattern.search(self.source, self.offset, end)
+            if self._good_token(match.group(), match.start()):
+                break
+            else:
+                self._skip_comment()
+        self.offset = match.end()
+        return match.start(), match.end()
+
+    def till_token(self, token):
+        new_offset = self.source.index(token, self.offset)
+        return self[self.offset:new_offset]
+
+    def rfind_token(self, token, start, end):
+        index = start
+        while True:
+            try:
+                index = self.source.rindex(token, start, end)
+                if self._good_token(token, index, start=start):
+                    return index
+                else:
+                    end = index
+            except ValueError:
+                return None
+
+    def from_offset(self, offset):
+        return self[offset:self.offset]
+
+    def find_backwards(self, pattern, offset):
+        return self.source.rindex(pattern, 0, offset)
+
+    def __getitem__(self, index):
+        return self.source[index]
+
+    def __getslice__(self, i, j):
+        return self.source[i:j]
+
+    def _get_number_pattern(self):
+        # HACK: It is merely an approaximation and does the job
+        integer = r'\-?(0x[\da-fA-F]+|\d+)[lL]?'
+        return r'(%s(\.\d*)?|(\.\d+))([eE][-+]?\d+)?[jJ]?' % integer
+
+    _string_pattern = None
+    _number_pattern = None
+    _not_equals_pattern = None
diff --git a/venv/Lib/site-packages/rope/refactor/rename.py b/venv/Lib/site-packages/rope/refactor/rename.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f1f5b7e6d61271124767e29a8be067c96e5199a
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/rename.py
@@ -0,0 +1,220 @@
+import warnings
+
+from rope.base import (exceptions, pyobjects, pynames, taskhandle,
+                       evaluate, worder, codeanalyze, libutils)
+from rope.base.change import ChangeSet, ChangeContents, MoveResource
+from rope.refactor import occurrences
+
+
+class Rename(object):
+    """A class for performing rename refactoring
+
+    It can rename everything: classes, functions, modules, packages,
+    methods, variables and keyword arguments.
+
+    """
+
+    def __init__(self, project, resource, offset=None):
+        """If `offset` is None, the `resource` itself will be renamed"""
+        self.project = project
+        self.resource = resource
+        if offset is not None:
+            self.old_name = worder.get_name_at(self.resource, offset)
+            this_pymodule = self.project.get_pymodule(self.resource)
+            self.old_instance, self.old_pyname = \
+                evaluate.eval_location2(this_pymodule, offset)
+            if self.old_pyname is None:
+                raise exceptions.RefactoringError(
+                    'Rename refactoring should be performed'
+                    ' on resolvable python identifiers.')
+        else:
+            if not resource.is_folder() and resource.name == '__init__.py':
+                resource = resource.parent
+            dummy_pymodule = libutils.get_string_module(self.project, '')
+            self.old_instance = None
+            self.old_pyname = pynames.ImportedModule(dummy_pymodule,
+                                                     resource=resource)
+            if resource.is_folder():
+                self.old_name = resource.name
+            else:
+                self.old_name = resource.name[:-3]
+
+    def get_old_name(self):
+        return self.old_name
+
+    def get_changes(self, new_name, in_file=None, in_hierarchy=False,
+                    unsure=None, docs=False, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        """Get the changes needed for this refactoring
+
+        Parameters:
+
+        - `in_hierarchy`: when renaming a method this keyword forces
+          to rename all matching methods in the hierarchy
+        - `docs`: when `True` rename refactoring will rename
+          occurrences in comments and strings where the name is
+          visible.  Setting it will make renames faster, too.
+        - `unsure`: decides what to do about unsure occurrences.
+          If `None`, they are ignored.  Otherwise `unsure` is
+          called with an instance of `occurrence.Occurrence` as
+          parameter.  If it returns `True`, the occurrence is
+          considered to be a match.
+        - `resources` can be a list of `rope.base.resources.File`\s to
+          apply this refactoring on.  If `None`, the restructuring
+          will be applied to all python files.
+        - `in_file`: this argument has been deprecated; use
+          `resources` instead.
+
+        """
+        if unsure in (True, False):
+            warnings.warn(
+                'unsure parameter should be a function that returns '
+                'True or False', DeprecationWarning, stacklevel=2)
+
+            def unsure_func(value=unsure):
+                return value
+            unsure = unsure_func
+        if in_file is not None:
+            warnings.warn(
+                '`in_file` argument has been deprecated; use `resources` '
+                'instead. ', DeprecationWarning, stacklevel=2)
+            if in_file:
+                resources = [self.resource]
+        if _is_local(self.old_pyname):
+            resources = [self.resource]
+        if resources is None:
+            resources = self.project.get_python_files()
+        changes = ChangeSet('Renaming <%s> to <%s>' %
+                            (self.old_name, new_name))
+        finder = occurrences.create_finder(
+            self.project, self.old_name, self.old_pyname, unsure=unsure,
+            docs=docs, instance=self.old_instance,
+            in_hierarchy=in_hierarchy and self.is_method())
+        job_set = task_handle.create_jobset('Collecting Changes',
+                                            len(resources))
+        for file_ in resources:
+            job_set.started_job(file_.path)
+            new_content = rename_in_module(finder, new_name, resource=file_)
+            if new_content is not None:
+                changes.add_change(ChangeContents(file_, new_content))
+            job_set.finished_job()
+        if self._is_renaming_a_module():
+            resource = self.old_pyname.get_object().get_resource()
+            if self._is_allowed_to_move(resources, resource):
+                self._rename_module(resource, new_name, changes)
+        return changes
+
+    def _is_allowed_to_move(self, resources, resource):
+        if resource.is_folder():
+            try:
+                return resource.get_child('__init__.py') in resources
+            except exceptions.ResourceNotFoundError:
+                return False
+        else:
+            return resource in resources
+
+    def _is_renaming_a_module(self):
+        if isinstance(self.old_pyname.get_object(), pyobjects.AbstractModule):
+            return True
+        return False
+
+    def is_method(self):
+        pyname = self.old_pyname
+        return isinstance(pyname, pynames.DefinedName) and \
+            isinstance(pyname.get_object(), pyobjects.PyFunction) and \
+            isinstance(pyname.get_object().parent, pyobjects.PyClass)
+
+    def _rename_module(self, resource, new_name, changes):
+        if not resource.is_folder():
+            new_name = new_name + '.py'
+        parent_path = resource.parent.path
+        if parent_path == '':
+            new_location = new_name
+        else:
+            new_location = parent_path + '/' + new_name
+        changes.add_change(MoveResource(resource, new_location))
+
+
+class ChangeOccurrences(object):
+    """A class for changing the occurrences of a name in a scope
+
+    This class replaces the occurrences of a name.  Note that it only
+    changes the scope containing the offset passed to the constructor.
+    What's more it does not have any side-effects.  That is for
+    example changing occurrences of a module does not rename the
+    module; it merely replaces the occurrences of that module in a
+    scope with the given expression.  This class is useful for
+    performing many custom refactorings.
+
+    """
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        self.resource = resource
+        self.offset = offset
+        self.old_name = worder.get_name_at(resource, offset)
+        self.pymodule = project.get_pymodule(self.resource)
+        self.old_pyname = evaluate.eval_location(self.pymodule, offset)
+
+    def get_old_name(self):
+        word_finder = worder.Worder(self.resource.read())
+        return word_finder.get_primary_at(self.offset)
+
+    def _get_scope_offset(self):
+        lines = self.pymodule.lines
+        scope = self.pymodule.get_scope().\
+            get_inner_scope_for_line(lines.get_line_number(self.offset))
+        start = lines.get_line_start(scope.get_start())
+        end = lines.get_line_end(scope.get_end())
+        return start, end
+
+    def get_changes(self, new_name, only_calls=False, reads=True, writes=True):
+        changes = ChangeSet('Changing <%s> occurrences to <%s>' %
+                            (self.old_name, new_name))
+        scope_start, scope_end = self._get_scope_offset()
+        finder = occurrences.create_finder(
+            self.project, self.old_name, self.old_pyname,
+            imports=False, only_calls=only_calls)
+        new_contents = rename_in_module(
+            finder, new_name, pymodule=self.pymodule, replace_primary=True,
+            region=(scope_start, scope_end), reads=reads, writes=writes)
+        if new_contents is not None:
+            changes.add_change(ChangeContents(self.resource, new_contents))
+        return changes
+
+
+def rename_in_module(occurrences_finder, new_name, resource=None,
+                     pymodule=None, replace_primary=False, region=None,
+                     reads=True, writes=True):
+    """Returns the changed source or `None` if there is no changes"""
+    if resource is not None:
+        source_code = resource.read()
+    else:
+        source_code = pymodule.source_code
+    change_collector = codeanalyze.ChangeCollector(source_code)
+    for occurrence in occurrences_finder.find_occurrences(resource, pymodule):
+        if replace_primary and occurrence.is_a_fixed_primary():
+            continue
+        if replace_primary:
+            start, end = occurrence.get_primary_range()
+        else:
+            start, end = occurrence.get_word_range()
+        if (not reads and not occurrence.is_written()) or \
+           (not writes and occurrence.is_written()):
+            continue
+        if region is None or region[0] <= start < region[1]:
+            change_collector.add_change(start, end, new_name)
+    return change_collector.get_changed()
+
+
+def _is_local(pyname):
+    module, lineno = pyname.get_definition_location()
+    if lineno is None:
+        return False
+    scope = module.get_scope().get_inner_scope_for_line(lineno)
+    if isinstance(pyname, pynames.DefinedName) and \
+       scope.get_kind() in ('Function', 'Class'):
+        scope = scope.parent
+    return scope.get_kind() == 'Function' and \
+        pyname in scope.get_names().values() and \
+        isinstance(pyname, pynames.AssignedName)
diff --git a/venv/Lib/site-packages/rope/refactor/restructure.py b/venv/Lib/site-packages/rope/refactor/restructure.py
new file mode 100644
index 0000000000000000000000000000000000000000..98a11e3d7741b0311a42a1068003747a1eb01a69
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/restructure.py
@@ -0,0 +1,307 @@
+import warnings
+
+from rope.base import change, taskhandle, builtins, ast, codeanalyze
+from rope.base import libutils
+from rope.refactor import patchedast, similarfinder, sourceutils
+from rope.refactor.importutils import module_imports
+
+
+class Restructure(object):
+    """A class to perform python restructurings
+
+    A restructuring transforms pieces of code matching `pattern` to
+    `goal`.  In the `pattern` wildcards can appear.  Wildcards match
+    some piece of code based on their kind and arguments that are
+    passed to them through `args`.
+
+    `args` is a dictionary of wildcard names to wildcard arguments.
+    If the argument is a tuple, the first item of the tuple is
+    considered to be the name of the wildcard to use; otherwise the
+    "default" wildcard is used.  For getting the list arguments a
+    wildcard supports, see the pydoc of the wildcard.  (see
+    `rope.refactor.wildcard.DefaultWildcard` for the default
+    wildcard.)
+
+    `wildcards` is the list of wildcard types that can appear in
+    `pattern`.  See `rope.refactor.wildcards`.  If a wildcard does not
+    specify its kind (by using a tuple in args), the wildcard named
+    "default" is used.  So there should be a wildcard with "default"
+    name in `wildcards`.
+
+    `imports` is the list of imports that changed modules should
+    import.  Note that rope handles duplicate imports and does not add
+    the import if it already appears.
+
+    Example #1::
+
+      pattern ${pyobject}.get_attribute(${name})
+      goal ${pyobject}[${name}]
+      args pyobject: instance=rope.base.pyobjects.PyObject
+
+    Example #2::
+
+      pattern ${name} in ${pyobject}.get_attributes()
+      goal ${name} in {pyobject}
+      args pyobject: instance=rope.base.pyobjects.PyObject
+
+    Example #3::
+
+      pattern ${pycore}.create_module(${project}.root, ${name})
+      goal generate.create_module(${project}, ${name})
+
+      imports
+       from rope.contrib import generate
+
+      args
+       project: type=rope.base.project.Project
+
+    Example #4::
+
+      pattern ${pow}(${param1}, ${param2})
+      goal ${param1} ** ${param2}
+      args pow: name=mod.pow, exact
+
+    Example #5::
+
+      pattern ${inst}.longtask(${p1}, ${p2})
+      goal
+       ${inst}.subtask1(${p1})
+       ${inst}.subtask2(${p2})
+      args
+       inst: type=mod.A,unsure
+
+    """
+
+    def __init__(self, project, pattern, goal, args=None,
+                 imports=None, wildcards=None):
+        """Construct a restructuring
+
+        See class pydoc for more info about the arguments.
+
+        """
+        self.project = project
+        self.pattern = pattern
+        self.goal = goal
+        self.args = args
+        if self.args is None:
+            self.args = {}
+        self.imports = imports
+        if self.imports is None:
+            self.imports = []
+        self.wildcards = wildcards
+        self.template = similarfinder.CodeTemplate(self.goal)
+
+    def get_changes(self, checks=None, imports=None, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        """Get the changes needed by this restructuring
+
+        `resources` can be a list of `rope.base.resources.File`\s to
+        apply the restructuring on.  If `None`, the restructuring will
+        be applied to all python files.
+
+        `checks` argument has been deprecated.  Use the `args` argument
+        of the constructor.  The usage of::
+
+          strchecks = {'obj1.type': 'mod.A', 'obj2': 'mod.B',
+                       'obj3.object': 'mod.C'}
+          checks = restructuring.make_checks(strchecks)
+
+        can be replaced with::
+
+          args = {'obj1': 'type=mod.A', 'obj2': 'name=mod.B',
+                  'obj3': 'object=mod.C'}
+
+        where obj1, obj2 and obj3 are wildcard names that appear
+        in restructuring pattern.
+
+        """
+        if checks is not None:
+            warnings.warn(
+                'The use of checks parameter is deprecated; '
+                'use the args parameter of the constructor instead.',
+                DeprecationWarning, stacklevel=2)
+            for name, value in checks.items():
+                self.args[name] = similarfinder._pydefined_to_str(value)
+        if imports is not None:
+            warnings.warn(
+                'The use of imports parameter is deprecated; '
+                'use imports parameter of the constructor, instead.',
+                DeprecationWarning, stacklevel=2)
+            self.imports = imports
+        changes = change.ChangeSet('Restructuring <%s> to <%s>' %
+                                   (self.pattern, self.goal))
+        if resources is not None:
+            files = [resource for resource in resources
+                     if libutils.is_python_file(self.project, resource)]
+        else:
+            files = self.project.get_python_files()
+        job_set = task_handle.create_jobset('Collecting Changes', len(files))
+        for resource in files:
+            job_set.started_job(resource.path)
+            pymodule = self.project.get_pymodule(resource)
+            finder = similarfinder.SimilarFinder(pymodule,
+                                                 wildcards=self.wildcards)
+            matches = list(finder.get_matches(self.pattern, self.args))
+            computer = self._compute_changes(matches, pymodule)
+            result = computer.get_changed()
+            if result is not None:
+                imported_source = self._add_imports(resource, result,
+                                                    self.imports)
+                changes.add_change(change.ChangeContents(resource,
+                                                         imported_source))
+            job_set.finished_job()
+        return changes
+
+    def _compute_changes(self, matches, pymodule):
+        return _ChangeComputer(
+            pymodule.source_code, pymodule.get_ast(),
+            pymodule.lines, self.template, matches)
+
+    def _add_imports(self, resource, source, imports):
+        if not imports:
+            return source
+        import_infos = self._get_import_infos(resource, imports)
+        pymodule = libutils.get_string_module(self.project, source, resource)
+        imports = module_imports.ModuleImports(self.project, pymodule)
+        for import_info in import_infos:
+            imports.add_import(import_info)
+        return imports.get_changed_source()
+
+    def _get_import_infos(self, resource, imports):
+        pymodule = libutils.get_string_module(
+            self.project, '\n'.join(imports), resource)
+        imports = module_imports.ModuleImports(self.project, pymodule)
+        return [imports.import_info
+                for imports in imports.imports]
+
+    def make_checks(self, string_checks):
+        """Convert str to str dicts to str to PyObject dicts
+
+        This function is here to ease writing a UI.
+
+        """
+        checks = {}
+        for key, value in string_checks.items():
+            is_pyname = not key.endswith('.object') and \
+                not key.endswith('.type')
+            evaluated = self._evaluate(value, is_pyname=is_pyname)
+            if evaluated is not None:
+                checks[key] = evaluated
+        return checks
+
+    def _evaluate(self, code, is_pyname=True):
+        attributes = code.split('.')
+        pyname = None
+        if attributes[0] in ('__builtin__', '__builtins__'):
+            class _BuiltinsStub(object):
+                def get_attribute(self, name):
+                    return builtins.builtins[name]
+            pyobject = _BuiltinsStub()
+        else:
+            pyobject = self.project.get_module(attributes[0])
+        for attribute in attributes[1:]:
+            pyname = pyobject[attribute]
+            if pyname is None:
+                return None
+            pyobject = pyname.get_object()
+        return pyname if is_pyname else pyobject
+
+
+def replace(code, pattern, goal):
+    """used by other refactorings"""
+    finder = similarfinder.RawSimilarFinder(code)
+    matches = list(finder.get_matches(pattern))
+    ast = patchedast.get_patched_ast(code)
+    lines = codeanalyze.SourceLinesAdapter(code)
+    template = similarfinder.CodeTemplate(goal)
+    computer = _ChangeComputer(code, ast, lines, template, matches)
+    result = computer.get_changed()
+    if result is None:
+        return code
+    return result
+
+
+class _ChangeComputer(object):
+
+    def __init__(self, code, ast, lines, goal, matches):
+        self.source = code
+        self.goal = goal
+        self.matches = matches
+        self.ast = ast
+        self.lines = lines
+        self.matched_asts = {}
+        self._nearest_roots = {}
+        if self._is_expression():
+            for match in self.matches:
+                self.matched_asts[match.ast] = match
+
+    def get_changed(self):
+        if self._is_expression():
+            result = self._get_node_text(self.ast)
+            if result == self.source:
+                return None
+            return result
+        else:
+            collector = codeanalyze.ChangeCollector(self.source)
+            last_end = -1
+            for match in self.matches:
+                start, end = match.get_region()
+                if start < last_end:
+                    if not self._is_expression():
+                        continue
+                last_end = end
+                replacement = self._get_matched_text(match)
+                collector.add_change(start, end, replacement)
+            return collector.get_changed()
+
+    def _is_expression(self):
+        return self.matches and isinstance(self.matches[0],
+                                           similarfinder.ExpressionMatch)
+
+    def _get_matched_text(self, match):
+        mapping = {}
+        for name in self.goal.get_names():
+            node = match.get_ast(name)
+            if node is None:
+                raise similarfinder.BadNameInCheckError(
+                    'Unknown name <%s>' % name)
+            force = self._is_expression() and match.ast == node
+            mapping[name] = self._get_node_text(node, force)
+        unindented = self.goal.substitute(mapping)
+        return self._auto_indent(match.get_region()[0], unindented)
+
+    def _get_node_text(self, node, force=False):
+        if not force and node in self.matched_asts:
+            return self._get_matched_text(self.matched_asts[node])
+        start, end = patchedast.node_region(node)
+        main_text = self.source[start:end]
+        collector = codeanalyze.ChangeCollector(main_text)
+        for node in self._get_nearest_roots(node):
+            sub_start, sub_end = patchedast.node_region(node)
+            collector.add_change(sub_start - start, sub_end - start,
+                                 self._get_node_text(node))
+        result = collector.get_changed()
+        if result is None:
+            return main_text
+        return result
+
+    def _auto_indent(self, offset, text):
+        lineno = self.lines.get_line_number(offset)
+        indents = sourceutils.get_indents(self.lines, lineno)
+        result = []
+        for index, line in enumerate(text.splitlines(True)):
+            if index != 0 and line.strip():
+                result.append(' ' * indents)
+            result.append(line)
+        return ''.join(result)
+
+    def _get_nearest_roots(self, node):
+        if node not in self._nearest_roots:
+            result = []
+            for child in ast.get_child_nodes(node):
+                if child in self.matched_asts:
+                    result.append(child)
+                else:
+                    result.extend(self._get_nearest_roots(child))
+            self._nearest_roots[node] = result
+        return self._nearest_roots[node]
diff --git a/venv/Lib/site-packages/rope/refactor/similarfinder.py b/venv/Lib/site-packages/rope/refactor/similarfinder.py
new file mode 100644
index 0000000000000000000000000000000000000000..425f9ed955c27eab2741cfb496f3257747f5bbaf
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/similarfinder.py
@@ -0,0 +1,370 @@
+"""This module can be used for finding similar code"""
+import re
+
+import rope.refactor.wildcards
+from rope.base import libutils
+from rope.base import codeanalyze, exceptions, ast, builtins
+from rope.refactor import (patchedast, wildcards)
+
+from rope.refactor.patchedast import MismatchedTokenError
+
+
+class BadNameInCheckError(exceptions.RefactoringError):
+    pass
+
+
+class SimilarFinder(object):
+    """`SimilarFinder` can be used to find similar pieces of code
+
+    See the notes in the `rope.refactor.restructure` module for more
+    info.
+
+    """
+
+    def __init__(self, pymodule, wildcards=None):
+        """Construct a SimilarFinder"""
+        self.source = pymodule.source_code
+        try:
+            self.raw_finder = RawSimilarFinder(
+                pymodule.source_code, pymodule.get_ast(), self._does_match)
+        except MismatchedTokenError:
+            print("in file %s" % pymodule.resource.path)
+            raise
+        self.pymodule = pymodule
+        if wildcards is None:
+            self.wildcards = {}
+            for wildcard in [rope.refactor.wildcards.
+                             DefaultWildcard(pymodule.pycore.project)]:
+                self.wildcards[wildcard.get_name()] = wildcard
+        else:
+            self.wildcards = wildcards
+
+    def get_matches(self, code, args={}, start=0, end=None):
+        self.args = args
+        if end is None:
+            end = len(self.source)
+        skip_region = None
+        if 'skip' in args.get('', {}):
+            resource, region = args['']['skip']
+            if resource == self.pymodule.get_resource():
+                skip_region = region
+        return self.raw_finder.get_matches(code, start=start, end=end,
+                                           skip=skip_region)
+
+    def get_match_regions(self, *args, **kwds):
+        for match in self.get_matches(*args, **kwds):
+            yield match.get_region()
+
+    def _does_match(self, node, name):
+        arg = self.args.get(name, '')
+        kind = 'default'
+        if isinstance(arg, (tuple, list)):
+            kind = arg[0]
+            arg = arg[1]
+        suspect = wildcards.Suspect(self.pymodule, node, name)
+        return self.wildcards[kind].matches(suspect, arg)
+
+
+class RawSimilarFinder(object):
+    """A class for finding similar expressions and statements"""
+
+    def __init__(self, source, node=None, does_match=None):
+        if node is None:
+            node = ast.parse(source)
+        if does_match is None:
+            self.does_match = self._simple_does_match
+        else:
+            self.does_match = does_match
+        self._init_using_ast(node, source)
+
+    def _simple_does_match(self, node, name):
+        return isinstance(node, (ast.expr, ast.Name))
+
+    def _init_using_ast(self, node, source):
+        self.source = source
+        self._matched_asts = {}
+        if not hasattr(node, 'region'):
+            patchedast.patch_ast(node, source)
+        self.ast = node
+
+    def get_matches(self, code, start=0, end=None, skip=None):
+        """Search for `code` in source and return a list of `Match`\es
+
+        `code` can contain wildcards.  ``${name}`` matches normal
+        names and ``${?name} can match any expression.  You can use
+        `Match.get_ast()` for getting the node that has matched a
+        given pattern.
+
+        """
+        if end is None:
+            end = len(self.source)
+        for match in self._get_matched_asts(code):
+            match_start, match_end = match.get_region()
+            if start <= match_start and match_end <= end:
+                if skip is not None and (skip[0] < match_end and
+                                         skip[1] > match_start):
+                    continue
+                yield match
+
+    def _get_matched_asts(self, code):
+        if code not in self._matched_asts:
+            wanted = self._create_pattern(code)
+            matches = _ASTMatcher(self.ast, wanted,
+                                  self.does_match).find_matches()
+            self._matched_asts[code] = matches
+        return self._matched_asts[code]
+
+    def _create_pattern(self, expression):
+        expression = self._replace_wildcards(expression)
+        node = ast.parse(expression)
+        # Getting Module.Stmt.nodes
+        nodes = node.body
+        if len(nodes) == 1 and isinstance(nodes[0], ast.Expr):
+            # Getting Discard.expr
+            wanted = nodes[0].value
+        else:
+            wanted = nodes
+        return wanted
+
+    def _replace_wildcards(self, expression):
+        ropevar = _RopeVariable()
+        template = CodeTemplate(expression)
+        mapping = {}
+        for name in template.get_names():
+            mapping[name] = ropevar.get_var(name)
+        return template.substitute(mapping)
+
+
+class _ASTMatcher(object):
+
+    def __init__(self, body, pattern, does_match):
+        """Searches the given pattern in the body AST.
+
+        body is an AST node and pattern can be either an AST node or
+        a list of ASTs nodes
+        """
+        self.body = body
+        self.pattern = pattern
+        self.matches = None
+        self.ropevar = _RopeVariable()
+        self.matches_callback = does_match
+
+    def find_matches(self):
+        if self.matches is None:
+            self.matches = []
+            ast.call_for_nodes(self.body, self._check_node, recursive=True)
+        return self.matches
+
+    def _check_node(self, node):
+        if isinstance(self.pattern, list):
+            self._check_statements(node)
+        else:
+            self._check_expression(node)
+
+    def _check_expression(self, node):
+        mapping = {}
+        if self._match_nodes(self.pattern, node, mapping):
+            self.matches.append(ExpressionMatch(node, mapping))
+
+    def _check_statements(self, node):
+        for child in ast.get_children(node):
+            if isinstance(child, (list, tuple)):
+                self.__check_stmt_list(child)
+
+    def __check_stmt_list(self, nodes):
+        for index in range(len(nodes)):
+            if len(nodes) - index >= len(self.pattern):
+                current_stmts = nodes[index:index + len(self.pattern)]
+                mapping = {}
+                if self._match_stmts(current_stmts, mapping):
+                    self.matches.append(StatementMatch(current_stmts, mapping))
+
+    def _match_nodes(self, expected, node, mapping):
+        if isinstance(expected, ast.Name):
+            if self.ropevar.is_var(expected.id):
+                return self._match_wildcard(expected, node, mapping)
+        if not isinstance(expected, ast.AST):
+            return expected == node
+        if expected.__class__ != node.__class__:
+            return False
+
+        children1 = self._get_children(expected)
+        children2 = self._get_children(node)
+        if len(children1) != len(children2):
+            return False
+        for child1, child2 in zip(children1, children2):
+            if isinstance(child1, ast.AST):
+                if not self._match_nodes(child1, child2, mapping):
+                    return False
+            elif isinstance(child1, (list, tuple)):
+                if not isinstance(child2, (list, tuple)) or \
+                   len(child1) != len(child2):
+                    return False
+                for c1, c2 in zip(child1, child2):
+                    if not self._match_nodes(c1, c2, mapping):
+                        return False
+            else:
+                if child1 != child2:
+                    return False
+        return True
+
+    def _get_children(self, node):
+        """Return not `ast.expr_context` children of `node`"""
+        children = ast.get_children(node)
+        return [child for child in children
+                if not isinstance(child, ast.expr_context)]
+
+    def _match_stmts(self, current_stmts, mapping):
+        if len(current_stmts) != len(self.pattern):
+            return False
+        for stmt, expected in zip(current_stmts, self.pattern):
+            if not self._match_nodes(expected, stmt, mapping):
+                return False
+        return True
+
+    def _match_wildcard(self, node1, node2, mapping):
+        name = self.ropevar.get_base(node1.id)
+        if name not in mapping:
+            if self.matches_callback(node2, name):
+                mapping[name] = node2
+                return True
+            return False
+        else:
+            return self._match_nodes(mapping[name], node2, {})
+
+
+class Match(object):
+
+    def __init__(self, mapping):
+        self.mapping = mapping
+
+    def get_region(self):
+        """Returns match region"""
+
+    def get_ast(self, name):
+        """Return the ast node that has matched rope variables"""
+        return self.mapping.get(name, None)
+
+
+class ExpressionMatch(Match):
+
+    def __init__(self, ast, mapping):
+        super(ExpressionMatch, self).__init__(mapping)
+        self.ast = ast
+
+    def get_region(self):
+        return self.ast.region
+
+
+class StatementMatch(Match):
+
+    def __init__(self, ast_list, mapping):
+        super(StatementMatch, self).__init__(mapping)
+        self.ast_list = ast_list
+
+    def get_region(self):
+        return self.ast_list[0].region[0], self.ast_list[-1].region[1]
+
+
+class CodeTemplate(object):
+
+    def __init__(self, template):
+        self.template = template
+        self._find_names()
+
+    def _find_names(self):
+        self.names = {}
+        for match in CodeTemplate._get_pattern().finditer(self.template):
+            if 'name' in match.groupdict() and \
+               match.group('name') is not None:
+                start, end = match.span('name')
+                name = self.template[start + 2:end - 1]
+                if name not in self.names:
+                    self.names[name] = []
+                self.names[name].append((start, end))
+
+    def get_names(self):
+        return self.names.keys()
+
+    def substitute(self, mapping):
+        collector = codeanalyze.ChangeCollector(self.template)
+        for name, occurrences in self.names.items():
+            for region in occurrences:
+                collector.add_change(region[0], region[1], mapping[name])
+        result = collector.get_changed()
+        if result is None:
+            return self.template
+        return result
+
+    _match_pattern = None
+
+    @classmethod
+    def _get_pattern(cls):
+        if cls._match_pattern is None:
+            pattern = codeanalyze.get_comment_pattern() + '|' + \
+                codeanalyze.get_string_pattern() + '|' + \
+                r'(?P<name>\$\{[^\s\$\}]*\})'
+            cls._match_pattern = re.compile(pattern)
+        return cls._match_pattern
+
+
+class _RopeVariable(object):
+    """Transform and identify rope inserted wildcards"""
+
+    _normal_prefix = '__rope__variable_normal_'
+    _any_prefix = '__rope__variable_any_'
+
+    def get_var(self, name):
+        if name.startswith('?'):
+            return self._get_any(name)
+        else:
+            return self._get_normal(name)
+
+    def is_var(self, name):
+        return self._is_normal(name) or self._is_var(name)
+
+    def get_base(self, name):
+        if self._is_normal(name):
+            return name[len(self._normal_prefix):]
+        if self._is_var(name):
+            return '?' + name[len(self._any_prefix):]
+
+    def _get_normal(self, name):
+        return self._normal_prefix + name
+
+    def _get_any(self, name):
+        return self._any_prefix + name[1:]
+
+    def _is_normal(self, name):
+        return name.startswith(self._normal_prefix)
+
+    def _is_var(self, name):
+        return name.startswith(self._any_prefix)
+
+
+def make_pattern(code, variables):
+    variables = set(variables)
+    collector = codeanalyze.ChangeCollector(code)
+
+    def does_match(node, name):
+        return isinstance(node, ast.Name) and node.id == name
+    finder = RawSimilarFinder(code, does_match=does_match)
+    for variable in variables:
+        for match in finder.get_matches('${%s}' % variable):
+            start, end = match.get_region()
+            collector.add_change(start, end, '${%s}' % variable)
+    result = collector.get_changed()
+    return result if result is not None else code
+
+
+def _pydefined_to_str(pydefined):
+    address = []
+    if isinstance(pydefined,
+                  (builtins.BuiltinClass, builtins.BuiltinFunction)):
+        return '__builtins__.' + pydefined.get_name()
+    else:
+        while pydefined.parent is not None:
+            address.insert(0, pydefined.get_name())
+            pydefined = pydefined.parent
+        module_name = libutils.modname(pydefined.resource)
+    return '.'.join(module_name.split('.') + address)
diff --git a/venv/Lib/site-packages/rope/refactor/sourceutils.py b/venv/Lib/site-packages/rope/refactor/sourceutils.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b842906636f5348579f796b40c6dd4a24e3d6d9
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/sourceutils.py
@@ -0,0 +1,91 @@
+from rope.base import codeanalyze
+
+
+def get_indents(lines, lineno):
+    return codeanalyze.count_line_indents(lines.get_line(lineno))
+
+
+def find_minimum_indents(source_code):
+    result = 80
+    lines = source_code.split('\n')
+    for line in lines:
+        if line.strip() == '':
+            continue
+        result = min(result, codeanalyze.count_line_indents(line))
+    return result
+
+
+def indent_lines(source_code, amount):
+    if amount == 0:
+        return source_code
+    lines = source_code.splitlines(True)
+    result = []
+    for l in lines:
+        if l.strip() == '':
+            result.append('\n')
+            continue
+        if amount < 0:
+            indents = codeanalyze.count_line_indents(l)
+            result.append(max(0, indents + amount) * ' ' + l.lstrip())
+        else:
+            result.append(' ' * amount + l)
+    return ''.join(result)
+
+
+def fix_indentation(code, new_indents):
+    """Change the indentation of `code` to `new_indents`"""
+    min_indents = find_minimum_indents(code)
+    return indent_lines(code, new_indents - min_indents)
+
+
+def add_methods(pymodule, class_scope, methods_sources):
+    source_code = pymodule.source_code
+    lines = pymodule.lines
+    insertion_line = class_scope.get_end()
+    if class_scope.get_scopes():
+        insertion_line = class_scope.get_scopes()[-1].get_end()
+    insertion_offset = lines.get_line_end(insertion_line)
+    methods = '\n\n' + '\n\n'.join(methods_sources)
+    indented_methods = fix_indentation(
+        methods, get_indents(lines, class_scope.get_start()) +
+        get_indent(pymodule.pycore.project))
+    result = []
+    result.append(source_code[:insertion_offset])
+    result.append(indented_methods)
+    result.append(source_code[insertion_offset:])
+    return ''.join(result)
+
+
+def get_body(pyfunction):
+    """Return unindented function body"""
+    # FIXME scope = pyfunction.get_scope()
+    pymodule = pyfunction.get_module()
+    start, end = get_body_region(pyfunction)
+    return fix_indentation(pymodule.source_code[start:end], 0)
+
+
+def get_body_region(defined):
+    """Return the start and end offsets of function body"""
+    scope = defined.get_scope()
+    pymodule = defined.get_module()
+    lines = pymodule.lines
+    node = defined.get_ast()
+    start_line = node.lineno
+    if defined.get_doc() is None:
+        start_line = node.body[0].lineno
+    elif len(node.body) > 1:
+        start_line = node.body[1].lineno
+    start = lines.get_line_start(start_line)
+    scope_start = pymodule.logical_lines.logical_line_in(scope.start)
+    if scope_start[1] >= start_line:
+        # a one-liner!
+        # XXX: what if colon appears in a string
+        start = pymodule.source_code.index(':', start) + 1
+        while pymodule.source_code[start].isspace():
+            start += 1
+    end = min(lines.get_line_end(scope.end) + 1, len(pymodule.source_code))
+    return start, end
+
+
+def get_indent(project):
+    return project.prefs.get('indent_size', 4)
diff --git a/venv/Lib/site-packages/rope/refactor/suites.py b/venv/Lib/site-packages/rope/refactor/suites.py
new file mode 100644
index 0000000000000000000000000000000000000000..6878508088a7073d6b658eec25f13f41713600f3
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/suites.py
@@ -0,0 +1,158 @@
+from rope.base import ast
+from rope.base.utils import pycompat
+
+
+def find_visible(node, lines):
+    """Return the line which is visible from all `lines`"""
+    root = ast_suite_tree(node)
+    return find_visible_for_suite(root, lines)
+
+
+def find_visible_for_suite(root, lines):
+    if len(lines) == 1:
+        return lines[0]
+    line1 = lines[0]
+    line2 = find_visible_for_suite(root, lines[1:])
+    suite1 = root.find_suite(line1)
+    suite2 = root.find_suite(line2)
+
+    def valid(suite):
+        return suite is not None and not suite.ignored
+    if valid(suite1) and not valid(suite2):
+        return line1
+    if not valid(suite1) and valid(suite2):
+        return line2
+    if not valid(suite1) and not valid(suite2):
+        return None
+    while suite1 != suite2 and suite1.parent != suite2.parent:
+        if suite1._get_level() < suite2._get_level():
+            line2 = suite2.get_start()
+            suite2 = suite2.parent
+        elif suite1._get_level() > suite2._get_level():
+            line1 = suite1.get_start()
+            suite1 = suite1.parent
+        else:
+            line1 = suite1.get_start()
+            line2 = suite2.get_start()
+            suite1 = suite1.parent
+            suite2 = suite2.parent
+    if suite1 == suite2:
+        return min(line1, line2)
+    return min(suite1.get_start(), suite2.get_start())
+
+
+def ast_suite_tree(node):
+    if hasattr(node, 'lineno'):
+        lineno = node.lineno
+    else:
+        lineno = 1
+    return Suite(node.body, lineno)
+
+
+class Suite(object):
+
+    def __init__(self, child_nodes, lineno, parent=None, ignored=False):
+        self.parent = parent
+        self.lineno = lineno
+        self.child_nodes = child_nodes
+        self._children = None
+        self.ignored = ignored
+
+    def get_start(self):
+        if self.parent is None:
+            if self.child_nodes:
+                return self.local_start()
+            else:
+                return 1
+        return self.lineno
+
+    def get_children(self):
+        if self._children is None:
+            walker = _SuiteWalker(self)
+            for child in self.child_nodes:
+                ast.walk(child, walker)
+            self._children = walker.suites
+        return self._children
+
+    def local_start(self):
+        return self.child_nodes[0].lineno
+
+    def local_end(self):
+        end = self.child_nodes[-1].lineno
+        if self.get_children():
+            end = max(end, self.get_children()[-1].local_end())
+        return end
+
+    def find_suite(self, line):
+        if line is None:
+            return None
+        for child in self.get_children():
+            if child.local_start() <= line <= child.local_end():
+                return child.find_suite(line)
+        return self
+
+    def _get_level(self):
+        if self.parent is None:
+            return 0
+        return self.parent._get_level() + 1
+
+
+class _SuiteWalker(object):
+
+    def __init__(self, suite):
+        self.suite = suite
+        self.suites = []
+
+    def _If(self, node):
+        self._add_if_like_node(node)
+
+    def _For(self, node):
+        self._add_if_like_node(node)
+
+    def _While(self, node):
+        self._add_if_like_node(node)
+
+    def _With(self, node):
+        self.suites.append(Suite(node.body, node.lineno, self.suite))
+
+    def _TryFinally(self, node):
+        proceed_to_except_handler = False
+        if len(node.finalbody) == 1:
+            if pycompat.PY2:
+                proceed_to_except_handler = isinstance(node.body[0], ast.TryExcept)
+            elif pycompat.PY3:
+                try:
+                    proceed_to_except_handler = isinstance(node.handlers[0], ast.ExceptHandler)
+                except IndexError:
+                    pass
+        if proceed_to_except_handler:
+            self._TryExcept(node if pycompat.PY3 else node.body[0])
+        else:
+            self.suites.append(Suite(node.body, node.lineno, self.suite))
+        self.suites.append(Suite(node.finalbody, node.lineno, self.suite))
+
+    def _Try(self, node):
+        if len(node.finalbody) == 1:
+            self._TryFinally(node)
+        else:
+            self._TryExcept(node)
+
+    def _TryExcept(self, node):
+        self.suites.append(Suite(node.body, node.lineno, self.suite))
+        for handler in node.handlers:
+            self.suites.append(Suite(handler.body, node.lineno, self.suite))
+        if node.orelse:
+            self.suites.append(Suite(node.orelse, node.lineno, self.suite))
+
+    def _add_if_like_node(self, node):
+        self.suites.append(Suite(node.body, node.lineno, self.suite))
+        if node.orelse:
+            self.suites.append(Suite(node.orelse, node.lineno, self.suite))
+
+    def _FunctionDef(self, node):
+        self.suites.append(Suite(node.body, node.lineno,
+                                 self.suite, ignored=True))
+
+    def _ClassDef(self, node):
+        self.suites.append(Suite(node.body, node.lineno,
+                                 self.suite, ignored=True))
diff --git a/venv/Lib/site-packages/rope/refactor/topackage.py b/venv/Lib/site-packages/rope/refactor/topackage.py
new file mode 100644
index 0000000000000000000000000000000000000000..f36a6d528865f589ff22c80493db19d1971b1cb7
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/topackage.py
@@ -0,0 +1,32 @@
+import rope.refactor.importutils
+from rope.base.change import ChangeSet, ChangeContents, MoveResource, \
+    CreateFolder
+
+
+class ModuleToPackage(object):
+
+    def __init__(self, project, resource):
+        self.project = project
+        self.resource = resource
+
+    def get_changes(self):
+        changes = ChangeSet('Transform <%s> module to package' %
+                            self.resource.path)
+        new_content = self._transform_relatives_to_absolute(self.resource)
+        if new_content is not None:
+            changes.add_change(ChangeContents(self.resource, new_content))
+        parent = self.resource.parent
+        name = self.resource.name[:-3]
+        changes.add_change(CreateFolder(parent, name))
+        parent_path = parent.path + '/'
+        if not parent.path:
+            parent_path = ''
+        new_path = parent_path + '%s/__init__.py' % name
+        if self.resource.project == self.project:
+            changes.add_change(MoveResource(self.resource, new_path))
+        return changes
+
+    def _transform_relatives_to_absolute(self, resource):
+        pymodule = self.project.get_pymodule(resource)
+        import_tools = rope.refactor.importutils.ImportTools(self.project)
+        return import_tools.relatives_to_absolutes(pymodule)
diff --git a/venv/Lib/site-packages/rope/refactor/usefunction.py b/venv/Lib/site-packages/rope/refactor/usefunction.py
new file mode 100644
index 0000000000000000000000000000000000000000..85896a98f7750150fea34e9bd9049e88f2b601be
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/usefunction.py
@@ -0,0 +1,174 @@
+from rope.base import (change, taskhandle, evaluate,
+                       exceptions, pyobjects, pynames, ast)
+from rope.base import libutils
+from rope.refactor import restructure, sourceutils, similarfinder
+
+
+class UseFunction(object):
+    """Try to use a function wherever possible"""
+
+    def __init__(self, project, resource, offset):
+        self.project = project
+        self.offset = offset
+        this_pymodule = project.get_pymodule(resource)
+        pyname = evaluate.eval_location(this_pymodule, offset)
+        if pyname is None:
+            raise exceptions.RefactoringError('Unresolvable name selected')
+        self.pyfunction = pyname.get_object()
+        if not isinstance(self.pyfunction, pyobjects.PyFunction) or \
+           not isinstance(self.pyfunction.parent, pyobjects.PyModule):
+            raise exceptions.RefactoringError(
+                'Use function works for global functions, only.')
+        self.resource = self.pyfunction.get_module().get_resource()
+        self._check_returns()
+
+    def _check_returns(self):
+        node = self.pyfunction.get_ast()
+        if _yield_count(node):
+            raise exceptions.RefactoringError('Use function should not '
+                                              'be used on generators.')
+        returns = _return_count(node)
+        if returns > 1:
+            raise exceptions.RefactoringError('usefunction: Function has more '
+                                              'than one return statement.')
+        if returns == 1 and not _returns_last(node):
+            raise exceptions.RefactoringError('usefunction: return should '
+                                              'be the last statement.')
+
+    def get_changes(self, resources=None,
+                    task_handle=taskhandle.NullTaskHandle()):
+        if resources is None:
+            resources = self.project.get_python_files()
+        changes = change.ChangeSet('Using function <%s>' %
+                                   self.pyfunction.get_name())
+        if self.resource in resources:
+            newresources = list(resources)
+            newresources.remove(self.resource)
+        for c in self._restructure(newresources, task_handle).changes:
+            changes.add_change(c)
+        if self.resource in resources:
+            for c in self._restructure([self.resource], task_handle,
+                                       others=False).changes:
+                changes.add_change(c)
+        return changes
+
+    def get_function_name(self):
+        return self.pyfunction.get_name()
+
+    def _restructure(self, resources, task_handle, others=True):
+        pattern = self._make_pattern()
+        goal = self._make_goal(import_=others)
+        imports = None
+        if others:
+            imports = ['import %s' % self._module_name()]
+
+        body_region = sourceutils.get_body_region(self.pyfunction)
+        args_value = {'skip': (self.resource, body_region)}
+        args = {'': args_value}
+
+        restructuring = restructure.Restructure(
+            self.project, pattern, goal, args=args, imports=imports)
+        return restructuring.get_changes(resources=resources,
+                                         task_handle=task_handle)
+
+    def _find_temps(self):
+        return find_temps(self.project, self._get_body())
+
+    def _module_name(self):
+        return libutils.modname(self.resource)
+
+    def _make_pattern(self):
+        params = self.pyfunction.get_param_names()
+        body = self._get_body()
+        body = restructure.replace(body, 'return', 'pass')
+        wildcards = list(params)
+        wildcards.extend(self._find_temps())
+        if self._does_return():
+            if self._is_expression():
+                replacement = '${%s}' % self._rope_returned
+            else:
+                replacement = '%s = ${%s}' % (self._rope_result,
+                                              self._rope_returned)
+            body = restructure.replace(
+                body, 'return ${%s}' % self._rope_returned,
+                replacement)
+            wildcards.append(self._rope_result)
+        return similarfinder.make_pattern(body, wildcards)
+
+    def _get_body(self):
+        return sourceutils.get_body(self.pyfunction)
+
+    def _make_goal(self, import_=False):
+        params = self.pyfunction.get_param_names()
+        function_name = self.pyfunction.get_name()
+        if import_:
+            function_name = self._module_name() + '.' + function_name
+        goal = '%s(%s)' % (function_name,
+                           ', ' .join(('${%s}' % p) for p in params))
+        if self._does_return() and not self._is_expression():
+            goal = '${%s} = %s' % (self._rope_result, goal)
+        return goal
+
+    def _does_return(self):
+        body = self._get_body()
+        removed_return = restructure.replace(body, 'return ${result}', '')
+        return removed_return != body
+
+    def _is_expression(self):
+        return len(self.pyfunction.get_ast().body) == 1
+
+    _rope_result = '_rope__result'
+    _rope_returned = '_rope__returned'
+
+
+def find_temps(project, code):
+    code = 'def f():\n' + sourceutils.indent_lines(code, 4)
+    pymodule = libutils.get_string_module(project, code)
+    result = []
+    function_scope = pymodule.get_scope().get_scopes()[0]
+    for name, pyname in function_scope.get_names().items():
+        if isinstance(pyname, pynames.AssignedName):
+            result.append(name)
+    return result
+
+
+def _returns_last(node):
+    return node.body and isinstance(node.body[-1], ast.Return)
+
+
+def _yield_count(node):
+    visitor = _ReturnOrYieldFinder()
+    visitor.start_walking(node)
+    return visitor.yields
+
+
+def _return_count(node):
+    visitor = _ReturnOrYieldFinder()
+    visitor.start_walking(node)
+    return visitor.returns
+
+
+class _ReturnOrYieldFinder(object):
+
+    def __init__(self):
+        self.returns = 0
+        self.yields = 0
+
+    def _Return(self, node):
+        self.returns += 1
+
+    def _Yield(self, node):
+        self.yields += 1
+
+    def _FunctionDef(self, node):
+        pass
+
+    def _ClassDef(self, node):
+        pass
+
+    def start_walking(self, node):
+        nodes = [node]
+        if isinstance(node, ast.FunctionDef):
+            nodes = ast.get_child_nodes(node)
+        for child in nodes:
+            ast.walk(child, self)
diff --git a/venv/Lib/site-packages/rope/refactor/wildcards.py b/venv/Lib/site-packages/rope/refactor/wildcards.py
new file mode 100644
index 0000000000000000000000000000000000000000..90040c794e261cac5e91dd1380f6d465931ba4a0
--- /dev/null
+++ b/venv/Lib/site-packages/rope/refactor/wildcards.py
@@ -0,0 +1,178 @@
+from rope.base import ast, evaluate, builtins, pyobjects
+from rope.refactor import patchedast, occurrences
+
+
+class Wildcard(object):
+
+    def get_name(self):
+        """Return the name of this wildcard"""
+
+    def matches(self, suspect, arg):
+        """Return `True` if `suspect` matches this wildcard"""
+
+
+class Suspect(object):
+
+    def __init__(self, pymodule, node, name):
+        self.name = name
+        self.pymodule = pymodule
+        self.node = node
+
+
+class DefaultWildcard(object):
+    """The default restructuring wildcard
+
+    The argument passed to this wildcard is in the
+    ``key1=value1,key2=value2,...`` format.  Possible keys are:
+
+    * name - for checking the reference
+    * type - for checking the type
+    * object - for checking the object
+    * instance - for checking types but similar to builtin isinstance
+    * exact - matching only occurrences with the same name as the wildcard
+    * unsure - matching unsure occurrences
+
+    """
+
+    def __init__(self, project):
+        self.project = project
+
+    def get_name(self):
+        return 'default'
+
+    def matches(self, suspect, arg=''):
+        args = parse_arg(arg)
+
+        if not self._check_exact(args, suspect):
+            return False
+        if not self._check_object(args, suspect):
+            return False
+        return True
+
+    def _check_object(self, args, suspect):
+        kind = None
+        expected = None
+        unsure = args.get('unsure', False)
+        for check in ['name', 'object', 'type', 'instance']:
+            if check in args:
+                kind = check
+                expected = args[check]
+            if expected is not None:
+                checker = _CheckObject(self.project, expected,
+                                       kind, unsure=unsure)
+                return checker(suspect.pymodule, suspect.node)
+        return True
+
+    def _check_exact(self, args, suspect):
+        node = suspect.node
+        if args.get('exact'):
+            if not isinstance(node, ast.Name) or not node.id == suspect.name:
+                return False
+        else:
+            if not isinstance(node, ast.expr):
+                return False
+        return True
+
+
+def parse_arg(arg):
+    if isinstance(arg, dict):
+        return arg
+    result = {}
+    tokens = arg.split(',')
+    for token in tokens:
+        if '=' in token:
+            parts = token.split('=', 1)
+            result[parts[0].strip()] = parts[1].strip()
+        else:
+            result[token.strip()] = True
+    return result
+
+
+class _CheckObject(object):
+
+    def __init__(self, project, expected, kind='object', unsure=False):
+        self.project = project
+        self.kind = kind
+        self.unsure = unsure
+        self.expected = self._evaluate(expected)
+
+    def __call__(self, pymodule, node):
+        pyname = self._evaluate_node(pymodule, node)
+        if pyname is None or self.expected is None:
+            return self.unsure
+        if self._unsure_pyname(pyname, unbound=self.kind == 'name'):
+            return True
+        if self.kind == 'name':
+            return self._same_pyname(self.expected, pyname)
+        else:
+            pyobject = pyname.get_object()
+            if self.kind == 'object':
+                objects = [pyobject]
+            if self.kind == 'type':
+                objects = [pyobject.get_type()]
+            if self.kind == 'instance':
+                objects = [pyobject]
+                objects.extend(self._get_super_classes(pyobject))
+                objects.extend(self._get_super_classes(pyobject.get_type()))
+            for pyobject in objects:
+                if self._same_pyobject(self.expected.get_object(), pyobject):
+                    return True
+            return False
+
+    def _get_super_classes(self, pyobject):
+        result = []
+        if isinstance(pyobject, pyobjects.AbstractClass):
+            for superclass in pyobject.get_superclasses():
+                result.append(superclass)
+                result.extend(self._get_super_classes(superclass))
+        return result
+
+    def _same_pyobject(self, expected, pyobject):
+        return expected == pyobject
+
+    def _same_pyname(self, expected, pyname):
+        return occurrences.same_pyname(expected, pyname)
+
+    def _unsure_pyname(self, pyname, unbound=True):
+        return self.unsure and occurrences.unsure_pyname(pyname, unbound)
+
+    def _split_name(self, name):
+        parts = name.split('.')
+        expression, kind = parts[0], parts[-1]
+        if len(parts) == 1:
+            kind = 'name'
+        return expression, kind
+
+    def _evaluate_node(self, pymodule, node):
+        scope = pymodule.get_scope().get_inner_scope_for_line(node.lineno)
+        expression = node
+        if isinstance(expression, ast.Name) and \
+           isinstance(expression.ctx, ast.Store):
+            start, end = patchedast.node_region(expression)
+            text = pymodule.source_code[start:end]
+            return evaluate.eval_str(scope, text)
+        else:
+            return evaluate.eval_node(scope, expression)
+
+    def _evaluate(self, code):
+        attributes = code.split('.')
+        pyname = None
+        if attributes[0] in ('__builtin__', '__builtins__'):
+            class _BuiltinsStub(object):
+                def get_attribute(self, name):
+                    return builtins.builtins[name]
+
+                def __getitem__(self, name):
+                    return builtins.builtins[name]
+
+                def __contains__(self, name):
+                    return name in builtins.builtins
+            pyobject = _BuiltinsStub()
+        else:
+            pyobject = self.project.get_module(attributes[0])
+        for attribute in attributes[1:]:
+            pyname = pyobject[attribute]
+            if pyname is None:
+                return None
+            pyobject = pyname.get_object()
+        return pyname
diff --git a/venv/Lib/site-packages/xgboost/__pycache__/sklearn.cpython-37.pyc b/venv/Lib/site-packages/xgboost/__pycache__/sklearn.cpython-37.pyc
index e3553177da796b7342b9f98ec87ec5f3dda20a09..a399c7371452148484f14598b03d2d630f91a0c8 100644
Binary files a/venv/Lib/site-packages/xgboost/__pycache__/sklearn.cpython-37.pyc and b/venv/Lib/site-packages/xgboost/__pycache__/sklearn.cpython-37.pyc differ
diff --git a/xgb_sample_submission.csv b/xgb_sample_submission.csv
index dda251dd5d660b0f8d5a158946c3aec42fcf6439..7acb28f0fe964797404daeb72a7611938b240d82 100644
--- a/xgb_sample_submission.csv
+++ b/xgb_sample_submission.csv
@@ -117,7 +117,7 @@ Id,label
 115,3
 116,2
 117,2
-118,0
+118,3
 119,0
 120,3
 121,2
@@ -206,7 +206,7 @@ Id,label
 204,0
 205,3
 206,2
-207,0
+207,3
 208,2
 209,0
 210,0
@@ -271,7 +271,7 @@ Id,label
 269,2
 270,0
 271,0
-272,0
+272,3
 273,0
 274,0
 275,0
@@ -320,7 +320,7 @@ Id,label
 318,0
 319,0
 320,3
-321,1
+321,3
 322,3
 323,0
 324,3
@@ -338,14 +338,14 @@ Id,label
 336,2
 337,1
 338,1
-339,0
+339,3
 340,0
 341,0
 342,1
 343,0
 344,0
 345,0
-346,0
+346,3
 347,0
 348,3
 349,3
@@ -414,7 +414,7 @@ Id,label
 412,3
 413,0
 414,3
-415,3
+415,0
 416,3
 417,0
 418,3
@@ -481,7 +481,7 @@ Id,label
 479,2
 480,0
 481,0
-482,0
+482,3
 483,2
 484,3
 485,3
@@ -541,7 +541,7 @@ Id,label
 539,0
 540,1
 541,3
-542,0
+542,3
 543,3
 544,0
 545,2
@@ -643,7 +643,7 @@ Id,label
 641,2
 642,0
 643,0
-644,0
+644,3
 645,3
 646,0
 647,2
@@ -696,7 +696,7 @@ Id,label
 694,2
 695,3
 696,0
-697,3
+697,0
 698,1
 699,0
 700,0
@@ -709,7 +709,7 @@ Id,label
 707,2
 708,2
 709,0
-710,0
+710,3
 711,1
 712,0
 713,0
@@ -761,7 +761,7 @@ Id,label
 759,1
 760,3
 761,3
-762,0
+762,3
 763,1
 764,3
 765,3
@@ -804,7 +804,7 @@ Id,label
 802,2
 803,2
 804,3
-805,0
+805,3
 806,0
 807,2
 808,2
@@ -877,7 +877,7 @@ Id,label
 875,1
 876,3
 877,0
-878,0
+878,3
 879,1
 880,3
 881,0
@@ -1039,7 +1039,7 @@ Id,label
 1037,0
 1038,1
 1039,1
-1040,3
+1040,0
 1041,2
 1042,3
 1043,1
@@ -1072,7 +1072,7 @@ Id,label
 1070,0
 1071,0
 1072,1
-1073,0
+1073,3
 1074,2
 1075,2
 1076,0
@@ -1099,8 +1099,8 @@ Id,label
 1097,0
 1098,1
 1099,0
-1100,0
-1101,0
+1100,3
+1101,3
 1102,3
 1103,1
 1104,1
@@ -1110,7 +1110,7 @@ Id,label
 1108,2
 1109,3
 1110,1
-1111,0
+1111,3
 1112,0
 1113,0
 1114,0
@@ -1169,7 +1169,7 @@ Id,label
 1167,3
 1168,2
 1169,3
-1170,0
+1170,3
 1171,0
 1172,0
 1173,1
@@ -1202,7 +1202,7 @@ Id,label
 1200,3
 1201,0
 1202,0
-1203,0
+1203,3
 1204,0
 1205,2
 1206,0
@@ -1224,7 +1224,7 @@ Id,label
 1222,0
 1223,3
 1224,2
-1225,0
+1225,3
 1226,2
 1227,0
 1228,3
@@ -1308,7 +1308,7 @@ Id,label
 1306,2
 1307,0
 1308,0
-1309,0
+1309,3
 1310,1
 1311,3
 1312,3
@@ -1405,7 +1405,7 @@ Id,label
 1403,2
 1404,0
 1405,3
-1406,0
+1406,3
 1407,2
 1408,0
 1409,0
@@ -1559,12 +1559,12 @@ Id,label
 1557,2
 1558,1
 1559,0
-1560,0
+1560,3
 1561,2
 1562,0
 1563,0
 1564,2
-1565,1
+1565,3
 1566,0
 1567,3
 1568,0
@@ -1757,7 +1757,7 @@ Id,label
 1755,2
 1756,0
 1757,3
-1758,0
+1758,3
 1759,1
 1760,0
 1761,0
@@ -1818,8 +1818,8 @@ Id,label
 1816,3
 1817,0
 1818,0
-1819,0
-1820,3
+1819,2
+1820,0
 1821,0
 1822,0
 1823,0
@@ -1963,7 +1963,7 @@ Id,label
 1961,1
 1962,2
 1963,2
-1964,0
+1964,3
 1965,0
 1966,2
 1967,2
@@ -1990,13 +1990,13 @@ Id,label
 1988,3
 1989,0
 1990,0
-1991,0
+1991,3
 1992,0
 1993,2
 1994,0
 1995,0
 1996,3
-1997,2
+1997,0
 1998,2
 1999,0
 2000,0
@@ -2106,7 +2106,7 @@ Id,label
 2104,2
 2105,0
 2106,0
-2107,0
+2107,2
 2108,0
 2109,2
 2110,2
@@ -2231,7 +2231,7 @@ Id,label
 2229,0
 2230,2
 2231,0
-2232,0
+2232,3
 2233,3
 2234,0
 2235,0
@@ -2439,7 +2439,7 @@ Id,label
 2437,3
 2438,2
 2439,0
-2440,0
+2440,3
 2441,0
 2442,2
 2443,3
@@ -2502,7 +2502,7 @@ Id,label
 2500,2
 2501,3
 2502,3
-2503,1
+2503,3
 2504,2
 2505,0
 2506,0
@@ -2516,7 +2516,7 @@ Id,label
 2514,1
 2515,0
 2516,3
-2517,0
+2517,3
 2518,1
 2519,1
 2520,0
@@ -2698,7 +2698,7 @@ Id,label
 2696,3
 2697,2
 2698,0
-2699,0
+2699,3
 2700,2
 2701,3
 2702,0
@@ -2803,7 +2803,7 @@ Id,label
 2801,0
 2802,0
 2803,0
-2804,0
+2804,3
 2805,3
 2806,0
 2807,3
@@ -2836,7 +2836,7 @@ Id,label
 2834,2
 2835,0
 2836,0
-2837,3
+2837,0
 2838,2
 2839,2
 2840,2
@@ -2942,7 +2942,7 @@ Id,label
 2940,2
 2941,3
 2942,0
-2943,0
+2943,3
 2944,1
 2945,0
 2946,0
@@ -3037,7 +3037,7 @@ Id,label
 3035,3
 3036,3
 3037,0
-3038,0
+3038,3
 3039,0
 3040,3
 3041,1
@@ -3055,7 +3055,7 @@ Id,label
 3053,1
 3054,0
 3055,2
-3056,0
+3056,3
 3057,2
 3058,0
 3059,3
@@ -3070,7 +3070,7 @@ Id,label
 3068,1
 3069,0
 3070,0
-3071,0
+3071,3
 3072,3
 3073,3
 3074,3
@@ -3230,8 +3230,8 @@ Id,label
 3228,0
 3229,2
 3230,0
-3231,3
-3232,0
+3231,0
+3232,3
 3233,1
 3234,3
 3235,0
@@ -3243,7 +3243,7 @@ Id,label
 3241,2
 3242,3
 3243,0
-3244,0
+3244,3
 3245,1
 3246,2
 3247,0
@@ -3277,7 +3277,7 @@ Id,label
 3275,0
 3276,0
 3277,0
-3278,0
+3278,3
 3279,0
 3280,2
 3281,1
@@ -3339,7 +3339,7 @@ Id,label
 3337,0
 3338,1
 3339,2
-3340,0
+3340,3
 3341,0
 3342,0
 3343,0
@@ -3360,7 +3360,7 @@ Id,label
 3358,0
 3359,3
 3360,0
-3361,0
+3361,3
 3362,0
 3363,3
 3364,0
@@ -3388,7 +3388,7 @@ Id,label
 3386,0
 3387,2
 3388,1
-3389,0
+3389,3
 3390,0
 3391,0
 3392,3
@@ -3450,7 +3450,7 @@ Id,label
 3448,1
 3449,3
 3450,0
-3451,3
+3451,0
 3452,3
 3453,0
 3454,0
@@ -3555,7 +3555,7 @@ Id,label
 3553,3
 3554,0
 3555,2
-3556,0
+3556,3
 3557,2
 3558,3
 3559,0
@@ -3572,7 +3572,7 @@ Id,label
 3570,2
 3571,2
 3572,0
-3573,0
+3573,3
 3574,0
 3575,0
 3576,0
@@ -3604,7 +3604,7 @@ Id,label
 3602,3
 3603,2
 3604,0
-3605,0
+3605,3
 3606,2
 3607,0
 3608,0
@@ -3623,7 +3623,7 @@ Id,label
 3621,1
 3622,3
 3623,1
-3624,3
+3624,0
 3625,3
 3626,3
 3627,3
@@ -3753,7 +3753,7 @@ Id,label
 3751,0
 3752,3
 3753,2
-3754,0
+3754,3
 3755,2
 3756,3
 3757,0
@@ -3778,7 +3778,7 @@ Id,label
 3776,0
 3777,0
 3778,0
-3779,1
+3779,0
 3780,1
 3781,0
 3782,0
@@ -3808,7 +3808,7 @@ Id,label
 3806,2
 3807,0
 3808,3
-3809,3
+3809,0
 3810,2
 3811,3
 3812,2
@@ -3923,7 +3923,7 @@ Id,label
 3921,2
 3922,1
 3923,1
-3924,0
+3924,3
 3925,0
 3926,1
 3927,2
@@ -3961,7 +3961,7 @@ Id,label
 3959,0
 3960,0
 3961,0
-3962,0
+3962,3
 3963,2
 3964,2
 3965,3
@@ -3976,7 +3976,7 @@ Id,label
 3974,3
 3975,0
 3976,0
-3977,3
+3977,0
 3978,3
 3979,1
 3980,3
@@ -4079,7 +4079,7 @@ Id,label
 4077,0
 4078,0
 4079,2
-4080,0
+4080,3
 4081,1
 4082,0
 4083,0
@@ -4126,7 +4126,7 @@ Id,label
 4124,0
 4125,2
 4126,2
-4127,0
+4127,3
 4128,0
 4129,3
 4130,0
@@ -4160,7 +4160,7 @@ Id,label
 4158,1
 4159,2
 4160,3
-4161,0
+4161,3
 4162,2
 4163,2
 4164,0
@@ -4174,7 +4174,7 @@ Id,label
 4172,2
 4173,0
 4174,0
-4175,0
+4175,3
 4176,1
 4177,0
 4178,2
@@ -4218,7 +4218,7 @@ Id,label
 4216,1
 4217,0
 4218,0
-4219,0
+4219,3
 4220,0
 4221,3
 4222,2
@@ -4244,7 +4244,7 @@ Id,label
 4242,0
 4243,0
 4244,0
-4245,3
+4245,0
 4246,0
 4247,1
 4248,3
@@ -4314,7 +4314,7 @@ Id,label
 4312,0
 4313,3
 4314,2
-4315,0
+4315,3
 4316,2
 4317,3
 4318,0
@@ -4441,7 +4441,7 @@ Id,label
 4439,0
 4440,0
 4441,2
-4442,0
+4442,3
 4443,2
 4444,3
 4445,0
@@ -4473,13 +4473,13 @@ Id,label
 4471,0
 4472,1
 4473,1
-4474,0
+4474,3
 4475,1
 4476,0
 4477,2
 4478,3
 4479,0
-4480,3
+4480,0
 4481,3
 4482,1
 4483,3
@@ -4496,8 +4496,8 @@ Id,label
 4494,1
 4495,0
 4496,3
-4497,0
-4498,3
+4497,3
+4498,0
 4499,0
 4500,0
 4501,0
@@ -4522,7 +4522,7 @@ Id,label
 4520,0
 4521,2
 4522,2
-4523,0
+4523,3
 4524,2
 4525,0
 4526,3
@@ -4652,7 +4652,7 @@ Id,label
 4650,3
 4651,0
 4652,0
-4653,0
+4653,3
 4654,0
 4655,0
 4656,3
@@ -4682,7 +4682,7 @@ Id,label
 4680,2
 4681,0
 4682,3
-4683,0
+4683,3
 4684,0
 4685,2
 4686,0
@@ -4750,7 +4750,7 @@ Id,label
 4748,2
 4749,0
 4750,2
-4751,3
+4751,0
 4752,1
 4753,1
 4754,0
@@ -4844,7 +4844,7 @@ Id,label
 4842,3
 4843,0
 4844,0
-4845,0
+4845,3
 4846,0
 4847,0
 4848,3
@@ -4909,7 +4909,7 @@ Id,label
 4907,0
 4908,0
 4909,0
-4910,0
+4910,3
 4911,1
 4912,2
 4913,3
@@ -4998,12 +4998,12 @@ Id,label
 4996,3
 4997,0
 4998,2
-4999,0
+4999,3
 5000,0
 5001,0
 5002,0
 5003,1
-5004,0
+5004,3
 5005,0
 5006,0
 5007,0
@@ -5110,7 +5110,7 @@ Id,label
 5108,3
 5109,0
 5110,0
-5111,0
+5111,3
 5112,2
 5113,1
 5114,3
@@ -5122,12 +5122,12 @@ Id,label
 5120,2
 5121,2
 5122,1
-5123,0
+5123,3
 5124,0
 5125,0
 5126,0
 5127,2
-5128,3
+5128,0
 5129,0
 5130,0
 5131,1
@@ -5180,7 +5180,7 @@ Id,label
 5178,2
 5179,1
 5180,3
-5181,0
+5181,3
 5182,2
 5183,1
 5184,1
@@ -5202,7 +5202,7 @@ Id,label
 5200,3
 5201,0
 5202,0
-5203,3
+5203,0
 5204,3
 5205,1
 5206,2
@@ -5255,10 +5255,10 @@ Id,label
 5253,3
 5254,2
 5255,0
-5256,0
+5256,2
 5257,0
 5258,0
-5259,0
+5259,3
 5260,3
 5261,2
 5262,0
@@ -5309,7 +5309,7 @@ Id,label
 5307,3
 5308,0
 5309,0
-5310,0
+5310,3
 5311,2
 5312,0
 5313,0
@@ -5354,7 +5354,7 @@ Id,label
 5352,0
 5353,3
 5354,3
-5355,0
+5355,3
 5356,3
 5357,2
 5358,3
@@ -5453,7 +5453,7 @@ Id,label
 5451,2
 5452,3
 5453,1
-5454,3
+5454,0
 5455,0
 5456,0
 5457,0
@@ -5520,7 +5520,7 @@ Id,label
 5518,2
 5519,0
 5520,0
-5521,3
+5521,0
 5522,0
 5523,3
 5524,3
@@ -5547,7 +5547,7 @@ Id,label
 5545,0
 5546,0
 5547,3
-5548,0
+5548,3
 5549,0
 5550,3
 5551,0
@@ -5599,7 +5599,7 @@ Id,label
 5597,0
 5598,0
 5599,1
-5600,3
+5600,0
 5601,1
 5602,2
 5603,3
@@ -5632,7 +5632,7 @@ Id,label
 5630,2
 5631,2
 5632,0
-5633,0
+5633,3
 5634,2
 5635,0
 5636,0
@@ -5660,7 +5660,7 @@ Id,label
 5658,3
 5659,0
 5660,0
-5661,1
+5661,0
 5662,3
 5663,2
 5664,3
@@ -5700,7 +5700,7 @@ Id,label
 5698,3
 5699,0
 5700,2
-5701,0
+5701,3
 5702,2
 5703,3
 5704,0
@@ -5848,7 +5848,7 @@ Id,label
 5846,0
 5847,2
 5848,1
-5849,0
+5849,3
 5850,1
 5851,1
 5852,2
@@ -5958,7 +5958,7 @@ Id,label
 5956,3
 5957,1
 5958,0
-5959,3
+5959,0
 5960,3
 5961,0
 5962,2
@@ -5985,7 +5985,7 @@ Id,label
 5983,3
 5984,3
 5985,2
-5986,0
+5986,3
 5987,1
 5988,2
 5989,0
@@ -6035,7 +6035,7 @@ Id,label
 6033,3
 6034,0
 6035,2
-6036,0
+6036,3
 6037,0
 6038,2
 6039,0
@@ -6133,7 +6133,7 @@ Id,label
 6131,0
 6132,0
 6133,0
-6134,0
+6134,3
 6135,0
 6136,0
 6137,3
@@ -6238,7 +6238,7 @@ Id,label
 6236,0
 6237,0
 6238,0
-6239,0
+6239,3
 6240,0
 6241,0
 6242,0
@@ -6289,7 +6289,7 @@ Id,label
 6287,3
 6288,2
 6289,1
-6290,0
+6290,3
 6291,3
 6292,0
 6293,0
@@ -6315,13 +6315,13 @@ Id,label
 6313,0
 6314,3
 6315,3
-6316,0
+6316,3
 6317,2
 6318,3
 6319,3
 6320,3
 6321,3
-6322,0
+6322,3
 6323,2
 6324,2
 6325,0
@@ -6364,7 +6364,7 @@ Id,label
 6362,3
 6363,2
 6364,3
-6365,3
+6365,0
 6366,2
 6367,1
 6368,0
@@ -6453,7 +6453,7 @@ Id,label
 6451,0
 6452,3
 6453,0
-6454,0
+6454,3
 6455,0
 6456,0
 6457,0
@@ -6541,7 +6541,7 @@ Id,label
 6539,2
 6540,0
 6541,0
-6542,3
+6542,0
 6543,0
 6544,0
 6545,1
@@ -6622,14 +6622,14 @@ Id,label
 6620,0
 6621,0
 6622,3
-6623,0
+6623,3
 6624,0
 6625,1
 6626,0
 6627,3
 6628,0
-6629,3
-6630,0
+6629,0
+6630,3
 6631,3
 6632,2
 6633,2
@@ -6653,7 +6653,7 @@ Id,label
 6651,0
 6652,0
 6653,3
-6654,0
+6654,3
 6655,0
 6656,0
 6657,0
@@ -6827,7 +6827,7 @@ Id,label
 6825,2
 6826,2
 6827,3
-6828,0
+6828,3
 6829,0
 6830,3
 6831,0
@@ -6866,7 +6866,7 @@ Id,label
 6864,0
 6865,1
 6866,2
-6867,0
+6867,3
 6868,2
 6869,1
 6870,1
@@ -6929,7 +6929,7 @@ Id,label
 6927,0
 6928,2
 6929,1
-6930,0
+6930,3
 6931,1
 6932,0
 6933,3
@@ -7074,7 +7074,7 @@ Id,label
 7072,2
 7073,2
 7074,2
-7075,0
+7075,3
 7076,0
 7077,0
 7078,3
@@ -7108,7 +7108,7 @@ Id,label
 7106,1
 7107,2
 7108,3
-7109,3
+7109,0
 7110,0
 7111,1
 7112,2
@@ -7247,7 +7247,7 @@ Id,label
 7245,3
 7246,2
 7247,2
-7248,0
+7248,3
 7249,1
 7250,0
 7251,2
@@ -7282,12 +7282,12 @@ Id,label
 7280,1
 7281,3
 7282,1
-7283,0
+7283,3
 7284,3
 7285,0
 7286,1
 7287,3
-7288,0
+7288,3
 7289,1
 7290,3
 7291,0
@@ -7358,7 +7358,7 @@ Id,label
 7356,1
 7357,1
 7358,0
-7359,0
+7359,3
 7360,0
 7361,0
 7362,1
@@ -7419,12 +7419,12 @@ Id,label
 7417,0
 7418,2
 7419,1
-7420,0
+7420,3
 7421,0
 7422,3
 7423,3
 7424,1
-7425,0
+7425,3
 7426,0
 7427,0
 7428,3
@@ -7478,7 +7478,7 @@ Id,label
 7476,1
 7477,2
 7478,0
-7479,3
+7479,0
 7480,0
 7481,0
 7482,3
@@ -7525,7 +7525,7 @@ Id,label
 7523,3
 7524,0
 7525,1
-7526,0
+7526,3
 7527,3
 7528,0
 7529,0
@@ -7545,7 +7545,7 @@ Id,label
 7543,0
 7544,0
 7545,2
-7546,0
+7546,3
 7547,0
 7548,3
 7549,0
@@ -7554,8 +7554,8 @@ Id,label
 7552,0
 7553,2
 7554,3
-7555,3
-7556,0
+7555,0
+7556,3
 7557,0
 7558,3
 7559,1
@@ -7590,7 +7590,7 @@ Id,label
 7588,0
 7589,0
 7590,0
-7591,0
+7591,3
 7592,2
 7593,0
 7594,3
@@ -7633,7 +7633,7 @@ Id,label
 7631,0
 7632,1
 7633,3
-7634,0
+7634,3
 7635,1
 7636,0
 7637,1
@@ -7650,7 +7650,7 @@ Id,label
 7648,2
 7649,0
 7650,1
-7651,0
+7651,3
 7652,2
 7653,1
 7654,2
@@ -7658,7 +7658,7 @@ Id,label
 7656,0
 7657,3
 7658,0
-7659,0
+7659,3
 7660,2
 7661,0
 7662,0
@@ -7794,10 +7794,10 @@ Id,label
 7792,2
 7793,3
 7794,0
-7795,3
+7795,0
 7796,2
 7797,2
-7798,0
+7798,3
 7799,0
 7800,0
 7801,3
@@ -7810,7 +7810,7 @@ Id,label
 7808,3
 7809,0
 7810,3
-7811,0
+7811,3
 7812,2
 7813,1
 7814,0
@@ -7890,10 +7890,10 @@ Id,label
 7888,2
 7889,1
 7890,0
-7891,0
+7891,3
 7892,1
 7893,2
-7894,0
+7894,3
 7895,0
 7896,0
 7897,1
@@ -7907,7 +7907,7 @@ Id,label
 7905,1
 7906,2
 7907,0
-7908,0
+7908,3
 7909,3
 7910,1
 7911,2
@@ -8013,7 +8013,7 @@ Id,label
 8011,3
 8012,0
 8013,3
-8014,3
+8014,0
 8015,0
 8016,3
 8017,3
@@ -8110,7 +8110,7 @@ Id,label
 8108,3
 8109,2
 8110,1
-8111,0
+8111,3
 8112,0
 8113,3
 8114,2
@@ -8215,7 +8215,7 @@ Id,label
 8213,0
 8214,0
 8215,0
-8216,0
+8216,3
 8217,2
 8218,1
 8219,3
@@ -8229,7 +8229,7 @@ Id,label
 8227,0
 8228,0
 8229,0
-8230,0
+8230,3
 8231,0
 8232,3
 8233,0
@@ -8353,7 +8353,7 @@ Id,label
 8351,3
 8352,3
 8353,2
-8354,0
+8354,3
 8355,0
 8356,2
 8357,3
@@ -8392,12 +8392,12 @@ Id,label
 8390,2
 8391,1
 8392,3
-8393,0
+8393,3
 8394,0
 8395,2
 8396,3
 8397,0
-8398,3
+8398,0
 8399,2
 8400,0
 8401,1
@@ -8428,7 +8428,7 @@ Id,label
 8426,0
 8427,0
 8428,0
-8429,0
+8429,2
 8430,3
 8431,1
 8432,2
@@ -8504,7 +8504,7 @@ Id,label
 8502,2
 8503,2
 8504,1
-8505,0
+8505,2
 8506,0
 8507,0
 8508,1
@@ -8637,7 +8637,7 @@ Id,label
 8635,2
 8636,0
 8637,3
-8638,0
+8638,3
 8639,0
 8640,0
 8641,0
@@ -8675,7 +8675,7 @@ Id,label
 8673,0
 8674,0
 8675,0
-8676,3
+8676,0
 8677,1
 8678,3
 8679,1
@@ -8724,7 +8724,7 @@ Id,label
 8722,2
 8723,0
 8724,3
-8725,0
+8725,3
 8726,0
 8727,0
 8728,0
@@ -8806,7 +8806,7 @@ Id,label
 8804,0
 8805,3
 8806,0
-8807,0
+8807,3
 8808,0
 8809,0
 8810,1
@@ -9055,9 +9055,9 @@ Id,label
 9053,0
 9054,1
 9055,3
-9056,0
+9056,3
 9057,2
-9058,0
+9058,3
 9059,2
 9060,0
 9061,2
@@ -9143,7 +9143,7 @@ Id,label
 9141,2
 9142,0
 9143,3
-9144,3
+9144,0
 9145,0
 9146,2
 9147,2
@@ -9239,7 +9239,7 @@ Id,label
 9237,1
 9238,3
 9239,0
-9240,0
+9240,3
 9241,2
 9242,3
 9243,1
@@ -9401,7 +9401,7 @@ Id,label
 9399,0
 9400,2
 9401,0
-9402,0
+9402,3
 9403,2
 9404,0
 9405,0
@@ -9424,12 +9424,12 @@ Id,label
 9422,2
 9423,2
 9424,3
-9425,0
+9425,3
 9426,0
 9427,2
 9428,0
 9429,0
-9430,0
+9430,3
 9431,2
 9432,2
 9433,0
@@ -9717,7 +9717,7 @@ Id,label
 9715,0
 9716,0
 9717,2
-9718,0
+9718,3
 9719,3
 9720,2
 9721,0
@@ -9830,7 +9830,7 @@ Id,label
 9828,0
 9829,0
 9830,0
-9831,0
+9831,3
 9832,0
 9833,0
 9834,3
@@ -9889,11 +9889,11 @@ Id,label
 9887,2
 9888,2
 9889,3
-9890,0
+9890,3
 9891,0
 9892,0
 9893,2
-9894,3
+9894,0
 9895,0
 9896,1
 9897,0
@@ -10015,7 +10015,7 @@ Id,label
 10013,0
 10014,0
 10015,2
-10016,0
+10016,3
 10017,0
 10018,3
 10019,2
@@ -10197,7 +10197,7 @@ Id,label
 10195,0
 10196,2
 10197,3
-10198,0
+10198,3
 10199,2
 10200,0
 10201,2
@@ -10373,7 +10373,7 @@ Id,label
 10371,0
 10372,0
 10373,3
-10374,0
+10374,3
 10375,2
 10376,0
 10377,3
@@ -10539,7 +10539,7 @@ Id,label
 10537,0
 10538,1
 10539,1
-10540,0
+10540,3
 10541,2
 10542,0
 10543,1
@@ -10563,7 +10563,7 @@ Id,label
 10561,0
 10562,3
 10563,1
-10564,0
+10564,3
 10565,0
 10566,0
 10567,3
@@ -10630,7 +10630,7 @@ Id,label
 10628,0
 10629,0
 10630,3
-10631,3
+10631,0
 10632,0
 10633,3
 10634,1
@@ -10661,7 +10661,7 @@ Id,label
 10659,1
 10660,1
 10661,1
-10662,0
+10662,3
 10663,1
 10664,2
 10665,0
@@ -10706,7 +10706,7 @@ Id,label
 10704,2
 10705,1
 10706,0
-10707,0
+10707,3
 10708,3
 10709,0
 10710,0