├── .gitignore ├── images ├── architecture.png ├── february_sales_plot.png ├── january_sales_excel.png ├── january_sales_plot.png ├── january_sales_table.png ├── process_flow.png ├── reach_out.png └── template_notebook_screenshot.png ├── report-automation-part-1.md ├── report-automation-part-2.md └── src ├── base.ipynb ├── cloud_reporter.py ├── sales_february.ipynb ├── sales_february.xlsx ├── sales_january.html ├── sales_january.ipynb ├── sales_january.xlsx └── template.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints -------------------------------------------------------------------------------- /images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/images/architecture.png -------------------------------------------------------------------------------- /images/february_sales_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/images/february_sales_plot.png -------------------------------------------------------------------------------- /images/january_sales_excel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/images/january_sales_excel.png -------------------------------------------------------------------------------- /images/january_sales_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/images/january_sales_plot.png -------------------------------------------------------------------------------- /images/january_sales_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/images/january_sales_table.png -------------------------------------------------------------------------------- /images/process_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/images/process_flow.png -------------------------------------------------------------------------------- /images/reach_out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/images/reach_out.png -------------------------------------------------------------------------------- /images/template_notebook_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/images/template_notebook_screenshot.png -------------------------------------------------------------------------------- /report-automation-part-1.md: -------------------------------------------------------------------------------- 1 | About the author: 2 | 3 | *My name is [Duarte Carmo](https://duarteocarmo.com/) and I'm a product manager and digital consultant. Originally from Lisbon - Portugal, but currently living and working in Copenhagen - Denmark. Find more about my work and leisure in [my website](https://duarteocarmo.com/).* 4 | 5 | # Automating report generation with Papermill and Rclone: Part 1 - Tool roundup 6 | 7 | Welcome to part 1 of this two-part series post about automating report generation using python, jupyter, papermill, and a couple of other tools. 8 | 9 | In the first part, we will cover 4 main important workflows that are part of the automation process. In the second and final part, we will bring everything together and build our own report automation system. 10 | 11 | *Note: This code was written in python 3.7. You might have to adapt the code for older versions of python.* 12 | 13 | Alright, let's get to work. 14 | 15 | ## Automating report generation with Python - Why? 16 | 17 | Not everyone can code. This might seem like an obvious statement, but once you start using python to automate or analyze things around you, you start to encounter a big problem: **reproducibility**. Not everyone knows how to run your scripts, use your tools, or even use a modern browser. 18 | 19 | Let us say you built a killer script. How exactly do you make someone who has never heard the word "python" use it? You could teach them python, but that would take a long time. 20 | 21 | In this series, we will teach you how you can automatically generate shareable Html reports from any excel file using a combination of tools, centered around python. 22 | 23 | ## Creating a Jupyter Notebook reports from Excel files 24 | 25 | Let us say you have an excel file (`sales_january.xlsx`) with a list of the sales generated by a group of employees. Just like this: 26 | 27 |
28 |
29 | excel 30 |
31 |
32 | 33 | Let's start by using a jupyter notebook `sales_january.ipynb` to create a very simple analysis of that sales data. 34 | 35 | We start by importing the [pandas](https://pandas.pydata.org/) and [maplotlib](https://matplotlib.org/) libraries. After that, we specify the name of our file using the `filename` variable. Finally, we use the `read_excel` function to read our data into a pandas DataFrame. 36 | 37 | ```python 38 | import pandas as pd 39 | import matplotlib.pyplot as plt 40 | %matplotlib inline # so plots are printed automatically 41 | 42 | filename = "sales_january.xlsx" 43 | data = pd.read_excel(filename, index_col=0) 44 | ``` 45 | When printing the `data` dataframe, we get the following: 46 | 47 |
48 |
49 | excel 50 |
51 |
52 | 53 | After that, we plot the data using pandas: 54 | 55 | ```python 56 | data.plot(kind="bar", title=f"Sales report from {filename}") 57 | ``` 58 | 59 | And we get the following: 60 | 61 |
62 |
63 | excel 64 |
65 |
66 | 67 | And that's it! We got ourselves a [jupyter notebook](src/sales_january.ipynb) that analyzes (a very simple analysis let us say) a sales report in excel. Now let's say we want to share that report with other people in the organization, what do we do? 68 | 69 | 70 | ## Generating Html reports from Jupyter Notebooks to share with colleagues 71 | 72 | In my experience, the easiest way to share a report with colleagues is to use a little tool called [nbconvert](https://nbconvert.readthedocs.io/en/latest/). Nbconvert allows you to generate an Html version of your notebook. To install it simply run `pip install nbconvert`. 73 | 74 | To do this, start by navigating to the same directory where your notebook is and run the following from your terminal: 75 | 76 | ```bash 77 | $ jupyter nbconvert sales_january.ipynb 78 | ``` 79 | You will see that a new file named `sales_january.html` was created. Html files are better than `ipynb` in the measure that they are easily shareable via email, message, or any other way. Just make sure the person receiving the file opens it via a relatively modern browser. 80 | 81 | But lets us say that this sales report comes in every month, how can we automatically run this notebook with any excel file that has the same format? 82 | 83 | ## Automating report generation using papermill 84 | 85 | [Papermill](https://papermill.readthedocs.io/en/latest/) is a handy tool that allows us to "parameterize and execute" Jupyter Notebooks. This basically means that papermill allows you to execute the same jupyter notebook, with different variables defined outside its context. 86 | 87 | To install it, run `pip install papermill`, or follow the more complete [installation instructions](https://papermill.readthedocs.io/en/latest/installation.html). 88 | 89 | Let us say we want to generate the same report as above, but with another excel file: `sales_february.xlsx`. You should have in your directory, the following: 90 | 91 | ```bash 92 | ├── sales_february.xlsx 93 | ├── sales_january.html 94 | ├── sales_january.ipynb 95 | └── sales_january.xlsx 96 | ``` 97 | 98 | The first step is to parameterize our notebook, to do this, let us create a `template.ipynb` file. This notebook is very similar to `sales_january.ipynb` but with a small difference: a new cell with a tag `parameters`. Just like this: 99 | 100 |
101 |
102 | excel 103 |
104 |
105 | 106 | (If you have trouble adding a tag to your notebook, visit [this link](https://papermill.readthedocs.io/en/latest/usage-parameterize.html#notebook)) 107 | 108 | 109 | The cell with the `parameters` tag, will allow you to run this notebook from another python script while feeding the `filename` variable, any value you would like. 110 | 111 | Your directory should look like this: 112 | 113 | ```bash 114 | ├── sales_february.xlsx 115 | ├── sales_january.html 116 | ├── sales_january.ipynb 117 | ├── sales_january.xlsx 118 | └── template.ipynb 119 | ``` 120 | 121 | You can always browse the code in the [GitHub repo](https://github.com/duarteocarmo/automation-post). 122 | 123 | Now that we have everything in place, let's generate a report for a new `february_sales.xlsx` excel file. 124 | 125 | To do it, in a new python file, or python console, run the following: 126 | 127 | ```python 128 | import papermill as pm 129 | 130 | pm.execute_notebook( 131 | 'template.ipynb', 132 | 'sales_february.ipynb', 133 | parameters=dict(filename="sales_february.xlsx") 134 | ) 135 | ``` 136 | 137 | Let's break this down: the `pm.execute_notebook` function takes 3 arguments. The first, `template.ipynb` is the name of the file what we will use as a base to run our notebook, the one with the `parameters` tag. The second argument is the name of the new notebook that we will generate with the new arguments. Finally, `parameters` is a dictionary of the variables that we want to impose to our template, in this case, the `filename` variable, that will now point to our February sales report. 138 | 139 | After running the above code, you will notice a new file in your directory: 140 | 141 | 142 | ```bash 143 | ├── sales_february.ipynb <- This one! 144 | ├── sales_february.xlsx 145 | ├── sales_january.html 146 | ├── sales_january.ipynb 147 | ├── sales_january.xlsx 148 | └── template.ipynb 149 | ``` 150 | 151 | Which means, that Papermill has generated a new notebook for us, based on the `sales_february.xlsx` sales report. When openning this notebook, we see a new graph with the new february numbers: 152 | 153 |
154 |
155 | excel 156 |
157 |
158 | 159 | This is pretty handy! We could have a continuous script that always runs this notebook with different sales reports from different months. But how can we automate the process even more? Stay tuned to learn how! 160 | 161 | In the second part of this series, you will learn how to bring all of this together to build a full report automation workflow that your colleagues can use! Sign up to the [mailing list](https://pbpython.com/pages/mailinglist.html) to make sure you are alerted when the next part comes out! 162 | 163 | Browse the all of the notebooks and files in the [GitHub repo](https://github.com/duarteocarmo/automation-post). -------------------------------------------------------------------------------- /report-automation-part-2.md: -------------------------------------------------------------------------------- 1 | MAKE SURE TO ADD LINKS TO PART 1 BEFORE PUBLISHING 2 | 3 | About the author: 4 | 5 | *My name is [Duarte Carmo](https://duarteocarmo.com/) and I'm a product manager and digital consultant. Originally from Lisbon - Portugal, but currently living and working in Copenhagen - Denmark. Find more about my work and leisure in [my website](https://duarteocarmo.com/).* 6 | 7 | # Automating report generation with Papermill and Rclone: Part 2 - Designing a solution 8 | 9 | Welcome to part 2 of this two-part series post about automating report generation using python, jupyter, papermill, and a couple of other tools. 10 | 11 | In the [first part](https://pbpython.com/papermil-rclone-report-1.html), we covered 4 main important processes that are part of the automation process. In this second and final part, we will bring everything together and build our report automation system. 12 | 13 | *Note: This code was written in python 3.7. You might have to adapt the code for older versions of python.* 14 | 15 | All of the code for this article is available on [GitHub](https://github.com/duarteocarmo/automation-post). 16 | 17 | ## A workflow to automatically generate reports in a shared cloud folder 18 | 19 | Let's imagine you want to generate automatic reports for every similar excel file of sales reports. You also want to share them with your colleagues. Your colleagues are interested in the reports, but not in learning how to program python, how would you proceed? 20 | 21 | There are a lot of options, and hardly any incorrect ones, but one I found particularly interesting was using what we already had company: a cloud folder (Google Drive, OneDrive, Dropbox). 22 | 23 | Cloud folders are very popular in companies, particularly shared ones. So a good idea would be to create a shared folder where everyone can upload sales excel reports, and automatically generate Html reports from them, so everyone can read! 24 | 25 | Here is the basic architecture of the solution: 26 | 27 |
28 |
29 | excel 30 |
31 |
32 | 33 | Let's describe each one of the steps: 34 | - A user uploads a new excel sales report to a shared cloud folder. 35 | - We sync the cloud folder with a local folder and detect that new excel sales report. 36 | - We use papermill to generate a new notebook file from that new excel sales report. 37 | - We use nbconvert to generate an Html file from that new notebook file. 38 | - We upload the Html file to the cloud folder, so the user can read it. 39 | 40 | Let's start building this step by step: 41 | 42 | #### 1.Sync a cloud folder with a local folder and detect new files 43 | To sync cloud directories with local directories, we will a tool called [Rclone](https://rclone.org/). Of course, we will integrate it with python. 44 | 45 | Start by installing rclone in the same machine as your local folder (your personal computer or a virtual private server for example). 46 | 47 | To do so, on a Mac or Linux machine, you should: 48 | 49 | ```bash 50 | $ curl https://rclone.org/install.sh | sudo bash 51 | ``` 52 | On Windows, download the executable in the [Rclone downloads page](https://rclone.org/downloads/). 53 | 54 | Once rclone is installed, we must configure it. Depending on your cloud provider (Dropbox, Google Drive, OneDrive), the instructions will vary, so make sure to follow the [configuration instructions](https://rclone.org/). 55 | 56 | Once configured, let us do a first sync from the command line: 57 | 58 | ```bash 59 | $ rclone sync remote:REMOTE_FOLDER_NAME LOCAL_FOLDER_NAME 60 | ``` 61 | This will sync your local folder with your remote folder. 62 | 63 | We can also spark this command from a python script using the core [`subprocess` library](https://docs.python.org/3/library/subprocess.html). That allows you to run command-line programs from python: 64 | 65 | ```python 66 | import subprocess 67 | 68 | # define our variables 69 | REMOTE_FOLDER_NAME="shared folder" 70 | LOCAL_FOLDER="local folder" 71 | 72 | # run the rclone sync command from python 73 | subprocess.run( 74 | ["rclone", "sync", f"remote:{REMOTE_FOLDER_NAME}", LOCAL_FOLDER] 75 | ) 76 | ``` 77 | Now that we know how to sync a local and a cloud directory, how do we detect if a user has uploaded a new file to our cloud directory? Well, an option would be to navigate to our local directory and use the `ls` command and see what pops out. 78 | 79 | Rclone also [allows us](https://rclone.org/commands/rclone_ls/) to list files in our cloud directory. Having this, we can create a python function that detects new files if they have been uploaded to the cloud folder: 80 | 81 | ```python 82 | def get_new_files(remote_folder, local_folder): 83 | """ 84 | A function that returns files that were uploaded to the cloud folder and 85 | do not exist in our local folder. 86 | """ 87 | # list the files in our cloud folder 88 | list_cloud = subprocess.run( 89 | ["rclone", "lsf", f"remote:{remote_folder}"], 90 | capture_output=True, 91 | text=True, 92 | ) 93 | 94 | # transform the command output into a list 95 | cloud_directories = list_cloud.split("\n")[0:-1] 96 | 97 | print(f"In the cloud we have: \n{cloud_directories}") 98 | 99 | # list the files in our local folder 100 | list_cloud = subprocess.run( 101 | ["ls", local_folder], capture_output=True, text=True 102 | ) 103 | 104 | # transform the command output into a list 105 | local_directories = list_cloud.stdout.split("\n")[0:-1] 106 | 107 | print(f"In the local copy we have: \n{local_directories}") 108 | 109 | # create a list with the differences between the two lists above 110 | new_files = list(set(cloud_directories) - set(local_directories)) 111 | 112 | return new_files 113 | ``` 114 | A couple of notes about the script above: 115 | - The `capture_output` file in the `subprocess.run` function, allows us to capture the output of the command. The `text` flag allows us to treat everything as text, avoiding problems with spaces for example. 116 | - After running `subprocess.run`, we apply the `.split` function, this is because of the output of the `subprocess.run` function is a string of different files separated by a line break (`\n`). This split function allows us to but all the elements into a nicely formatted python list. 117 | - The `new_files` list will contain only files that are in the cloud directory, but not in the local directory, or in other words: the excel file that users have uploaded to the cloud drive. In case there are no differences, the function will return an empty list. 118 | 119 | #### 2.Using Papermill and Nbconvert to generate new reports 120 | 121 | Once we have a reliable way of detecting if new files are uploaded to the cloud, we now need to process that new file and generate an `html` report from it. 122 | 123 | We will use two of the tools mentioned in the [first part of this article](https://pbpython.com/papermil-rclone-report-1.html): papermill, and nbconvert. 124 | 125 | We start by creating a function that will produce a new notebook file, based on an excel report. Using, of course, a notebook template (for example `template.ipynb`) as [previously described in part 1](https://pbpython.com/papermil-rclone-report-1.html). 126 | 127 | ```python 128 | import papermill as pm 129 | 130 | def run_notebook(excel_report, notebook_template): 131 | # take only the name of the file, and ignore the .xlsx ending 132 | no_extension_name = excel_report.split(".")[0] 133 | # run with papermill 134 | pm.execute_notebook( 135 | notebook_template, 136 | f"{no_extension_name}.ipynb", 137 | parameters=dict(filename=excel_report), 138 | ) 139 | return no_extension_name 140 | ``` 141 | 142 | Then, we must convert the notebook to an Html file. To do this, we create another function that calls the `nbconvert` command from the python interpreter. 143 | 144 | ```python 145 | import subprocess 146 | 147 | def generate_html_report(notebook_file): 148 | generate = subprocess.run( 149 | [ 150 | "jupyter", 151 | "nbconvert", 152 | notebook_file, 153 | "--to=html", 154 | ] 155 | ) 156 | print("HTML Report was generated") 157 | return True 158 | ``` 159 | 160 | This function runs the nbconvert command previously described in the beginning of the article, from a python script. 161 | 162 | #### 4.Uploading an Html file back to the cloud folder 163 | 164 | There is another Rclone command that is pretty handy. If you want to push a file from a local folder to a cloud folder, you can use the following from the command line: 165 | 166 | ```bash 167 | $ rclone copy FILENAME remote:REMOTE_FOLDER_NAME 168 | ``` 169 | 170 | We could do it from the command line, but why do it from python? With the subprocess library, it's pretty straightforward: 171 | 172 | 173 | ```python 174 | import subprocess 175 | 176 | def push_to_cloud(remote_folder, html_report): 177 | push = subprocess.run( 178 | ["rclone", "copy", html_report, f"remote:{remote_folder}"] 179 | ) 180 | print("Report Published!!!") 181 | ``` 182 | 183 | #### 5.Bringing it all together 184 | So finally, after giving you a rundown of all of the major tools and processes, here is the full script that scans the cloud folder for new excel sales reports, and generates and uploads an Html analysis of them is presented. 185 | 186 | The script, `cloud_reporter.py` follows: 187 | 188 | ```python 189 | import subprocess 190 | import sys 191 | import papermill as papermill 192 | 193 | 194 | REMOTE_FOLDER = "your cloud folder name" 195 | LOCAL_FOLDER = "your local folder name" 196 | TEMPLATE_NOTEBOOK = "template_notebook.ipynb" 197 | 198 | 199 | def get_new_files(remote_folder, local_folder): 200 | """ 201 | A function that returns files that were uploaded to the cloud folder and do not exist in our local folder. 202 | """ 203 | # list the files in our cloud folder 204 | list_cloud = subprocess.run( 205 | ["rclone", "lsf", f"remote:{remote_folder}"], 206 | capture_output=True, 207 | text=True, 208 | ) 209 | 210 | # transform the command output into a list 211 | cloud_directories = list_cloud.split("\n")[0:-1] 212 | 213 | print(f"In the cloud we have: \n{cloud_directories}") 214 | 215 | # list the files in our local folder 216 | list_cloud = subprocess.run( 217 | ["ls", local_folder], capture_output=True, text=True 218 | ) 219 | 220 | # transform the command output into a list 221 | local_directories = list_cloud.stdout.split("\n")[0:-1] 222 | 223 | print(f"In the local copy we have: \n{local_directories}") 224 | 225 | # create a list with the differences between the two lists above 226 | new_files = list(set(cloud_directories) - set(local_directories)) 227 | 228 | return new_files 229 | 230 | 231 | def sync_directories(remote_folder, local_folder): 232 | """ 233 | A function that syncs a remote folder with a local folder 234 | with rclone. 235 | """ 236 | sync = subprocess.run( 237 | ["rclone", "sync", f"remote:{remote_folder}", local_folder] 238 | ) 239 | 240 | print("Syncing local directory with cloud....") 241 | return sync.returncode 242 | 243 | 244 | def run_notebook(excel_report, template_notebook): 245 | """ 246 | A function that runs a notebook against an excel report 247 | via papermill. 248 | """ 249 | no_extension_name = excel_report.split(".")[0] 250 | papermill.execute_notebook( 251 | template_notebook, 252 | f"{no_extension_name}.ipynb", 253 | parameters=dict(filename=excel_report), 254 | ) 255 | return no_extension_name 256 | 257 | 258 | def generate_html_report(notebook_file): 259 | """ 260 | A function that converts a notebook into an html 261 | file. 262 | """ 263 | generate = subprocess.run( 264 | ["jupyter", "nbconvert", notebook_file, "--to=html"] 265 | ) 266 | print("HTML Report was generated") 267 | return True 268 | 269 | 270 | def push_to_cloud(remote_folder, filename): 271 | """ 272 | A function that pushes to a remote cloud folder 273 | a specific file. 274 | """ 275 | 276 | push = subprocess.run( 277 | ["rclone", "copy", filename, f"remote:{remote_folder}"] 278 | ) 279 | print("Report Published!!!") 280 | 281 | def main(): 282 | print("Starting updater..") 283 | 284 | # detect if there are new files in the remote folder 285 | new_files = get_new_files( 286 | remote_folder=REMOTE_FOLDER, local_folder=LOCAL_FOLDER 287 | ) 288 | 289 | # if there are none, exit 290 | if not new_files: 291 | print("Everything is synced. No new files.") 292 | sys.exit() 293 | # else, continue 294 | else: 295 | print("There are files missing.") 296 | print(new_files) 297 | 298 | # sync directories to get new excel report 299 | sync_directories(remote_folder=REMOTE_FOLDER, local_folder=LOCAL_FOLDER) 300 | 301 | # generate new notebook and extract the name 302 | clean_name = run_notebook(new_files[0]) 303 | 304 | # the new notebook generate will have the following name 305 | notebook_name = f"{clean_name}.ipynb" 306 | 307 | # generate the html report from the notebook 308 | generate_html_report(notebook_name) 309 | 310 | # the notebook name will be the following 311 | html_report_name = f"{clean_name}.html" 312 | 313 | # push the new notebook to the cloud 314 | push_to_cloud(html_report=html_report_name, remote_folder=ONEDRIVE_FOLDER) 315 | 316 | # make sure everything is synced again 317 | sync_directories(remote_folder=REMOTE_FOLDER, local_folder=LOCAL_FOLDER) 318 | 319 | print("Updater finished.") 320 | 321 | return True 322 | 323 | 324 | if __name__ == "main": 325 | main() 326 | ``` 327 | 328 | #### 6.Running the updater regularly 329 | 330 | Once you get the script running, one option is to copy it to a virtual private server (you can get one in [digitalocean.com](https://www.digitalocean.com/products/linux-distribution/ubuntu/) for example) and have it run regularly via something like `cron`. 331 | 332 | ⚠️Warning: If you are going to sync sensitive company information to a virtual private server, please make sure that you have permission, and that you take [necessary security measures](https://www.digitalocean.com/community/tutorials/7-security-measures-to-protect-your-servers) to protect the server. 333 | 334 | You should [read more about `cron`](https://www.ostechnix.com/a-beginners-guide-to-cron-jobs/) before messing with it. It allows you to run scripts every X amount of time. A simple approach to our problem would be: 335 | 336 | 1. Make sure the script is running successfully in your server by: 337 | - Installing and configuring rclone. 338 | - Installing jupyter and nbconvert. 339 | - Creating a local folder to serve as a remote copy. 340 | - Modifying the script above with your variables (base notebook, remote folder name, and local folder name). 341 | - Making sure the script runs. 342 | 343 | 2. Editing your crontab by: 344 | 345 | ```bash 346 | $ crontab -e 347 | ``` 348 | 349 | 3. Adding a crontab job that navigates to a certain directory and runs the `cloud_reporter.py` file, every X minutes using python. 350 | 351 | Here is an example of it running every 4 minutes: 352 | 353 | ```bash 354 | */4 * * * * python /path/to/your/folder/cloud_reporter.py 355 | ``` 356 | 357 | 4. Upload a new excel file to your cloud folder and wait a minimum of 4 minutes, and a new Html report should be generated and uploaded automatically! 358 | 359 | 5. Give access to the shared cloud folder (Dropbox, Google Drive) to your colleagues, and let them upload any excel report. 360 | 361 | ## Final thoughts 362 | 363 | And just like this, we reach the end of this article series! 364 | 365 | Hopefully, these tools and scripts will inspire you to go out and automate report generation or any other process around you. Making it as simple as possible to your colleagues to generate reports. 366 | 367 | I would like to thank [Chris](https://twitter.com/chris1610) for allowing me to collaborate with him in these posts. I really had a blast building these tools and writing these "guides". [A team effort](https://github.com/duarteocarmo/automation-post/issues/1) that started with a simple reach out on twitter: 368 | 369 | 370 |
371 |
372 | excel 373 |
374 |
375 | 376 | 377 | All of the code for this article series is in [this GitHub repo](https://github.com/duarteocarmo/automation-post). 378 | 379 | 380 | 381 | -------------------------------------------------------------------------------- /src/cloud_reporter.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | import papermill as papermill 4 | 5 | 6 | REMOTE_FOLDER = "your cloud folder name" 7 | LOCAL_FOLDER = "your local folder name" 8 | TEMPLATE_NOTEBOOK = "template_notebook.ipynb" 9 | 10 | 11 | def get_new_files(remote_folder, local_folder): 12 | """ 13 | A function that returns files that were uploaded to the cloud folder and 14 | do not exist in our local folder. 15 | """ 16 | # list the files in our cloud folder 17 | list_cloud = subprocess.run( 18 | ["rclone", "lsf", f"remote:{remote_folder}"], 19 | capture_output=True, 20 | text=True, 21 | ) 22 | 23 | # transform the command output into a list 24 | cloud_directories = list_cloud.split("\n")[0:-1] 25 | 26 | print(f"In the cloud we have: \n{cloud_directories}") 27 | 28 | # list the files in our local folder 29 | list_cloud = subprocess.run( 30 | ["ls", local_folder], capture_output=True, text=True 31 | ) 32 | 33 | # transform the command output into a list 34 | local_directories = list_cloud.stdout.split("\n")[0:-1] 35 | 36 | print(f"In the local copy we have: \n{local_directories}") 37 | 38 | # create a list with the differences between the two lists above 39 | new_files = list(set(cloud_directories) - set(local_directories)) 40 | 41 | return new_files 42 | 43 | 44 | def sync_directories(remote_folder, local_folder): 45 | """ 46 | A function that syncs a remote folder with a local folder 47 | with rclone. 48 | """ 49 | sync = subprocess.run( 50 | ["rclone", "sync", f"remote:{remote_folder}", local_folder] 51 | ) 52 | 53 | print("Syncing local directory with cloud....") 54 | return sync.returncode 55 | 56 | 57 | def run_notebook(excel_report, template_notebook): 58 | """ 59 | A function that runs a notebook against an excel report 60 | via papermill. 61 | """ 62 | no_extension_name = excel_report.split(".")[0] 63 | papermill.execute_notebook( 64 | template_notebook, 65 | f"{no_extension_name}.ipynb", 66 | parameters=dict(filename=excel_report), 67 | ) 68 | return no_extension_name 69 | 70 | 71 | def generate_html_report(notebook_file): 72 | """ 73 | A function that converts a notebook into an html 74 | file. 75 | """ 76 | generate = subprocess.run( 77 | ["jupyter", "nbconvert", notebook_file, "--to=html"] 78 | ) 79 | print("HTML Report was generated") 80 | return True 81 | 82 | 83 | def push_to_cloud(remote_folder, filename): 84 | """ 85 | A function that pushes to a remote cloud folder 86 | a specific file. 87 | """ 88 | 89 | push = subprocess.run( 90 | ["rclone", "copy", filename, f"remote:{remote_folder}"] 91 | ) 92 | print("Report Published!!!") 93 | 94 | def main(): 95 | print("Starting updater..") 96 | 97 | # detect if there are new files in the remote folder 98 | new_files = get_new_files( 99 | remote_folder=REMOTE_FOLDER, local_folder=LOCAL_FOLDER 100 | ) 101 | 102 | # if there are none, exit 103 | if not new_files: 104 | print("Everything is synced. No new files.") 105 | sys.exit() 106 | # else, continue 107 | else: 108 | print("There are files missing.") 109 | print(new_files) 110 | 111 | # sync directories to get new excel report 112 | sync_directories(remote_folder=REMOTE_FOLDER, local_folder=LOCAL_FOLDER) 113 | 114 | # generate new notebook and extract the name 115 | clean_name = run_notebook(new_files[0]) 116 | 117 | # the new notebook generate will have the following name 118 | notebook_name = f"{clean_name}.ipynb" 119 | 120 | # generate the html report from the notebook 121 | generate_html_report(notebook_name) 122 | 123 | # the notebook name will be the following 124 | html_report_name = f"{clean_name}.html" 125 | 126 | # push the new notebook to the cloud 127 | push_to_cloud(html_report=html_report_name, remote_folder=ONEDRIVE_FOLDER) 128 | 129 | # make sure everything is synced again 130 | sync_directories(remote_folder=REMOTE_FOLDER, local_folder=LOCAL_FOLDER) 131 | 132 | print("Updater finished.") 133 | 134 | return True 135 | 136 | 137 | if __name__ == "main": 138 | main() -------------------------------------------------------------------------------- /src/sales_february.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "papermill": { 7 | "duration": 0.021948, 8 | "end_time": "2019-07-16T08:19:31.413195", 9 | "exception": false, 10 | "start_time": "2019-07-16T08:19:31.391247", 11 | "status": "completed" 12 | }, 13 | "tags": [] 14 | }, 15 | "source": [ 16 | "# Sales Report" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "metadata": { 23 | "papermill": { 24 | "duration": 0.826242, 25 | "end_time": "2019-07-16T08:19:32.251470", 26 | "exception": false, 27 | "start_time": "2019-07-16T08:19:31.425228", 28 | "status": "completed" 29 | }, 30 | "tags": [] 31 | }, 32 | "outputs": [], 33 | "source": [ 34 | "import pandas as pd\n", 35 | "import matplotlib.pyplot as plt\n", 36 | "%matplotlib inline" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 2, 42 | "metadata": { 43 | "papermill": { 44 | "duration": 0.028103, 45 | "end_time": "2019-07-16T08:19:32.291574", 46 | "exception": false, 47 | "start_time": "2019-07-16T08:19:32.263471", 48 | "status": "completed" 49 | }, 50 | "tags": [ 51 | "parameters" 52 | ] 53 | }, 54 | "outputs": [], 55 | "source": [ 56 | "filename = \"sales_january.xlsx\"" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 3, 62 | "metadata": { 63 | "papermill": { 64 | "duration": 0.022058, 65 | "end_time": "2019-07-16T08:19:32.327141", 66 | "exception": false, 67 | "start_time": "2019-07-16T08:19:32.305083", 68 | "status": "completed" 69 | }, 70 | "tags": [ 71 | "injected-parameters" 72 | ] 73 | }, 74 | "outputs": [], 75 | "source": [ 76 | "# Parameters\n", 77 | "filename = \"sales_february.xlsx\"\n" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 4, 83 | "metadata": { 84 | "papermill": { 85 | "duration": 0.071755, 86 | "end_time": "2019-07-16T08:19:32.412446", 87 | "exception": false, 88 | "start_time": "2019-07-16T08:19:32.340691", 89 | "status": "completed" 90 | }, 91 | "tags": [] 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "data = pd.read_excel(filename, index_col=0)" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 5, 101 | "metadata": { 102 | "papermill": { 103 | "duration": 0.03584, 104 | "end_time": "2019-07-16T08:19:32.460286", 105 | "exception": false, 106 | "start_time": "2019-07-16T08:19:32.424446", 107 | "status": "completed" 108 | }, 109 | "tags": [] 110 | }, 111 | "outputs": [ 112 | { 113 | "data": { 114 | "text/html": [ 115 | "
\n", 116 | "\n", 129 | "\n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | "
Sales
Employee Name
Paul250
Oscar4000
Richard3250
Thomas100
Ursula0
Gabriela260
Allison890
Louis990
\n", 175 | "
" 176 | ], 177 | "text/plain": [ 178 | " Sales \n", 179 | "Employee Name \n", 180 | "Paul 250\n", 181 | "Oscar 4000\n", 182 | "Richard 3250\n", 183 | "Thomas 100\n", 184 | "Ursula 0\n", 185 | "Gabriela 260\n", 186 | "Allison 890\n", 187 | "Louis 990" 188 | ] 189 | }, 190 | "execution_count": 5, 191 | "metadata": {}, 192 | "output_type": "execute_result" 193 | } 194 | ], 195 | "source": [ 196 | "data" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": 6, 202 | "metadata": { 203 | "papermill": { 204 | "duration": 0.267664, 205 | "end_time": "2019-07-16T08:19:32.744495", 206 | "exception": false, 207 | "start_time": "2019-07-16T08:19:32.476831", 208 | "status": "completed" 209 | }, 210 | "tags": [] 211 | }, 212 | "outputs": [ 213 | { 214 | "data": { 215 | "text/plain": [ 216 | "" 217 | ] 218 | }, 219 | "execution_count": 6, 220 | "metadata": {}, 221 | "output_type": "execute_result" 222 | }, 223 | { 224 | "data": { 225 | "image/png": "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uzXaR8NVQLkr4Ecl3ZLnt1Man/MppTFhN8zlffP8nLx8WNU+zsnlT9bontbMrFOWLl3KFltsUbqDP4Aktthii7U6++nMNYAzSN0JV3wVuDQiRpC6lq30EX4yacSh4aRuZL+agx0JjCWN3XoocHnuo97MbI2V8eBfsbavvaEEkAct+RCpL3jyYBUHkfqZh9RH+JF5+og8T17+/rz+EaTBmN+IiGdI/ZXvs1bRm5kVbMKECeyyyy7svvvujBo1ioceeqju+ieccAI33nhj3XW6S6PXAL4FfIk0+g/AFsCiiFiW51tZOebqIPKAEBGxTNLivP4gVo521XabFSSNJw3wzNChPa6jww4NO/vWLt/n3Es+1OX7NOuJuvr71dF364EHHuCWW27hkUceoW/fvrzwwgu8+eabXRrDutThGYCkDwPPR8T06uIaq0YHy+pts7IgYmJEjI6I0S0tHd7JbGZWmPnz5zNw4ED69u0LwMCBA9lmm20AuPDCC9l7773ZddddGT9+PLV6Xp4+fTrve9/72GuvvTjkkEOYP38+AJdddhkjR45k9913Z+zYsess/kaqgPYHPiJpLmk814NIZwQD8jiwsHIgcEi/7IfAisGYNwUWVpfX2MbMrMc5+OCDmTdvHjvuuCOf//znuffee1csO/XUU5k6dSqPP/44r7/+Orfccssq27711lucdtpp3HjjjUyfPp2TTjqJL3/5ywBccsklPProo8ycOZMrr7xyncXfYQKIiHMiYnBEDCNdxL0rIo4F7gY+kVcbRxobFtLYtOPy9Cfy+pHLx+ZWQtuRxj59uMteiZlZN9t4442ZPn06EydOpKWlhaOPPpprrrkGgLvvvpt9992X3XbbjbvuuotZs2atsu2TTz7J448/zgc/+EFGjRrFxRdfTGtrKwC77747xx57LD/+8Y/ZYIN111p/bfZ8FnCdpIuBR0kDepP//kjSHNIv/7EAETFL0g3AE8Ay4JQ86LiZWY/Vu3dvxowZw5gxY9htt92YNGkSY8eO5fOf/zzTpk1jyJAhnH/++as114wIdtllFx544IHV9nnrrbdy3333MXnyZC666CJmzZq1ThJBp7qCiIh7IuLDefrpiNgnIoZHxFER8UYuX5rnh+flT1dtPyEidoiInSLif7v2pZiZda8nn3ySp556asX8jBkz2HbbbVcc7AcOHMiSJUtq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\n", 226 | "text/plain": [ 227 | "
" 228 | ] 229 | }, 230 | "metadata": { 231 | "needs_background": "light" 232 | }, 233 | "output_type": "display_data" 234 | } 235 | ], 236 | "source": [ 237 | "data.plot(kind=\"bar\", title=f\"Sales report from {filename}\")" 238 | ] 239 | } 240 | ], 241 | "metadata": { 242 | "celltoolbar": "Tags", 243 | "kernelspec": { 244 | "display_name": "Python 3", 245 | "language": "python", 246 | "name": "python3" 247 | }, 248 | "language_info": { 249 | "codemirror_mode": { 250 | "name": "ipython", 251 | "version": 3 252 | }, 253 | "file_extension": ".py", 254 | "mimetype": "text/x-python", 255 | "name": "python", 256 | "nbconvert_exporter": "python", 257 | "pygments_lexer": "ipython3", 258 | "version": "3.7.2" 259 | }, 260 | "papermill": { 261 | "duration": 3.709709, 262 | "end_time": "2019-07-16T08:19:33.401817", 263 | "environment_variables": {}, 264 | "exception": null, 265 | "input_path": "template.ipynb", 266 | "output_path": "sales_february.ipynb", 267 | "parameters": { 268 | "filename": "sales_february.xlsx" 269 | }, 270 | "start_time": "2019-07-16T08:19:29.692108", 271 | "version": "1.0.1" 272 | } 273 | }, 274 | "nbformat": 4, 275 | "nbformat_minor": 2 276 | } -------------------------------------------------------------------------------- /src/sales_february.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/src/sales_february.xlsx -------------------------------------------------------------------------------- /src/sales_january.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Sales Report" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import pandas as pd\n", 17 | "import matplotlib.pyplot as plt\n", 18 | "%matplotlib inline\n", 19 | "\n", 20 | "filename = \"sales_january.xlsx\"" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 2, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "data = pd.read_excel(filename, index_col=0)" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 3, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "text/html": [ 40 | "
\n", 41 | "\n", 54 | "\n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | "
Sales
Employee Name
Paul2000
Oscar1500
Richard4000
Thomas500
Ursula780
Gabriela1760
Allison1000
Louis530
\n", 100 | "
" 101 | ], 102 | "text/plain": [ 103 | " Sales \n", 104 | "Employee Name \n", 105 | "Paul 2000\n", 106 | "Oscar 1500\n", 107 | "Richard 4000\n", 108 | "Thomas 500\n", 109 | "Ursula 780\n", 110 | "Gabriela 1760\n", 111 | "Allison 1000\n", 112 | "Louis 530" 113 | ] 114 | }, 115 | "execution_count": 3, 116 | "metadata": {}, 117 | "output_type": "execute_result" 118 | } 119 | ], 120 | "source": [ 121 | "data" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 4, 127 | "metadata": {}, 128 | "outputs": [ 129 | { 130 | "data": { 131 | "text/plain": [ 132 | "" 133 | ] 134 | }, 135 | "execution_count": 4, 136 | "metadata": {}, 137 | "output_type": "execute_result" 138 | }, 139 | { 140 | "data": { 141 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYAAAAE3CAYAAACjCJZyAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3XmcHVWd9/HPlyQkzLAESMNAFhIgIGGLEBYFNYCyuYCjSBiRCDxGRxBwnEHAeQYEMiIuOC7AREHCoAIDIjEyQoZVlCUJxJCAPESIpCVCIAQImyT8nj/OuclN53b37aTTVZ36vl+v++qqU6fq/u7S9bt1quocRQRmZlY9GxQdgJmZFcMJwMysopwAzMwqygnAzKyinADMzCrKCcDMrKKcANYDkuZLen/RcfQ0SQdIekLSUklHFx1PsySFpB3X0bbnShq7LrZdBpLeL2l+0XGsL5wASkLSgZJ+J+klSYsl/VbSPkXHVRRJV0m6sJNq5wPfj4iNI+IXPRFX2UXErhFxV9FxWO/Qt+gADCRtCkwF/hG4HtgQeA/wZpFx1UjqGxHLevD5+jRZdTtgbjvbEKCIeLvbArM10tPfH2uejwDKYSeAiPhZRCyPiNcj4raImA0gaQdJd0h6QdLzkn4iaWCjDUnaQNJZkv6Y618vaYu8bICka3L5EknTJW3dznbmS/qypNnAq5L6StpW0o2SFkl6StJpdfXPk3SDpOskvSLpIUl71i3fRdJd+XnnSvpI3bKrJF0m6RZJrwInA58EzszNO79sEN8fge2BX+Y6/fP2J0r6LfAasH2OeUo+qpon6TNtYv7v/J68IukRSTtJOlvSc5IWSDq0vQ8tvz9/zus+LumQXL6vpPvya10o6fuSNmxnG/0lfVPS05KelXS5pI3yskGSpubtLJb0G0kd/s/WNwd2FkduivpcbkZ7UdIPcuKsvTfX1NUdnuv3zfMnSnosv/YnJX22ru5YSa35/fkL8GNJcyR9uK5Ov/xdHt3gNfxQ0rV189+SdGsttjZ1z5H0jKSXJf0hP7dy/a/X1btR0qSO3rtKigg/Cn4AmwIvAJOBI4DN2yzfEfgA0B9oAe4BvlO3fD7w/jx9BnA/MCTX/0/gZ3nZZ4FfAn8D9AH2BjZtJ6b5wCxgKLAR6cfCTODfSEco2wNPAofl+ucBbwEfB/oB/ww8laf7AfOAc/K6BwOvADvnda8CXgIOyM8zIJdd2Mn7tuJ15/m7gKeBXUlHt/2Au4FL8zZHA4uAQ+pifgM4LNe/Osf8lbzuZ4Cn2nnunYEFwLZ5fjiwQ57eG9g/b3M48BhwRt26AeyYp78DTAG2ADbJn8/X8rKvAZfXvYfvIR3VNPWeNBnHVGAgMCy/N4fXvTfX1NUdnuv3zfMfBHYABLyPlHD3ysvGAsuAr5O+gxsBZwLX1W3vKOCRdl7Dxvn7cnze1qK69/n9wPw8vSvwJ+Dv8vwIYPs8vW1e773A+Ly9vy36f71sj8ID8CN/ELALaafXmv95pgBbt1P3aODhuvn6f/rHyDu4PL8NacfcFzgJ+B2wRxPxzAdOqpvfD3i6TZ2zgR/n6fOA++uWbQAszDut9wB/ATaoW/4z4Lw8fRVwdZttX8WaJYDz6+aHAsuBTerKvgZcVRfztLplHwaWAn3y/CZ5pzewwXPvCDyXd0j9OonzDOCmuvnI6wt4lZw48rJ3kZMO6RzHzeRk0eT3aJX3pIk4Dqybvx44q+69aTcBNNj2L4DT8/RY4K/AgLrl25KS/qZ5/gbgzA5ex7tJP4qeBj5RV16fAHYGngUOaRQX8Im8/gvAu7rj/3R9e7gJqCQi4rGI+HREDAF2I/3DfAdA0laSrs3NDS8D1wCD2tnUdsBN+bB/CSkhLAe2Bv4LuBW4Nh82XyypXwdhLWiz3W1r283bPidvd7X6kdreW/Pr2BZYEKu2x/8JGNzOc62N+u1sCyyOiFc6eN5n66ZfB56PiOV185B+ka4iIuaRdqjnAc/lz2dbgNyMNFXSX/Ln9e80/rxaSEdjM+ve01/ncoBvkH653pabWc7q5LWvosk4/lI3/Vqj19rOto+QdH9umloCHNlm24si4o3aTEQ8A/wW+JhS8+URwE86eIr7SDvv5aRksZqIeBz4EilRPifpZ5L+rq7KFNIRyJyIuK+Z11U1TgAlFBF/IP0C3i0XfY3062uPiNiUdGi8WntotgA4IiIG1j0GRMSfI+KtiPhqRIwi/cL6EHBCR6G02e5Tbba7SUQcWVdnaG0it1UPAZ7Jj6Ft2q+HAX9u57kazTerfr1ngC0kbdLB866xiPhpRBxISo5BavIAuAz4AzAyf17n0Pjzep6UZHate083i4iN8/ZfiYgvRcT2pKOTf6qdZ2hSs3E08iopOdWs2LFK6g/cCHyTdJQ6ELilzbYbfX6TSd/dY4D7IqKjz+G0vL3nSTv5hiLimog4gNT804f0v1LzNeD3wHBJx3TwXJXlBFACkt4h6UuShuT5ocBxpLZ8SE0RS4ElkgYD/9LB5i4HJkraLm+rRdJRefogSbsrXWXzMqlpaHn7m1rFg8DL+cTeRpL6SNpNq16qurekv88nCs8gXcV0P/AAaYdyZj75N5a0Q7uW9j1LOs+wxiJiAanJ62tKJ8D3IJ1g7uiXZ1Mk7Szp4LwzfIO0I6+9l5uQ3t+lkt5BurqrUXxvAz8ELpG0Vd7uYEmH5ekPSdoxn/x8OW+/2c+r6TjaMQt4r6RhkjYjNffVbEj6Zb0IWCbpCKDdk+V1fgHsBZxOOt/SkKRdSEdWnyIljHMk7d6oXv5O9ye9/ys+A0kH53XH58elkrZpIsZKcQIoh1dIbewPKF0Fcz8wh5W/fL5K+sd5CfgV8PMOtvUfpEPf2yS9kre1X172d6TD6ZdJTUN3k5qTOpWbRT5MOpH6FOmX2Y+Azeqq3QwcC7xI+uf9+3zU8VfgI6TD/udJJ2VPyEc67bkCGJWbRtbmGv/jSO3XzwA3AedGxLS12F5Nf+Ai0uv5C7AV6Rc2pBPg/0D6XH8IXNfBdr5Maua5PzfT/C+pbRtgZJ5fSmoSuTS6do1/V+JYRX6PrgNmk07+T61b9grpF/r1pM/6H0jfuc62+TrpyGEEdd/h/GNiqaR35SbJa4CJEfFIbub5N+C/tPqVVP2Bi1n5GWwO/GtuYroK+MeIWJjfs6tJ3ymrowgPCGNrT9J5pJOVxxcdS5VJeho4PiLuKTqWRiT9G7CTvyfl4BvBzNYTklpIJ5DnFxxKQ0r3o5xMOjq0EnATkFkvktvklzZ4vEo6b/K9iHi66DjbUroBbwHwP2U9OqkiNwGZmVWUjwDMzCrKCcDMrKJKfRJ40KBBMXz48KLDMDPrVWbOnPl8RLR0Vq/UCWD48OHMmDGj6DDMzHoVSX9qpp6bgMzMKsoJwMysopwAzMwqqtTnAMzMOvLWW2/R2trKG2+80Xnl9dCAAQMYMmQI/fp11Kt7+5wAzKzXam1tZZNNNmH48OE0GDFyvRYRvPDCC7S2tjJixIg12kbTTUC5x76HJU3N8yMkPaA0nuh1tZ76lMY4vU5p/NUHJA2v28bZufzxWpe3ZmZr6o033mDLLbes3M4fQBJbbrnlWh39dOUcwOmkLoRrvg5cEhEjSV3CnpzLTwZejIgdgUtyPSSNAsaRxvE8nNQ/d581jtzMDCq5869Z29feVALIA5V8kNT/O3mAioNZOVTbZNI4tZAGe56cp28ADsn1jwKujYg3I+IpUh/o+65V9GZmBZs4cSK77rore+yxB6NHj+aBBx7osP6nP/1pbrih4SiXPa7ZcwDfAc4kjTAEsCWwJCKW5flWVo6zOpg8LmtELJP0Uq4/mJUjXLVdZwVJE4AJAMOGDWv6hVj3Gn7Wr7p9m/Mv+mC3b9OsXnd/bzv7zt53331MnTqVhx56iP79+/P888/z17/+tVtjWJc6PQKQ9CHguYiYWV/coGp0sqyjdVYWREyKiDERMaalpdM7mc3MCrNw4UIGDRpE//79ARg0aBDbbrstAOeffz777LMPu+22GxMmTKBRz8szZ87kfe97H3vvvTeHHXYYCxcuBOC73/0uo0aNYo899mDcuHHrLP5mmoAOAD4iaT5pDNeDSUcEA/PYr7By8G9Iv+yHAuTlmwGL68sbrGNm1usceuihLFiwgJ122onPf/7z3H333SuWnXrqqUyfPp05c+bw+uuvM3Xq1FXWfeutt/jCF77ADTfcwMyZMznppJP4yle+AsBFF13Eww8/zOzZs7n88svXWfydJoCIODsihkTEcNJJ3Dsi4pPAncDHc7XxpPFgIY0NOj5PfzzXj1w+Ll8lNII03umD3fZKzMx62MYbb8zMmTOZNGkSLS0tHHvssVx11VUA3Hnnney3337svvvu3HHHHcydO3eVdR9//HHmzJnDBz7wAUaPHs2FF15Ia2srAHvssQef/OQnueaaa+jbd91drb82W/4ycK2kC4GHWTng8hWkAZznkX75jwOIiLmSrgceBZYBp+SBxs3Meq0+ffowduxYxo4dy+67787kyZMZN24cn//855kxYwZDhw7lvPPOW+1yzYhg11135b777lttm7/61a+45557mDJlChdccAFz585dJ4mgS11BRMRdEfGhPP1kROwbETtGxDER8WYufyPP75iXP1m3/sSI2CEido6I/+nel2Jm1rMef/xxnnjiiRXzs2bNYrvttluxsx80aBBLly5teNXPzjvvzKJFi1YkgLfeeou5c+fy9ttvs2DBAg466CAuvvhilixZwtKlS9dJ/L4T2MxsDS1dupQvfOELLFmyhL59+7LjjjsyadIkBg4cyGc+8xl23313hg8fzj777LPauhtuuCE33HADp512Gi+99BLLli3jjDPOYKedduL444/npZdeIiL44he/yMCBA9dJ/KUeE3jMmDHh8QCK4ctArTd47LHH2GWXXYoOo1CN3gNJMyNiTGfrujdQM7OKcgIwM6soJwAzs4pyAjCzXq3M5zHXtbV97U4AZtZrDRgwgBdeeKGSSaA2HsCAAQPWeBu+DNTMeq0hQ4bQ2trKokWLig6lELURwdaUE4CZ9Vr9+vVb49GwzE1AZmaV5QRgZlZRTgBmZhXlBGBmVlFOAGZmFeUEYGZWUU4AZmYV1cyg8AMkPSjp95LmSvpqLr9K0lOSZuXH6FwuSd+VNE/SbEl71W1rvKQn8mN8e89pZmbrXjM3gr0JHBwRSyX1A+6VVBvN618iou1QN0eQxvsdCewHXAbsJ2kL4FxgDBDATElTIuLF7nghZmbWNc0MCh8RURuPrF9+dNTxxlHA1Xm9+4GBkrYBDgOmRcTivNOfBhy+duGbmdmaauocgKQ+kmYBz5F24g/kRRNzM88lkvrnssHAgrrVW3NZe+VmZlaAphJARCyPiNHAEGBfSbsBZwPvAPYBtgC+nKur0SY6KF+FpAmSZkiaUdUOnszMekKXrgKKiCXAXcDhEbEwN/O8CfwY2DdXawWG1q02BHimg/K2zzEpIsZExJiWlpauhGdmZl3QzFVALZIG5umNgPcDf8jt+kgScDQwJ68yBTghXw20P/BSRCwEbgUOlbS5pM2BQ3OZmZkVoJmrgLYBJkvqQ0oY10fEVEl3SGohNe3MAj6X698CHAnMA14DTgSIiMWSLgCm53rnR8Ti7nspZmbWFZ0mgIiYDbyzQfnB7dQP4JR2ll0JXNnFGM3MbB3wncBmZhXlBGBmVlFOAGZmFeUEYGZWUU4AZmYV5QRgZlZRTgBmZhXlBGBmVlFOAGZmFeUEYGZWUU4AZmYV5QRgZlZRTgBmZhXlBGBmVlFOAGZmFeUEYGZWUU4AZmYV1cyYwAMkPSjp95LmSvpqLh8h6QFJT0i6TtKGubx/np+Xlw+v29bZufxxSYetqxdlZmada+YI4E3g4IjYExgNHJ4He/86cElEjAReBE7O9U8GXoyIHYFLcj0kjQLGAbsChwOX5nGGzcysAJ0mgEiW5tl++RHAwcANuXwycHSePirPk5cfIkm5/NqIeDMiniINGr9vt7wKMzPrsqbOAUjqI2kW8BwwDfgjsCQiluUqrcDgPD0YWACQl78EbFlf3mAdMzPrYU0lgIhYHhGjgSGkX+27NKqW/6qdZe2Vr0LSBEkzJM1YtGhRM+GZmdka6NJVQBGxBLgL2B8YKKlvXjQEeCZPtwJDAfLyzYDF9eUN1ql/jkkRMSYixrS0tHQlPDMz64JmrgJqkTQwT28EvB94DLgT+HiuNh64OU9PyfPk5XdEROTycfkqoRHASODB7nohZmbWNX07r8I2wOR8xc4GwPURMVXSo8C1ki4EHgauyPWvAP5L0jzSL/9xABExV9L1wKPAMuCUiFjevS/HzMya1WkCiIjZwDsblD9Jg6t4IuIN4Jh2tjURmNj1MM3MrLv5TmAzs4pyAjAzqygnADOzinICMDOrKCcAM7OKcgIwM6soJwAzs4pyAjAzqygnADOzinICMDOrKCcAM7OKcgIwM6soJwAzs4pyAjAzqygnADOzinICMDOrKCcAM7OKamZM4KGS7pT0mKS5kk7P5edJ+rOkWflxZN06Z0uaJ+lxSYfVlR+ey+ZJOmvdvCQzM2tGM2MCLwO+FBEPSdoEmClpWl52SUR8s76ypFGkcYB3BbYF/lfSTnnxD4APAK3AdElTIuLR7nghZmbWNc2MCbwQWJinX5H0GDC4g1WOAq6NiDeBp/Lg8LWxg+flsYSRdG2u6wRgZlaALp0DkDScNED8A7noVEmzJV0pafNcNhhYULdaay5rr9zMzArQdAKQtDFwI3BGRLwMXAbsAIwmHSF8q1a1werRQXnb55kgaYakGYsWLWo2PDMz66KmEoCkfqSd/08i4ucAEfFsRCyPiLeBH7KymacVGFq3+hDgmQ7KVxERkyJiTESMaWlp6errMTOzJjVzFZCAK4DHIuLbdeXb1FX7KDAnT08BxknqL2kEMBJ4EJgOjJQ0QtKGpBPFU7rnZZiZWVc1cxXQAcCngEckzcpl5wDHSRpNasaZD3wWICLmSrqedHJ3GXBKRCwHkHQqcCvQB7gyIuZ242sxM7MuaOYqoHtp3H5/SwfrTAQmNii/paP1zMys5/hOYDOzinICMDOrKCcAM7OKcgIwM6soJwAzs4pyAjAzqygnADOzinICMDOrKCcAM7OKcgIwM6soJwAzs4pyAjAzqygnADOzinICMDOrKCcAM7OKcgIwM6soJwAzs4pqZkzgoZLulPSYpLmSTs/lW0iaJumJ/HfzXC5J35U0T9JsSXvVbWt8rv+EpPHr7mWZmVlnmjkCWAZ8KSJ2AfYHTpE0CjgLuD0iRgK353mAI0gDwY8EJgCXQUoYwLnAfsC+wLm1pGFmZj2v0wQQEQsj4qE8/QrwGDAYOAqYnKtNBo7O00cBV0dyPzBQ0jbAYcC0iFgcES8C04DDu/XVmJlZ07p0DkDScOCdwAPA1hGxEFKSALbK1QYDC+pWa81l7ZWbmVkB+jZbUdLGwI3AGRHxsqR2qzYoiw7K2z7PBFLTEcOGDWs2PIaf9aum6zZr/kUf7PZtmpmVRVNHAJL6kXb+P4mIn+fiZ3PTDvnvc7m8FRhat/oQ4JkOylcREZMiYkxEjGlpaenKazEzsy5o5iogAVcAj0XEt+sWTQFqV/KMB26uKz8hXw20P/BSbiK6FThU0ub55O+huczMzArQTBPQAcCngEckzcpl5wAXAddLOhl4GjgmL7sFOBKYB7wGnAgQEYslXQBMz/XOj4jF3fIqzMysyzpNABFxL43b7wEOaVA/gFPa2daVwJVdCdDMzNYN3wlsZlZRTgBmZhXlBGBmVlFOAGZmFeUEYGZWUU4AZmYV5QRgZlZRTfcFZGbrN/enVT0+AjAzqygnADOzinICMDOrKCcAM7OKcgIwM6soJwAzs4pyAjAzqygnADOzinICMDOrqGbGBL5S0nOS5tSVnSfpz5Jm5ceRdcvOljRP0uOSDqsrPzyXzZN0Vve/FDMz64pmjgCuAg5vUH5JRIzOj1sAJI0CxgG75nUuldRHUh/gB8ARwCjguFzXzMwK0syYwPdIGt7k9o4Cro2IN4GnJM0D9s3L5kXEkwCSrs11H+1yxGZm1i3W5hzAqZJm5yaizXPZYGBBXZ3WXNZeuZmZFWRNewO9DLgAiPz3W8BJgBrUDRonmmi0YUkTgAkAw4YNW8Pwyss9LppZWazREUBEPBsRyyPibeCHrGzmaQWG1lUdAjzTQXmjbU+KiDERMaalpWVNwjMzsyasUQKQtE3d7EeB2hVCU4BxkvpLGgGMBB4EpgMjJY2QtCHpRPGUNQ/bzMzWVqdNQJJ+BowFBklqBc4FxkoaTWrGmQ98FiAi5kq6nnRydxlwSkQsz9s5FbgV6ANcGRFzu/3VmJlZ05q5Cui4BsVXdFB/IjCxQfktwC1dis7MzNYZ3wlsZlZRTgBmZhXlBGBmVlFOAGZmFeUEYGZWUU4AZmYV5QRgZlZRTgBmZhXlBGBmVlFOAGZmFeUEYGZWUU4AZmYV5QRgZlZRTgBmZhXlBGBmVlFOAGZmFeUEYGZWUZ0mAElXSnpO0py6si0kTZP0RP67eS6XpO9KmidptqS96tYZn+s/IWn8unk5ZmbWrGaOAK4CDm9TdhZwe0SMBG7P8wBHkAaCHwlMAC6DlDBIYwnvB+wLnFtLGmZmVoxOE0BE3AMsblN8FDA5T08Gjq4rvzqS+4GBkrYBDgOmRcTiiHgRmMbqScXMzHrQmp4D2DoiFgLkv1vl8sHAgrp6rbmsvXIzMytI327enhqURQflq29AmkBqPmLYsGHdF5mZrReGn/Wrbt/m/Is+2O3b7A3W9Ajg2dy0Q/77XC5vBYbW1RsCPNNB+WoiYlJEjImIMS0tLWsYnpmZdWZNE8AUoHYlz3jg5rryE/LVQPsDL+UmoluBQyVtnk/+HprLzMysIJ02AUn6GTAWGCSplXQ1z0XA9ZJOBp4GjsnVbwGOBOYBrwEnAkTEYkkXANNzvfMjou2JZTMz60GdJoCIOK6dRYc0qBvAKe1s50rgyi5FZ2Zm64zvBDYzqygnADOzinICMDOrKCcAM7OKcgIwM6soJwAzs4rq7q4gzKwNd11gZeUjADOzinICMDOrKCcAM7OKcgIwM6soJwAzs4pyAjAzqygnADOzinICMDOrKCcAM7OKcgIwM6uotUoAkuZLekTSLEkzctkWkqZJeiL/3TyXS9J3Jc2TNFvSXt3xAszMbM10xxHAQRExOiLG5PmzgNsjYiRwe54HOAIYmR8TgMu64bnNzGwNrYvO4I4iDSIPMBm4C/hyLr86jxt8v6SBkraJiIXrIAYzs0L1hk4A1/YIIIDbJM2UNCGXbV3bqee/W+XywcCCunVbc5mZmRVgbY8ADoiIZyRtBUyT9IcO6qpBWaxWKSWSCQDDhg1by/BsfdYbfmGZldlaHQFExDP573PATcC+wLOStgHIf5/L1VuBoXWrDwGeabDNSRExJiLGtLS0rE14ZmbWgTVOAJL+VtImtWngUGAOMAUYn6uNB27O01OAE/LVQPsDL7n938ysOGvTBLQ1cJOk2nZ+GhG/ljQduF7SycDTwDG5/i3AkcA84DXgxLV4bjMzW0trnAAi4klgzwblLwCHNCgP4JQ1fT4zM+tevhPYzKyinADMzCrKCcDMrKKcAMzMKsoJwMysopwAzMwqygnAzKyinADMzCrKCcDMrKKcAMzMKsoJwMysopwAzMwqygnAzKyinADMzCrKCcDMrKKcAMzMKsoJwMysono8AUg6XNLjkuZJOqunn9/MzJIeTQCS+gA/AI4ARgHHSRrVkzGYmVnS00cA+wLzIuLJiPgrcC1wVA/HYGZm9HwCGAwsqJtvzWVmZtbDFBE992TSMcBhEfF/8vyngH0j4gt1dSYAE/LszsDj3RzGIOD5bt7muuA4u5fj7F69Ic7eECOsmzi3i4iWzir17eYn7UwrMLRufgjwTH2FiJgETFpXAUiaERFj1tX2u4vj7F6Os3v1hjh7Q4xQbJw93QQ0HRgpaYSkDYFxwJQejsHMzOjhI4CIWCbpVOBWoA9wZUTM7ckYzMws6ekmICLiFuCWnn7eOuuseambOc7u5Ti7V2+IszfECAXG2aMngc3MrDzcFYSZWUU5AZiZVZQTQElI6iPpmqLjWF9IOl3SpkqukPSQpEOLjsusTHr8JHBPkvRPHS2PiG/3VCydiYjlklokbZi7ySgdSX/f0fKI+HlPxdKEkyLiPyQdBrQAJwI/Bm4rNqzGJG0OjAQG1Moi4p7iIlqdpN1IfXjVx3h1cRE1JmkwsB11+7cSvpc7AK0R8aakscAewNURsaQn41ivEwCwSdEBdNF84LeSpgCv1gpLlKg+nP9uBbwbuCPPHwTcBZQpASj/PRL4cUT8XpI6WqEokv4PcDrpxshZwP7AfcDBRcZVT9K5wFhSAriF1KHjvUCpEoCkrwPHAo8Cy3NxAKVKAMCNwBhJOwJXkO6H+inp+9pj1usEEBFfLTqGLnomPzaghMkrIk4EkDQVGBURC/P8NqReXstkpqTbgBHA2ZI2Ad4uOKb2nA7sA9wfEQdJegdQtu/ux4E9gYcj4kRJWwM/KjimRo4Gdo6IN4sOpBNv5/uiPgp8JyK+J+nhng5ivU4ANZJ+TPoVsIqIOKmAcNrVixLW8NrOP3sW2KmoYNpxMjAaeDIiXpO0JakZqIzeiIg3JCGpf0T8QdLORQfVxusR8bakZZI2BZ4Dti86qAaeBPoBZU8Ab0k6DhjPyiPrfj0dRCUSADC1bnoA8FHa9EFUBpJagDOBXVm1nbU0TQHZXZJuBX5GSqzjgDuLDWlVeWf1FLCTpAGdrlCsVkkDgV8A0yS9SPm+nzNyjD8EZgJLgQeLDamh14BZkm6nLglExGnFhdTQicDngIkR8ZSkEUCPXwRSyRvBJG0A/G/Zdqy5yeI64J9JX47xwKKI+HKhgTWQD13fm2fviYibioynrfba1cv2mbcl6X3AZsCvS3wxwHBg04iYXXAoq5E0vlF5REzu6Vh6g6omgJ2BX0XEjkXHUk/SzIjYW9LsiNgjl90dEe8rOraaPKrbrRHx/qLcO+AtAAANUElEQVRj6YikR1jZrj661q4eEccWHNoKkrboaHlELO6pWNojaa+OlkfEQz0VS7NyR5O1JsnHI+KtIuOpJ+n6iPhE/n42apbeoyfjqUQTkKRXSG+28t+/AKX7VQ3UvqgLJX2Q1AwwpMB4VpMvV31N0mYR8VLR8XSgN7Srz2Tl97KtoBxt7N/qYFlQoiuVAPIllZNJV9QJGCppfIkuAz09//1QoVFklUgAEVG6K2racaGkzYAvAd8DNgW+WGxIDb0BPCJpGqterlqmdtbSt6tHxIiiY+hMRBxUdAxd9C3g0Ih4HEDSTqRzVXsXGlVWu3giIv5UdCxQoSag3nCjTW/R29pZy96uLum9jcrL9P2U9DfAPwHDImKCpJGkyy2ndrJqj6pvPu2orGh1rRIAG5KuAHo1Ijbt0TiqkAB6ywlBSZOB02t3A+ak9a2yXa7aW+T3byir3hFaxjbrX9bNDgD2BWaW6fsp6TpSk9UJEbGbpI1I/0OjCw5tFZKuJO1Y/ysXHQ/0qd3DUlaSjiYNj3tOjz5vRRJA6U8IAkh6OCLe2VlZ0fKvv6+xercAZWizBkDSBcCnSdeF124AizLtVNsjaShwcUQcV3QsNbVhC+u/j5J+HxF7Fh1bPUn9gVOAA0nnAO4BLu0FN4Yh6f6I2L8nn7MS5wDoHScEATaQtHlEvAgrrhIp42f0Y+Bc4BJSNxAn0vhEZpE+AexQxiafJrQCuxUdRBt/zb/6A1b0ZVO6nWre0X8b+Hb+/xlSxp1/m361NgDG0OCqoHWtjDuXdaH0JwSzbwG/k3RDnj8GmFhgPO3ZKCJul6R8Mus8Sb8hJYWymAMMJN2xWmqSvsfKf/4NSHcw/764iBo6F/g16aqanwAHkI6wSkXSXcBHSPu2WcCifCl1hx1DFuDDddPLSFctHdXTQVSiCaheLzghOIp0aZ2A2yPi0YJDWo2k3wLvAW4gdQj3Z+CiiCjNUZWkMcDNpERQf0foRwoLqh1tTqovA+ZHxG+Liqc9uTuN/Unfzfsj4vmCQ1pNrYkqn/cbGhHnlvEkcFms1wkgdwHwOWBH4BHgiohYVmxU7StLF7GdkbQP8BjpF/YFpIR6cUTcX2hgdSTNBf6T9Lmv6AQuIu4uLKgm1E5cl+UuW0nvyE2mDW8IK9tJ9Xy+71DSvQBfiYjpZUwAkoaQLvU+gHT0dy/pApDWHo1jPU8A15FurvoNqfvaP0XE6R2vVRxJs0htgcNJh9u/JF1q16NdxK4PynYHdUcaNVsApWi2kDQpX/bZqK+n0p1Ul3QM8H+BeyPi85K2B74RER8rOLRV5HtofsqqVyt9MiI+0KNxrOcJ4JGI2D1P9wUejIgOb20vkqSHImIvSWeSel/8XkmvAtoJ+BdWH3SjNDsDSd8mNf1MYdUmoFL9YoXyN1vkvrPeVcZmqd5K0qy2l9A2KlvX1veTwCv6AInU93aRsTSj1kXsCRTYRWwT/hu4nNQz5PJO6halljTrL6srXdcFWV+lMRU+AXyl6GDayj2rfhN4V9GxtEfSmRFxcZsT6iuU7C51gOclHU+6SxngOOCFng5ifU8Ae0p6OU8L2CjPi3T42qN33TXhRFK74HWk/oAK6SK2Ccsi4rKig+hIL+vC4KvAraRmi+m52eKJgmNq6zZJHwN+HuVsNngs/51RaBTNOwn4PulS6gB+RwHjVazXTUC9RW6e+nfSl+JpUoIaAlwFnFOW3gzreq88jXR55U2s2rxSeO+VNblPpXNZ2WX13cD5ZevALveuelpEXFJ0LB3JXRf8LemI73XK+yOq15J0RkR8p0ef0wmgeJIuIQ0B+cWIeCWXbQp8E3gtIs4oMr4apQFW2u29smR3At9IugS01j/Rp4A9I6LDge2LIOnOXnbEUjq5O412d2ZlvPy3LUlPR8SwHn1OJ4DiSXoC2KntoXX+dfiHiBhZTGS9V1lOsjVD0kTSpbTXsWrvqqU6YZ3vXj2QtKP9TUT8ouCQVsj397Sr7Jf/AkhaEBFDe/I51/dzAL1FNGpXjdT3fukytKRTgJ+06bTuuIi4tNjIVvG6pAMj4l4ASQeQmi7K6N35b21M6Nq4FaU5YS3pUtL9NLWTlp+T9IGIOKXAsFboDTv4JvT4/7qPAEpA0i9IJ9eublN+PPCJsh2+tvPrulSXq0raE7ia9MtawGLg0xFRmi4WJNWu8681qQXpHoB7I+KpYqJqLN9Yt1vth0q+NPSRiNi12MgStTPCFum9fbssndZp1W6gV1lE6mKlR3+U+wigHE4Bfi7pJFaOErUPsBFpAPuy2SD3A1TbGfQh9WleGnlHv2c+l0JEvNzJKkVoNFDRdsBXJJ0XEdf2dEAdeBwYBtQGMhkKlOJu5azRCFu1iyl6tIvljkTJBqfyEUCJSDoY2JX0xZ0bEbcXHFJDkr5Bulv5clKy+hywICK+VGRc9XK3wB8jxVl/s9r5RcXUrHy11f+W4abFupOrm5F+lDyY5/cDfhclHBta0mjgH0j3VTwF3BgR3y82qnLyEUCJRMQdpM7Vyu7LwGeBfyQlq9uAHxUa0epuBl4iHVGVrjvgjkTEYpXnrsVvFh1AM/Ld6eNYeUPVdaQfuL66qgM+ArD1kqQ5EVG2PvWbko8E/7VMXWuUnaS3SX1+nRwR83LZk2W6NLmMfARgTZN0fUR8or0TbmXpuyb7naTdI+KRogNpTzvv4xaksSpO6PmI2idpf9Jd6ruQzvf0oYAxbDvwMdIRwJ2Sfg1cS/kGKSodHwFY0yRtExELJW3XaHmkwWEKJWkOqfvnvsBI0pCQb7LyztXSJKkG72MAL0TEq43qF0nSDNIO9r9JPdaeAIyMHh7DtjOS/hY4mtQUdDDpRsCbIuK2QgMrKScAW2v5KqBxEfGTEsTyImlErYbKkKR6I60cE3hFL6WSfhcR7+5s3aLkk+nHAMe6Oa0xNwFZ0/IllacAg0ndLE8DTgX+mdSPfeEJAHjKO/l14jVJGwK/l3QxsJDUN1Bp5b6p/jM/rAEfAVjTJN0MvAjcBxwCbE5qDz49ImYVGVuNpFbSoOANRUS7y6x9ubnqWdLn/UVgU+Cy2glX6518BGBdsX3dADs/Ap4HhtU6sCuJPsDG+ARgt5B0FDAkIn6Q5+8GtiKdr7gPcALoxZwArCvqB9hZLumpku38ARb2hpu9epEzSSd/a/oDe5OS7I+BG4oIyrqHE4B1RW8YYMe//LvXhhGxoG7+3ty2vjhfcWO9mM8B2HpF0hZlGpimt5M0LyJ2bGfZHyNih56OybrPBkUHYNadvPPvdg9I+kzbQkmfJfULZL2YjwDMrF2StgJ+QbqZrjZAzd6kcwFHR8SzRcVma88JwMw6VddTLaSeantDp4XWCScAM7OK8jkAM7OKcgIwM6soJwArLUnLJc2qe5zVTdudL2lQd2yri897V+5VszY/RtJdPR2HWY1vBLMye73t4PPrga0kHRER/1N0IGY+ArBeJ/+C/3dJ90maIWkvSbdK+qOkz+U6YyXdI+kmSY9KulzSat93Sf8kaU5+nJHLLpB0el2diZJOy9P/Imm6pNmSvlpX53hJD+Yjlf/MXWQ38g3gXxvEMVzSbyQ9lB/vrnsdd0u6XtL/k3SRpE/m53pE0g65XoukG3Ns0yUdsObvsFVGRPjhRykfwHJSN9O1x7G5fD7wj3n6EmA2sAnQAjyXy8cCbwDbkzqImwZ8vG79QaTr2R8hdWu8MTAXeCdpIPmHct0NgD8CWwKHApNI3U1sAEwF3ksaJeuXQL+8zqXACQ1ez12kwVTuAA7K03flZX8DDMjTI4EZda9jCbAN6dr7PwNfzctOB76Tp38KHJinhwGPFf35+VH+h5uArMw6agKakv8+AmwcqVO6VyS9IWlgXvZgRDwJIOlnwIGs2nnZgaTRol7NdX4OvCcivivpBUnvBLYGHo6IFyQdSkoCD+f1NybtrPcgJZPpeSz3jYDnOnhdF5KOAr5cV9YP+L6k0aTEt1PdsukRsTDH+EegNrrVI6REAvB+YFTdWPKbStokytdZn5WIE4D1Vm/mv2/XTdfma9/rtje5tJ3vqOO4HwGfBv4OuLKu/tciYpUBRiR9AZgcEWc3E3hE3CHpAmD/uuIvkvrb35N0dPFG3bK2r6/+tdde6wbAuyLi9WZiMAOfA7D1276SRuS2/2OBe9ssvwc4WtLf5J4tPwr8Ji+7CTgc2Ae4NZfdCpwkaWMASYNzVwm3Ax/P00jaor1xk+tMJHW1XLMZqSvrt4FPkZqtuuI20uhs5BjWt5Pntg74CMDKbCNJ9SON/ToiunIp6H3ARcDupJ39TfULI+IhSVexslOzH0XEw3nZXyXdCSyJiOW57DZJuwD35aaWpcDxEfGopH8FbsvJ5i3S0JntDk0ZEbdIWlRXdClwo6RjgDuBrg4MfxrwA0mzSf/X9wCf6+I2rGLcFYStlySNBf45Ij60hutvQOr87JiIeKI7YzMrCzcBmbUhaRRpqMPbvfO39ZmPAMzMKspHAGZmFeUEYGZWUU4AZmYV5QRgZlZRTgBmZhXlBGBmVlH/H16V7GzEAeL6AAAAAElFTkSuQmCC\n", 142 | "text/plain": [ 143 | "
" 144 | ] 145 | }, 146 | "metadata": { 147 | "needs_background": "light" 148 | }, 149 | "output_type": "display_data" 150 | } 151 | ], 152 | "source": [ 153 | "data.plot(kind=\"bar\", title=f\"Sales report from {filename}\")" 154 | ] 155 | } 156 | ], 157 | "metadata": { 158 | "kernelspec": { 159 | "display_name": "Python 3", 160 | "language": "python", 161 | "name": "python3" 162 | }, 163 | "language_info": { 164 | "codemirror_mode": { 165 | "name": "ipython", 166 | "version": 3 167 | }, 168 | "file_extension": ".py", 169 | "mimetype": "text/x-python", 170 | "name": "python", 171 | "nbconvert_exporter": "python", 172 | "pygments_lexer": "ipython3", 173 | "version": "3.7.2" 174 | } 175 | }, 176 | "nbformat": 4, 177 | "nbformat_minor": 2 178 | } 179 | -------------------------------------------------------------------------------- /src/sales_january.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarteocarmo/automation-post/5e1d3f80b2e8e6d5961397e8349469e262fe3da1/src/sales_january.xlsx -------------------------------------------------------------------------------- /src/template.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Sales Report" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import pandas as pd\n", 17 | "import matplotlib.pyplot as plt\n", 18 | "%matplotlib inline" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": { 25 | "tags": [ 26 | "parameters" 27 | ] 28 | }, 29 | "outputs": [], 30 | "source": [ 31 | "filename = \"sales_january.xlsx\"" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 2, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "data = pd.read_excel(filename, index_col=0)" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 3, 46 | "metadata": {}, 47 | "outputs": [ 48 | { 49 | "data": { 50 | "text/html": [ 51 | "
\n", 52 | "\n", 65 | "\n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | "
Sales
Employee Name
Paul2000
Oscar1500
Richard4000
Thomas500
Ursula780
Gabriela1760
Allison1000
Louis530
\n", 111 | "
" 112 | ], 113 | "text/plain": [ 114 | " Sales \n", 115 | "Employee Name \n", 116 | "Paul 2000\n", 117 | "Oscar 1500\n", 118 | "Richard 4000\n", 119 | "Thomas 500\n", 120 | "Ursula 780\n", 121 | "Gabriela 1760\n", 122 | "Allison 1000\n", 123 | "Louis 530" 124 | ] 125 | }, 126 | "execution_count": 3, 127 | "metadata": {}, 128 | "output_type": "execute_result" 129 | } 130 | ], 131 | "source": [ 132 | "data" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 4, 138 | "metadata": {}, 139 | "outputs": [ 140 | { 141 | "data": { 142 | "text/plain": [ 143 | "" 144 | ] 145 | }, 146 | "execution_count": 4, 147 | "metadata": {}, 148 | "output_type": "execute_result" 149 | }, 150 | { 151 | "data": { 152 | "image/png": "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ZmZr6o033mDLLbes3M4fQBJbbrnlWh39dOUcwOmkLoRrvg5cEhEjSV3CnpzLTwZejIgdgUtyPSSNAsaRxvE8nNQ/d581jtzMDCq5869Z29feVALIA5V8kNT/O3mAioNZOVTbZNI4tZAGe56cp28ADsn1jwKujYg3I+IpUh/o+65V9GZmBZs4cSK77rore+yxB6NHj+aBBx7osP6nP/1pbrih4SiXPa7ZcwDfAc4kjTAEsCWwJCKW5flWVo6zOpg8LmtELJP0Uq4/mJUjXLVdZwVJE4AJAMOGDWv6hVj3Gn7Wr7p9m/Mv+mC3b9OsXnd/bzv7zt53331MnTqVhx56iP79+/P888/z17/+tVtjWJc6PQKQ9CHguYiYWV/coGp0sqyjdVYWREyKiDERMaalpdM7mc3MCrNw4UIGDRpE//79ARg0aBDbbrstAOeffz777LMPu+22GxMmTKBRz8szZ87kfe97H3vvvTeHHXYYCxcuBOC73/0uo0aNYo899mDcuHHrLP5mmoAOAD4iaT5pDNeDSUcEA/PYr7By8G9Iv+yHAuTlmwGL68sbrGNm1usceuihLFiwgJ122onPf/7z3H333SuWnXrqqUyfPp05c+bw+uuvM3Xq1FXWfeutt/jCF77ADTfcwMyZMznppJP4yle+AsBFF13Eww8/zOzZs7n88svXWfydJoCIODsihkTEcNJJ3Dsi4pPAncDHc7XxpPFgIY0NOj5PfzzXj1w+Ll8lNII03umD3fZKzMx62MYbb8zMmTOZNGkSLS0tHHvssVx11VUA3Hnnney3337svvvu3HHHHcydO3eVdR9//HHmzJnDBz7wAUaPHs2FF15Ia2srAHvssQef/OQnueaaa+jbd91drb82W/4ycK2kC4GHWTng8hWkAZznkX75jwOIiLmSrgceBZYBp+SBxs3Meq0+ffowduxYxo4dy+67787kyZMZN24cn//855kxYwZDhw7lvPPOW+1yzYhg11135b777lttm7/61a+45557mDJlChdccAFz585dJ4mgS11BRMRdEfGhPP1kROwbETtGxDER8WYufyPP75iXP1m3/sSI2CEido6I/+nel2Jm1rMef/xxnnjiiRXzs2bNYrvttluxsx80aBBLly5teNXPzjvvzKJFi1YkgLfeeou5c+fy9ttvs2DBAg466CAuvvhilixZwtKl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\n", 153 | "text/plain": [ 154 | "
" 155 | ] 156 | }, 157 | "metadata": { 158 | "needs_background": "light" 159 | }, 160 | "output_type": "display_data" 161 | } 162 | ], 163 | "source": [ 164 | "data.plot(kind=\"bar\", title=f\"Sales report from {filename}\")" 165 | ] 166 | } 167 | ], 168 | "metadata": { 169 | "celltoolbar": "Tags", 170 | "kernelspec": { 171 | "display_name": "Python 3", 172 | "language": "python", 173 | "name": "python3" 174 | }, 175 | "language_info": { 176 | "codemirror_mode": { 177 | "name": "ipython", 178 | "version": 3 179 | }, 180 | "file_extension": ".py", 181 | "mimetype": "text/x-python", 182 | "name": "python", 183 | "nbconvert_exporter": "python", 184 | "pygments_lexer": "ipython3", 185 | "version": "3.7.2" 186 | } 187 | }, 188 | "nbformat": 4, 189 | "nbformat_minor": 2 190 | } 191 | --------------------------------------------------------------------------------