mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
Parse ofac
This commit is contained in:
593
common/ofacdata/scripts/ofac.ipynb
Normal file
593
common/ofacdata/scripts/ofac.ipynb
Normal file
@@ -0,0 +1,593 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"SDN OFAC csv file"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Index(['ent_num', 'SDN_name', 'SDN_type', 'Program', 'Title', 'Call_Sign',\n",
|
||||
" 'Vess_type', 'Tonnage', 'GRT', 'Vess_flag', 'Vess_owner', 'Remarks'],\n",
|
||||
" dtype='object')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>ent_num</th>\n",
|
||||
" <th>SDN_name</th>\n",
|
||||
" <th>SDN_type</th>\n",
|
||||
" <th>Program</th>\n",
|
||||
" <th>Title</th>\n",
|
||||
" <th>Call_Sign</th>\n",
|
||||
" <th>Vess_type</th>\n",
|
||||
" <th>Tonnage</th>\n",
|
||||
" <th>GRT</th>\n",
|
||||
" <th>Vess_flag</th>\n",
|
||||
" <th>Vess_owner</th>\n",
|
||||
" <th>Remarks</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>36</td>\n",
|
||||
" <td>AEROCARIBBEAN AIRLINES</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>CUBA</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>173</td>\n",
|
||||
" <td>ANGLO-CARIBBEAN CO., LTD.</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>CUBA</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>306</td>\n",
|
||||
" <td>BANCO NACIONAL DE CUBA</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>CUBA</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>a.k.a. 'BNC'.</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>424</td>\n",
|
||||
" <td>BOUTIQUE LA MAISON</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>CUBA</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>475</td>\n",
|
||||
" <td>CASA DE CUBA</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>CUBA</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" ent_num SDN_name SDN_type Program Title Call_Sign \\\n",
|
||||
"0 36 AEROCARIBBEAN AIRLINES -0- CUBA -0- -0- \n",
|
||||
"1 173 ANGLO-CARIBBEAN CO., LTD. -0- CUBA -0- -0- \n",
|
||||
"2 306 BANCO NACIONAL DE CUBA -0- CUBA -0- -0- \n",
|
||||
"3 424 BOUTIQUE LA MAISON -0- CUBA -0- -0- \n",
|
||||
"4 475 CASA DE CUBA -0- CUBA -0- -0- \n",
|
||||
"\n",
|
||||
" Vess_type Tonnage GRT Vess_flag Vess_owner Remarks \n",
|
||||
"0 -0- -0- -0- -0- -0- -0- \n",
|
||||
"1 -0- -0- -0- -0- -0- -0- \n",
|
||||
"2 -0- -0- -0- -0- -0- a.k.a. 'BNC'. \n",
|
||||
"3 -0- -0- -0- -0- -0- -0- \n",
|
||||
"4 -0- -0- -0- -0- -0- -0- "
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import json\n",
|
||||
"import re\n",
|
||||
"\n",
|
||||
"file_path = 'sdn.csv'\n",
|
||||
"df1 = pd.read_csv(file_path)\n",
|
||||
"print(df1.columns)\n",
|
||||
"df1.head()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Index(['ent_num', 'SDN_name', 'SDN_type', 'Program', 'Title', 'Call_Sign',\n",
|
||||
" 'Vess_type', 'Tonnage', 'GRT', 'Vess_flag', 'Vess_owner', 'Remarks',\n",
|
||||
" 'country'],\n",
|
||||
" dtype='object')"
|
||||
]
|
||||
},
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# COUNTRY\n",
|
||||
"\n",
|
||||
"# read add.csv which is the helper file to add the country column to sdn.csv\n",
|
||||
"add_file_path = 'add.csv'\n",
|
||||
"df2 = pd.read_csv(add_file_path)\n",
|
||||
"df2 = df2[['ent_num', 'country']]\n",
|
||||
"if 'country' in df1.columns:\n",
|
||||
" df1.drop(columns=['country'], inplace=True)\n",
|
||||
"\n",
|
||||
"# add a new column country in sdn.csv and add the values from add.csv when ent_num matches then concatanate the values\n",
|
||||
"merged_df = pd.merge(df1, df2[['ent_num', 'country']], on='ent_num', how='left')\n",
|
||||
"grouped_df = merged_df.groupby('ent_num')['country'].apply(lambda x: ';'.join(x.dropna())).reset_index()\n",
|
||||
"result_df = pd.merge(df1, grouped_df, on='ent_num', how='left')\n",
|
||||
"result_df.columns\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Index(['ent_num', 'SDN_name', 'SDN_type', 'Remarks', 'country'], dtype='object')"
|
||||
]
|
||||
},
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"col = ['Program', 'Title', 'Call_Sign',\n",
|
||||
" 'Vess_type', 'Tonnage', 'GRT', 'Vess_flag', 'Vess_owner']\n",
|
||||
"columns_to_drop = [col_name for col_name in col if col_name in result_df.columns]\n",
|
||||
"result_df.drop(columns=columns_to_drop, inplace=True)\n",
|
||||
"result_df.columns"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"SDN_type\n",
|
||||
"-0- 7252\n",
|
||||
"individual 6915\n",
|
||||
"vessel 861\n",
|
||||
"aircraft 374\n",
|
||||
"Name: count, dtype: int64\n",
|
||||
"Cleaned SDN_type\n",
|
||||
"individual 6915\n",
|
||||
"Name: count, dtype: int64\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(result_df['SDN_type'].value_counts())\n",
|
||||
"result_df = result_df[result_df['SDN_type'] == 'individual']\n",
|
||||
"print(\"Cleaned\",result_df['SDN_type'].value_counts())\n",
|
||||
"result_df.drop(columns=\"SDN_type\", inplace=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Individual have proper names and some vessels are right name, but most of them are not. Aircrafts seem to be aircraft manufacturers and have codes in names, hence not of any use. -0- seems to be names of company or groups, hence disregarded."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"6915"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"len(result_df) #total individuals"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"6855\n",
|
||||
"5924\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# DOB\n",
|
||||
"\n",
|
||||
"result_df['Remarks'] = result_df['Remarks'].str.lower() \n",
|
||||
"# for format dd mmm yyyy\n",
|
||||
"result_df['DOB'] = result_df['Remarks'].str.extract(r'(\\d{2} \\w{3} \\d{4})')\n",
|
||||
"result_df['day'] = result_df['DOB'].str.extract(r'(\\d{2})')\n",
|
||||
"result_df['month'] = result_df['DOB'].str.extract(r'(\\w{3})')\n",
|
||||
"result_df['year'] = result_df['DOB'].str.extract(r'(\\d{4})')\n",
|
||||
"# for yyyy only format\n",
|
||||
"result_df['year'] = result_df['Remarks'].str.extract(r'(\\d{4})')\n",
|
||||
"result_df.head()\n",
|
||||
"\n",
|
||||
"print(result_df['year'].count()) # total individuals with at least year in dob\n",
|
||||
"print(result_df['DOB'].count()) # total individuals with whole dob\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"4325"
|
||||
]
|
||||
},
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# GENDER\n",
|
||||
"def extract_gender(text):\n",
|
||||
" pattern = r'gender (male|female)'\n",
|
||||
" match = re.search(pattern, text)\n",
|
||||
" if match:\n",
|
||||
" return match.group(1)\n",
|
||||
" else:\n",
|
||||
" return None\n",
|
||||
" \n",
|
||||
"# Apply the function to extract the gender\n",
|
||||
"result_df[\"Gender\"] = result_df['Remarks'].apply(extract_gender)\n",
|
||||
"result_df.head()\n",
|
||||
"result_df[\"Gender\"].count() \n",
|
||||
"# result_df[result_df['ent_num'] == \"12610\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>ent_num</th>\n",
|
||||
" <th>SDN_name</th>\n",
|
||||
" <th>Remarks</th>\n",
|
||||
" <th>country</th>\n",
|
||||
" <th>DOB</th>\n",
|
||||
" <th>day</th>\n",
|
||||
" <th>month</th>\n",
|
||||
" <th>year</th>\n",
|
||||
" <th>Gender</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>2096</th>\n",
|
||||
" <td>12599</td>\n",
|
||||
" <td>PATEK, Umar</td>\n",
|
||||
" <td>dob 20 jul 1966; pob central java, indonesia; ...</td>\n",
|
||||
" <td>-0-</td>\n",
|
||||
" <td>20 jul 1966</td>\n",
|
||||
" <td>20</td>\n",
|
||||
" <td>jul</td>\n",
|
||||
" <td>1966</td>\n",
|
||||
" <td>None</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" ent_num SDN_name Remarks \\\n",
|
||||
"2096 12599 PATEK, Umar dob 20 jul 1966; pob central java, indonesia; ... \n",
|
||||
"\n",
|
||||
" country DOB day month year Gender \n",
|
||||
"2096 -0- 20 jul 1966 20 jul 1966 None "
|
||||
]
|
||||
},
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"result_df[result_df['ent_num'] == \"12599\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"20\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def extract_nationality(remark):\n",
|
||||
" pattern = r'nationality ([A-Za-z]+);'\n",
|
||||
" match = re.search(pattern, remark)\n",
|
||||
" if match:\n",
|
||||
" return match.group(1)\n",
|
||||
" else:\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
"def extract_citizen(remark):\n",
|
||||
" pattern = r'citizen ([A-Za-z]+);'\n",
|
||||
" match = re.search(pattern, remark)\n",
|
||||
" if match:\n",
|
||||
" return match.group(1)\n",
|
||||
" else:\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Apply the extract_nationality function to the 'remarks' column\n",
|
||||
"result_df['Citizen'] = result_df['Remarks'].apply(extract_citizen)\n",
|
||||
"result_df['Nationality'] = result_df['Remarks'].apply(extract_nationality)\n",
|
||||
"result_df['Nationality'].count()\n",
|
||||
"\n",
|
||||
"filtered_df = result_df.dropna(subset=['Citizen', 'Nationality'])\n",
|
||||
"diff_values_df = filtered_df[filtered_df['Citizen'] != filtered_df['Nationality']]\n",
|
||||
"count_diff_values = diff_values_df.shape[0]\n",
|
||||
"print(count_diff_values) # 20 instances where in remark both citizen <country1> and nationality <country2> are mentioned, hence seperated\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1549"
|
||||
]
|
||||
},
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pattern = r'passport ([^\\(]+) \\(([^)]+)\\)'\n",
|
||||
"\n",
|
||||
"def extract_passport_info(remark):\n",
|
||||
" match = re.search(pattern, remark)\n",
|
||||
" if match:\n",
|
||||
" return match.group(1), match.group(2)\n",
|
||||
" else:\n",
|
||||
" return None, None\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"result_df[['Pass_No', 'Pass_Country']] = result_df['Remarks'].apply(lambda x: pd.Series(extract_passport_info(x)))\n",
|
||||
"result_df['Pass_No'].count() # total individuals with passport number"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"11"
|
||||
]
|
||||
},
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pattern = r'eth (0x[0-9a-fA-F]+);'\n",
|
||||
"\n",
|
||||
"def extract_eth_address(remark):\n",
|
||||
" match = re.search(pattern, remark)\n",
|
||||
" if match:\n",
|
||||
" return match.group(1)\n",
|
||||
" else:\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
"result_df['Eth_address'] = result_df['Remarks'].apply(extract_eth_address)\n",
|
||||
"\n",
|
||||
"# Filter rows where 'eth_address' is not null\n",
|
||||
"filtered_df = result_df.dropna(subset=['Eth_address'])\n",
|
||||
"filtered_df['Eth_address'].count() # total individuals with eth address"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 39,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Index(['ent_num', 'SDN_name', 'Remarks', 'country', 'DOB', 'day', 'month',\n",
|
||||
" 'year', 'Gender', 'Citizen', 'Nationality', 'Pass_No', 'Pass_Country',\n",
|
||||
" 'Eth_address'],\n",
|
||||
" dtype='object')"
|
||||
]
|
||||
},
|
||||
"execution_count": 39,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"result_df.columns"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 40,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result_df.to_csv('cleaned_sdn.csv', index=False)\n",
|
||||
"\n",
|
||||
"filtered_df = result_df.dropna(subset=['Pass_No', 'Pass_Country'], how='all')\n",
|
||||
"passport_df = filtered_df[['Pass_No', 'Pass_Country']]\n",
|
||||
"filtered_df = result_df.dropna(subset=['Eth_address'], how='all')\n",
|
||||
"eth_df = filtered_df[['Eth_address']]\n",
|
||||
"\n",
|
||||
"passport_list = passport_df.to_dict(orient='records')\n",
|
||||
"with open('passports.json', 'w') as json_file:\n",
|
||||
" json.dump(passport_list, json_file, indent=4)\n",
|
||||
"etherum_list = eth_df.to_dict(orient='records')\n",
|
||||
"with open('etherum_add.json','w') as json_file:\n",
|
||||
" json.dump(etherum_list, json_file, indent=4)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "base",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
Reference in New Issue
Block a user