<jupyter_start><jupyter_text>Qlunc tutorial by <NAME> **Tutorial 1** Qlunc step by stepThis tutorial aims to facilitate the introduction to Qlunc. Will go through the code and create a lidar device with its modules and components. Will ask for uncertainties either lidar general one or component specific uncertainty. We will see some graphical interesting results. Will see how to access design lidar data. Importing some packages is always needed:<jupyter_code>import pandas as pd
import sys,inspect
from functools import reduce
from operator import getitem
import yaml
import os
import sys
import yaml<jupyter_output><empty_output><jupyter_text>Qlunc inputs:   A [.yml template](https://github.com/PacoCosta/Qlunc/blob/Qlunc-V0.9/Main/Template_yaml_inputs_file.yml) is included in the repository. To accomplish this tutorial a yaml file is already filled. The code below imports the `yaml` file.<jupyter_code># Obtain data from .yaml file:
with open (r'./yaml_inputs_file_1.yml','r') as file:
    Qlunc_yaml_inputs={}
    docs = yaml.load_all(file, Loader=yaml.FullLoader)
    for doc in docs:      
        for k, v in doc.items():     
            Qlunc_yaml_inputs.setdefault(k,v)<jupyter_output><empty_output><jupyter_text>We obtain a dictionary, a well-known python object, with all the data introduced in the `yaml` file. Let´s have a look to the data:<jupyter_code>Qlunc_yaml_inputs<jupyter_output><empty_output><jupyter_text>Now we have the component inputs, let's create them.  **Creating the lidar classes**: We create the python classes by running the Qlunc Core: `Qlunc_Classes.py`<jupyter_code># Execute Qlunc_Classes.py (creating classes for lidar 'objects'):
exec(open(Qlunc_yaml_inputs['Main_directory']+'/WorkingExample_Qlunc_Classes.py').read())<jupyter_output><empty_output><jupyter_text>The main directory is taken from the yaml file, as well as the rest of the lidar parameters, including plotting flags which select what we want to plot:<jupyter_code># Pointing accuracy uncertainty
flags.flag_plot_pointing_accuracy_unc    = Qlunc_yaml_inputs['Flags']['Pointing accuracy uncertainty']  

# Pattern of measuring points
flags.flag_plot_measuring_points_pattern = Qlunc_yaml_inputs['Flags']['Scanning Pattern']

# Photodetector noise: shot noise, dark current noise, thermal noise as a function of the photodetector input signal power.
flags.flag_plot_photodetector_noise      = Qlunc_yaml_inputs['Flags']['Photodetector noise']<jupyter_output><empty_output><jupyter_text>**Creating the lidar digital twin**: We can now begin building up the lidar device and we will do it modularly.  Scanner digital twin:Will begin with the optics module and want to include in here two components: a scanner and an optical circulator, wich characteristics has been introduced in the yaml file.Then, we can instance the class _scanner_ and the class _optical_circulator_ to build up an _optics_module_ wich, in turn, is created by instantiating the class _optics_module_.Let's instantiate the class _scanner_ to "create" the scanner object:<jupyter_code># Instantiating scanner class to create a Scanner virtual-twin

Scanner = scanner(name            = Qlunc_yaml_inputs['Components']['Scanner']['Name'],           # Introduce your scanner name.
                   scanner_type    = Qlunc_yaml_inputs['Components']['Scanner']['Type'],
                   origin          = Qlunc_yaml_inputs['Components']['Scanner']['Origin'],         # Origin (coordinates of the lidar deployment).
                   sample_rate     = Qlunc_yaml_inputs['Components']['Scanner']['Sample rate'],    # for now introduce it in [degrees].
                           
                   # This values for focus distance, cone_angle and azimuth define a typical VAD scanning sequence:
                   focus_dist      = np.array(Qlunc_yaml_inputs['Components']['Scanner']['Focus distance']*int(Qlunc_yaml_inputs['Components']['Scanner']['Azimuth'][1]/Qlunc_yaml_inputs['Components']['Scanner']['Azimuth'][2])),   # Focus distance in [meters]                                        
                   cone_angle      = np.array(Qlunc_yaml_inputs['Components']['Scanner']['Cone angle']*int(Qlunc_yaml_inputs['Components']['Scanner']['Azimuth'][1]/Qlunc_yaml_inputs['Components']['Scanner']['Azimuth'][2])),    # Cone angle in [degrees].
                   azimuth         = np.array(np.arange(Qlunc_yaml_inputs['Components']['Scanner']['Azimuth'][0],
                                                        Qlunc_yaml_inputs['Components']['Scanner']['Azimuth'][1],
                                                        Qlunc_yaml_inputs['Components']['Scanner']['Azimuth'][2])),#np.arange(0,360,15), # Azimuth angle in [degrees].
                   x               = np.array(Qlunc_yaml_inputs['Components']['Scanner']['x']),
                   y               = np.array(Qlunc_yaml_inputs['Components']['Scanner']['y']),
                   z               = np.array(Qlunc_yaml_inputs['Components']['Scanner']['z']),
                   stdv_focus_dist = Qlunc_yaml_inputs['Components']['Scanner']['stdv focus distance'],                 # Focus distance standard deviation in [meters].
                   stdv_cone_angle = Qlunc_yaml_inputs['Components']['Scanner']['stdv Cone angle'],                 # Cone angle standard deviation in [degrees].
                   stdv_azimuth    = Qlunc_yaml_inputs['Components']['Scanner']['stdv Azimuth'],                 # Azimuth angle standard deviation in [degrees].
                   stdv_x          = Qlunc_yaml_inputs['Components']['Scanner']['stdv x'],
                   stdv_y          = Qlunc_yaml_inputs['Components']['Scanner']['stdv y'],
                   stdv_z          = Qlunc_yaml_inputs['Components']['Scanner']['stdv z'],
                   unc_func        = eval(Qlunc_yaml_inputs['Components']['Scanner']['Uncertainty function']) )    # here you put the function describing your scanner uncertainty.<jupyter_output>Created new scanner: Scanner_Yaml<jupyter_text>The label "Yaml" in the name of the device informs us that the data was taken from a yaml file and not manually, instantiating the class in question. Optical circulator digital twin:Then we can create the optical circulator by instantiating the optical_circulator class as follows:<jupyter_code>#Optical Circulator:

Optical_circulator = optical_circulator (name           = Qlunc_yaml_inputs['Components']['Optical Circulator']['Name'],
                                         insertion_loss = Qlunc_yaml_inputs['Components']['Optical Circulator']['Insertion loss'],              
                                         unc_func       = eval(Qlunc_yaml_inputs['Components']['Optical Circulator']['Uncertainty function']))<jupyter_output>Created new optical circulator: OC_Yaml<jupyter_text>Optics module digital twin: Then we create the optics module by puting all optic components created so far (_Scanner_ and _Optical_circulator_) together<jupyter_code># Optics Module:

Optics_Module =  optics (name               = Qlunc_yaml_inputs['Modules']['Optics Module']['Name'],     # Introduce your Optics Module name.
                          scanner            = eval(Qlunc_yaml_inputs['Modules']['Optics Module']['Scanner']),             # Scanner instance (in this example "Scanner") or "None". "None" means that you don´t want to include Scanner in Optics Module, either in uncertainty calculations.
                          optical_circulator = eval(Qlunc_yaml_inputs['Modules']['Optics Module']['Optical circulator']),  # Optical Circulator instance (in this example "Optical_circulator") or "None". "None" means that you don´t want to include Optical circulator in Optics Module, either in uncertainty calculations.
                          laser              = eval(Qlunc_yaml_inputs['Modules']['Optics Module']['Laser']),
                          unc_func           = eval(Qlunc_yaml_inputs['Modules']['Optics Module']['Uncertainty function']))
Qlunc_yaml_inputs['Modules']['Optics Module']['Scanner']<jupyter_output><empty_output><jupyter_text>We have already created the optics module. Following the same method we can create the rest of the components and modules by instantiating their corresponding classes. Optical amplifier digital twin:Let's create the photonics module. First we do instantiate its components namely, photodetector and optical amplifier.<jupyter_code># Instantiating optical amplifier:
Optical_Amplifier = optical_amplifier(name     = Qlunc_yaml_inputs['Components']['Optical Amplifier']['Name'],        # Introduce your scanner name.
                                      OA_NF    = Qlunc_yaml_inputs['Components']['Optical Amplifier']['Optical amplifier noise figure'],          # In [dB]. Can introduce it as a table from manufactures (in this example the data is taken from Thorlabs.com, in section EDFA\Graps) or introduce a single well-known value
                                      OA_Gain  = Qlunc_yaml_inputs['Components']['Optical Amplifier']['Optical amplifier gain'],                         # In [dB]. (in this example the data is taken from Thorlabs.com, in section EDFA\Specs)
                                      unc_func = eval(Qlunc_yaml_inputs['Components']['Optical Amplifier']['Uncertainty function']))  # Function describing Optical Amplifier uncertainty. Further informaion in "UQ_Photonics_Classes.py" comments.<jupyter_output>Created new optical amplifier: OA_Yaml<jupyter_text>Photodetector digital twin:<jupyter_code># Instantiating Photodetector:
Photodetector    = photodetector(name             = Qlunc_yaml_inputs['Components']['Photodetector']['Name'],               # Introduce your photodetector name.
                                 Photo_BandWidth  = Qlunc_yaml_inputs['Components']['Photodetector']['Photodetector BandWidth'],                  # In[]. Photodetector bandwidth
                                 Load_Resistor    = Qlunc_yaml_inputs['Components']['Photodetector']['Load resistor'],                     # In [ohms]
                                 Photo_efficiency = Qlunc_yaml_inputs['Components']['Photodetector']['Photodetector efficiency'],                    # Photodetector efficiency [-]
                                 Dark_Current     = Qlunc_yaml_inputs['Components']['Photodetector']['Dark current'],                   #  In [A]. Dark current in the photodetector.
                                 Photo_SignalP    = Qlunc_yaml_inputs['Components']['Photodetector']['Photodetector signalP'],
                                 Power_interval   = np.array(np.arange(Qlunc_yaml_inputs['Components']['Photodetector']['Power interval'][0],
                                                                       Qlunc_yaml_inputs['Components']['Photodetector']['Power interval'][1],
                                                                       Qlunc_yaml_inputs['Components']['Photodetector']['Power interval'][2])),#np.arange(Qlunc_yaml_inputs['Components']['Photodetector']['Power interval']), # In [w]. Power interval for the photodetector domain in photodetector SNR plot. 
                                 Gain_TIA         = Qlunc_yaml_inputs['Components']['Photodetector']['Gain TIA'],                    # In [dB]. If there is a transimpedance amplifier.
                                 V_Noise_TIA      = Qlunc_yaml_inputs['Components']['Photodetector']['V Noise TIA'],                 # In [V]. If there is a transimpedance amplifier.
                                 unc_func         = eval(Qlunc_yaml_inputs['Components']['Photodetector']['Uncertainty function']))  # Function describing Photodetector uncertainty. Further informaion in "UQ_Photonics_Classes.py" comments.<jupyter_output>Created new photodetector: Photodetector_YAML<jupyter_text>Photonics module digital twin:And finally the Photonics module:<jupyter_code># Instantiating Photonics module:
Photonics_Module = photonics(name              = Qlunc_yaml_inputs['Modules']['Photonics Module']['Name'],        # Introduce your Photonics module name
                             photodetector     = eval(Qlunc_yaml_inputs['Modules']['Photonics Module']['Photodetector']),             # Photodetector instance (in this example "Photodetector") or "None". "None" means that you don´t want to include photodetector in Photonics Module, either in uncertainty calculations.
                             optical_amplifier = eval(Qlunc_yaml_inputs['Modules']['Photonics Module']['Optical amplifier']),         # Scanner instance (in this example "OpticalAmplifier") or "None". "None" means that you don´t want to include Optical Amplifier in Photonics Module, either in uncertainty calculations.
                             unc_func          = eval(Qlunc_yaml_inputs['Modules']['Photonics Module']['Uncertainty function']))<jupyter_output>Created new photonic module: Photonics_module_Yaml<jupyter_text>Lidar general inputs:<jupyter_code># Instantiating lidar general inputs
Lidar_inputs = lidar_gral_inp(name        = Qlunc_yaml_inputs['Components']['Lidar general inputs']['Name'],
                              wave        = Qlunc_yaml_inputs['Components']['Lidar general inputs']['Wavelength'],
                              yaw_error   = Qlunc_yaml_inputs['Components']['Lidar general inputs']['Yaw error'],                          
                              pitch_error = Qlunc_yaml_inputs['Components']['Lidar general inputs']['Pitch error'],                          
                              roll_error  = Qlunc_yaml_inputs['Components']['Lidar general inputs']['Roll error'])<jupyter_output>Created new lidar general inputs: Lidar_gral_inputs_Yaml<jupyter_text>Atmospheric scenarios:We can create different atmospheric scenarios under which the lidar uncertainties are assessed. Thus, single or multiple scenarios can be evaluated either including single or time-seried atmospheric variables values.<jupyter_code># Instantiating atmospheric scenario(s):
Atmospheric_TimeSeries = Qlunc_yaml_inputs['Atmospheric_inputs']['TimeSeries']  
                                                                           
if Atmospheric_TimeSeries:
    Atmos_TS_FILE           = '../metadata/AtmosphericData/'+Qlunc_yaml_inputs['Atmospheric_inputs']['Atmos_TS_FILE']
    AtmosphericScenarios_TS = pd.read_csv(Atmos_TS_FILE,delimiter=';',decimal=',')
    Atmospheric_inputs = {
                          'temperature' : list(AtmosphericScenarios_TS.loc[:,'T']),    
                          'humidity'    : list(AtmosphericScenarios_TS.loc[:,'H']),    
                          'rain'        : list(AtmosphericScenarios_TS.loc[:,'rain']),
                          'fog'         : list(AtmosphericScenarios_TS.loc[:,'fog']),
                          'time'        : list(AtmosphericScenarios_TS.loc[:,'t'])     
                          } 
    Atmospheric_Scenario = atmosphere(name        = 'Atmosphere1',
                                      temperature = Atmospheric_inputs['temperature'])
else:    

    Atmospheric_Scenario = atmosphere(name        = 'Atmosphere1',
                                      temperature = Qlunc_yaml_inputs['Atmospheric_inputs']['Temperature'])<jupyter_output>Created new atmosphere: Atmosphere1<jupyter_text>Lidar digital twin:Puting all objects together like a puzzle we made up a lidar (digital twin). This enable assessing lidar uncertainties before a lidar is manufactured:<jupyter_code># Instantiating lidar device:
Lidar = lidar(name         = Qlunc_yaml_inputs['Lidar']['Name'],                       # Introduce the name of your lidar device.
              photonics    = eval(Qlunc_yaml_inputs['Lidar']['Photonics module']),     # Introduce the name of your photonics module.
              optics       = eval(Qlunc_yaml_inputs['Lidar']['Optics module']),        # Introduce the name of your optics module.
              power        = eval(Qlunc_yaml_inputs['Lidar']['Power module']),         # Introduce the name of your power module. NOT IMPLEMENTED YET!
              lidar_inputs = eval(Qlunc_yaml_inputs['Lidar']['Lidar inputs']),         # Introduce lidar general inputs
              unc_func     = eval(Qlunc_yaml_inputs['Lidar']['Uncertainty function'])) # Function estimating lidar global uncertainty<jupyter_output>Created new lidar device: Caixa1<jupyter_text>**Calculating errors**:Now we can ask for the error we are interested in. The modularity of the code allows us to ask separately either for a specific component uncertainty, a module uncertainty or the global lidar uncertainty coming from the different lidar modules/components. Therefore we can ask for the photodetector uncertainty contribution:<jupyter_code>Photodetector_Uncertainty = Lidar.photonics.photodetector.Uncertainty(Lidar,Atmospheric_Scenario,cts)<jupyter_output>C:\Users\fcosta\SWE_LOCAL\GIT_Qlunc\UQ_functions\UQ_Photonics_Classes.py:37: RuntimeWarning: divide by zero encountered in log10
  UQ_Photodetector.SNR_thermal_noise = [10*np.log10(((R**2)/(4*cts.k*300*Lidar.photonics.photodetector.BandWidth/Lidar.photonics.photodetector.Load_Resistor))*(Lidar.photonics.photodetector.Power_interval/1000)**2)]
C:\Users\fcosta\SWE_LOCAL\GIT_Qlunc\UQ_functions\UQ_Photonics_Classes.py:38: RuntimeWarning: divide by zero encountered in log10
  UQ_Photodetector.SNR_Shot_noise    = [10*np.log10(((R**2)/(2*cts.e*R*Lidar.photonics.photodetector.BandWidth))*(Lidar.photonics.photodetector.Power_interval)/1000)]
C:\Users\fcosta\SWE_LOCAL\GIT_Qlunc\UQ_functions\UQ_Photonics_Classes.py:39: RuntimeWarning: divide by zero encountered in log10
  UQ_Photodetector.SNR_DarkCurrent   = [10*np.log10(((R**2)/(2*cts.e*Lidar.photonics.photodetector.DarkCurrent*Lidar.photonics.photodetector.BandWidth))*((Lidar.photonics.photodetector.Power_interval/1000)**2))]
C:\Users\fcosta\SW[...]<jupyter_text>Photonics module contributions, where contributions from the different photonics components are taken into account<jupyter_code>Photonics_Uncertainty = Lidar.photonics.Uncertainty(Lidar,Atmospheric_Scenario,cts)
print(Photonics_Uncertainty)<jupyter_output>There is a TIA component in the photodetector
{'Uncertainty_Photonics': array([[-127.43222576]])}<jupyter_text>Or,  eventually we can ask for the lidar global uncertainty, where uncertainties coming from the different lidar modules are taken into account and combined following GUM suggestions:<jupyter_code>Lidar_Uncertainty = Lidar.Uncertainty(Lidar,Atmospheric_Scenario,cts,Qlunc_yaml_inputs)
print(Lidar_Uncertainty)<jupyter_output>There is a TIA component in the photodetector
No telescope in calculations!
No power module in calculations!
Lidar unc Done
{'Lidar_Uncertainty': array([[2.1]])}<jupyter_text>**Plotting nice stuff**: Introducing plotting parameters manually<jupyter_code># Plotting parameters:
plot_param={
            'axes_label_fontsize' : 16,
            'textbox_fontsize'    : 14,
            'title_fontsize'      : 18,
            'suptitle_fontsize'   : 23,
            'legend_fontsize'     : 12,
            'xlim'                : [-25,25],
            'ylim'                : [-25,25],
            'zlim'                : [0,90],
            'markersize'          : 5,
            'markersize_lidar'    : 9,
            'marker'              : '.',
            'markerTheo'          : '.r',
            'tick_labelrotation'  : 45,
            'Qlunc_version'       : 'Qlunc Version - 0.9'
           }<jupyter_output><empty_output><jupyter_text>Want to plot scanner pointing accuracy:<jupyter_code>if flags.flag_plot_measuring_points_pattern:
    
    # Calling Scanner uncertainty to plot the graphics
    Scanner_Data1 = Lidar.optics.scanner.Uncertainty(Lidar,Atmospheric_Scenario,cts,Qlunc_yaml_inputs) 

    
    # Creating the figure and the axes
    fig,axs4 = plt.subplots()  
    axs4=plt.axes(projection='3d')
    
    # Plotting
    axs4.plot([Lidar.optics.scanner.origin[0]],[Lidar.optics.scanner.origin[1]],[Lidar.optics.scanner.origin[2]],'ob',label='{} coordinates [{},{},{}]'.format(Lidar.LidarID,Lidar.optics.scanner.origin[0],Lidar.optics.scanner.origin[1],Lidar.optics.scanner.origin[2]),markersize=plot_param['markersize_lidar'])
    axs4.plot(Scanner_Data1['MeasPoint_Coordinates'][0],Scanner_Data1['MeasPoint_Coordinates'][1],Scanner_Data1['MeasPoint_Coordinates'][2],plot_param['markerTheo'],markersize=plot_param['markersize'],label='Theoretical measuring point')
    axs4.plot(Scanner_Data1['NoisyMeasPoint_Coordinates'][0],Scanner_Data1['NoisyMeasPoint_Coordinates'][1],Scanner_Data1['NoisyMeasPoint_Coordinates'][2],plot_param['marker'],markersize=plot_param['markersize'],label='Distance error [m] = {0:.3g}$\pm${1:.3g}'.format(np.mean(Scanner_Data1['Simu_Mean_Distance']),np.mean(Scanner_Data1['STDV_Distance'])))
    
    # Setting labels, legend, title and axes limits:
    axs4.set_xlabel('x [m]',fontsize=plot_param['axes_label_fontsize'])#,orientation=plot_param['tick_labelrotation'])
    axs4.set_ylabel('y [m]',fontsize=plot_param['axes_label_fontsize'])#,orientation=plot_param['tick_labelrotation'])
    axs4.set_zlabel('z [m]',fontsize=plot_param['axes_label_fontsize'])
    axs4.set_title('Scanner Pointing accuracy',fontsize=plot_param['title_fontsize'])
    axs4.legend()
    axs4.set_xlim3d(plot_param['xlim'][0],plot_param['xlim'][1])
    axs4.set_ylim3d(plot_param['ylim'][0],plot_param['ylim'][1])
    axs4.set_zlim3d(plot_param['zlim'][0],plot_param['zlim'][1])<jupyter_output><empty_output><jupyter_text>Now we want to graphically evaluate the photodetector noise:<jupyter_code>if flags.flag_plot_photodetector_noise:
    # Quantifying uncertainty from photodetector and interval domain for the plot Psax is define in the photodetector class properties)
    UQ_photo = Lidar.photonics.photodetector.Uncertainty(Lidar,Atmospheric_Scenario,cts) # Obtain the UQ photodetector dictionary wit SNR and UQ information
    Psax=10*np.log10(Lidar.photonics.photodetector.Power_interval) 

    # Plotting:
    
    fig,ax=plt.subplots()
    ax.plot(Psax,UQ_photo['SNR_data_photodetector']['SNR_Shot_Noise'][0],Psax,UQ_photo['SNR_data_photodetector']['SNR_Thermal'][0],Psax,UQ_photo['SNR_data_photodetector']['SNR_Dark_Current'][0],Psax,UQ_photo['SNR_data_photodetector']['SNR_TIA'][0])
    ax.set_xlabel('Input Signal optical power (dBm)',fontsize=plot_param['axes_label_fontsize'])
    ax.set_ylabel('SNR (dB)',fontsize=plot_param['axes_label_fontsize'])
    ax.legend(['Shot Noise','Thermal Noise','Dark current Noise','TIA Noise'],fontsize=plot_param['legend_fontsize'])#,'Total error [w]'])
    ax.set_title('SNR Photodetector',fontsize=plot_param['title_fontsize'])
    ax.grid(axis='both')
    ax.text(.90,.05,plot_param['Qlunc_version'],transform=ax.transAxes, fontsize=14,verticalalignment='top',bbox=dict(boxstyle='round', facecolor='white', alpha=0.5))<jupyter_output>There is a TIA component in the photodetector<jupyter_text>Parameters access (dot notation): If want to access to some parameter, follow dot notation. Let's see some examples:*Focus distance*:<jupyter_code>print(Scanner.focus_dist)<jupyter_output>[40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40
 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40]<jupyter_text>Optical circulator *insertion loss*:<jupyter_code>print(Optical_circulator.insertion_loss)<jupyter_output>2.1<jupyter_text>*Optical circulator's ID*:<jupyter_code>print(Optical_circulator.Optical_CirculatorID)
Lidar.optics.scanner.cone_angle
# Cone angle for each pattern point:
print(Scanner.cone_angle)<jupyter_output>[20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20]
{'fraction_non_alphanumeric': 0.10634793259281158, 'fraction_numerical': 0.015077923723444693, 'mean_word_length': 3.6021379980563655, 'pattern_counts': {'":': 0, '<': 79, '<?xml version=': 0, '>': 79, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 35, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '23', 'dir': 'jupyter-structured-clean-dedup', 'id': '270261', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 7421, 'n_tokens_neox': 6851, 'n_words': 1563, 'path': 'Tutorials/Tutorial1.ipynb', 'repo_name': 'PacoPers/Qlunc', 'size': '23686'}