From 1c8e49529394096a6bab0b63cbe697f8fb2f4412 Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Wed, 8 Oct 2025 11:31:41 +1300 Subject: [PATCH 01/23] rename --- .../Training/Intro_HPC/035-filedir-cont.md | 5 + .../Intro_HPC/095-writing-good-code.md | 269 ++++++ .../Intro_HPC/14-environment-variables.md | 258 +++++ .../Training/Intro_HPC/bash_shell.md | 901 ++++++++++++++++++ .../Training/Intro_HPC/filesystem_basics.md | 214 +++++ .../Training/Intro_HPC/modules.md | 258 +++++ .../Training/Intro_HPC/parallel.md | 202 ++++ .../Training/Intro_HPC/resources.md | 376 ++++++++ .../Training/Intro_HPC/scaling.md | 60 ++ .../Training/Intro_HPC/scheduler.md | 338 +++++++ .../Training/Intro_HPC/what_is_a_cluster.md | 93 ++ ...ting_on_the_NeSI_HPC_YouTube_Recordings.md | 14 - 12 files changed, 2974 insertions(+), 14 deletions(-) create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/035-filedir-cont.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/095-writing-good-code.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/14-environment-variables.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/bash_shell.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/filesystem_basics.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/modules.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/parallel.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/resources.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/scaling.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/scheduler.md create mode 100644 docs/Scientific_Computing/Training/Intro_HPC/what_is_a_cluster.md delete mode 100644 docs/Scientific_Computing/Training/Introduction_to_computing_on_the_NeSI_HPC_YouTube_Recordings.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/035-filedir-cont.md b/docs/Scientific_Computing/Training/Intro_HPC/035-filedir-cont.md new file mode 100644 index 000000000..ff8933246 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/035-filedir-cont.md @@ -0,0 +1,5 @@ +--- +title: "Navigating Files and Directories (Continued)" +layout: break +break: 50 +--- \ No newline at end of file diff --git a/docs/Scientific_Computing/Training/Intro_HPC/095-writing-good-code.md b/docs/Scientific_Computing/Training/Intro_HPC/095-writing-good-code.md new file mode 100644 index 000000000..089b16355 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/095-writing-good-code.md @@ -0,0 +1,269 @@ +--- +title: "Writing good code" +teaching: 20 +exercises: 10 +questions: +- "How do we write a good job script." +objectives: +- "Write a script that can be run serial or parallel." +- "Write a script that using SLURM environment variables." +- "Understand the limitations of random number generation." +keypoints: +- "Write your script in a way that is independent of data or environment. (elaborate)" +--- + +When talking about 'a script' we could be referring to multiple things. + +* Slurm/Bash script - Almost everyone will be using one of these to submit their Slurm jobs. +* Work script - If your work involves running another script (usually in a language other than Bash like Python, R or MATLAB) that will have to be invoked in your bash script. + +This section will cover best practice for both types of script. + + + +## Use environment variables + +In this lesson we will take a look at a few of the things to watch out for when writing scripts for use on the cluster. +This will be most relevant to people writing their own code, but covers general practices applicable to everyone. + +There is a lot of useful information contained within environment variable. + +> ## Slurm Environment +> +> For a small demo of the sort of useful info contained within env variables, run the command. +> +> ``` +> sbatch --output "slurm_env.out" --wrap "env | grep" +> ``` +> {: .language-bash} +> +> once the job has finished check the results with, +> +> ``` +> cat slurm_env.out +> ``` +> {: .language-bash} +> +> ``` +> SLURM_JOB_START_TIME=1695513911 +> SLURM_NODELIST=wbn098 +> SLURM_JOB_NAME=wrap +> SLURMD_NODENAME=wbn098 +> SLURM_TOPOLOGY_ADDR=top.s13.s7.wbn098 +> SLURM_PRIO_PROCESS=0 +> SLURM_NODE_ALIASES=(null) +> SLURM_JOB_QOS=staff +> SLURM_TOPOLOGY_ADDR_PATTERN=switch.switch.switch.node +> SLURM_JOB_END_TIME=1695514811 +> SLURM_MEM_PER_CPU=512 +> SLURM_NNODES=1 +> SLURM_JOBID=39572365 +> SLURM_TASKS_PER_NODE=2 +> SLURM_WORKING_CLUSTER=mahuika:hpcwslurmctrl01:6817:9984:109 +> SLURM_CONF=/etc/opt/slurm/slurm.conf +> SLURM_JOB_ID=39572365 +> SLURM_JOB_USER=cwal219 +> __LMOD_STACK_SLURM_I_MPI_PMI_LIBRARY=L29wdC9zbHVybS9saWI2NC9saWJwbWkyLnNv +> SLURM_JOB_UID=201333 +> SLURM_NODEID=0 +> SLURM_SUBMIT_DIR=/scale_wlg_persistent/filesets/home/cwal219 +> SLURM_TASK_PID=8747 +> SLURM_CPUS_ON_NODE=2 +> SLURM_PROCID=0 +> SLURM_JOB_NODELIST=wbn098 +> SLURM_LOCALID=0 +> SLURM_JOB_GID=201333 +> SLURM_JOB_CPUS_PER_NODE=2 +> SLURM_CLUSTER_NAME=mahuika +> SLURM_GTIDS=0 +> SLURM_SUBMIT_HOST=wbn003 +> SLURM_JOB_PARTITION=large +> SLURM_JOB_ACCOUNT=nesi99999 +> SLURM_JOB_NUM_NODES=1 +> SLURM_SCRIPT_CONTEXT=prolog_task +> ``` +> {: .output} +> +> Can you think of some examples as to how these variables could be used in your script? + +> > ## Solution +> > +> > * `SLURM_JOB_CPUS_PER_NODE` could be used to pass CPU numbers directly to any programs being used. +> > * Some other things. +> {: .solution} +{: .challenge} + +> ## Variables in Slurm Header +> +> Environment variables set by Slurm cannot be referenced in the Slurm header. +{: .callout} + +## Default values + +It is good practice to set default values when using environment variables when there is a chance they will be run in an environment where they may not be present. + +``` +FOO="${VARIABLE:-default}" +``` +{: .language-bash} + +`FOO` will be to to the value of `VARIABLE` if is set, otherwise it will be set to `default`. + +As a slight variation on the above example. (`:=` as opposed to `:-`). + +``` +FOO="${VARIABLE:=default}" +``` +{: .language-bash} + +`FOO` will be to to the value of `VARIABLE` if is set, otherwise it will be set to `default`, `VARIABLE` will also be set to `default`. + + + + +``` +num_cpus <- 2 +``` +{: .language-r} + +The number of CPU's being used is fixed in the script. We can save time and reduce chances for making mistakes by replacing this static value with an environment variable. +We can use the environment variable `SLURM_CPUS_PER_TASK`. + +``` +num_cpus <- strtoi(Sys.getenv('SLURM_CPUS_PER_TASK')) +``` +{: .language-r} + +Slurm sets many environment variables when starting a job, see [Slurm Documentation for the full list](https://slurm.schedmd.com/sbatch.html). + +The problem with this approach however, is our code will throw an error if we run it on the login node, or on our local machine or anywhere else that `SLURM_CPUS_PER_TASK` is not set. + +Generally it is best not to diverge your codebase especially if you don't have it under version control, so lets add some compatibility for those use cases. + +``` +num_cpus <- strtoi(Sys.getenv('SLURM_CPUS_PER_TASK', unset = "1")) +``` +{: .language-r} + +Now if `SLURM_CPUS_PER_TASK` variable is not set, 1 CPU will be used. You could also use some other method of detecting CPUs, like `detectCores()`. + +## Interoperability + +windows + mac + linux +headless + interactive + +## Verbose + +Having a printout of job progress is fine for an interactive terminal, but when you aren't seeing the updates in real time anyway, it's just bloat for your output files. + +Let's add an option to mute the updates. + +``` +print_progress <- FALSE +``` +{: .language-r} + + +``` +if (print_progress && percent_complete%%1==0){ + +``` +{: .language-r} + +## Reproduceability + +As this script uses [Pseudorandom number generation](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) there are a few additional factors to consider. +It is desirable that our output be reproducible so we can confirm that changes to the code have not affected it. + +We can do this by setting the seed of the PRNG. That way we will get the same progression of 'random' numbers. + +We are using the environment variable `SLURM_ARRAY_TASK_ID` for reasons we will get to later. We also need to make sure a default seed is set for the occasions when `SLURM_ARRAY_TASK_ID` is not set. + +``` +seed <- strtoi(Sys.getenv('SLURM_ARRAY_TASK_ID', unset = "0")) +set.seed(seed) +``` +{: .language-r} + + +Now your script should look something like this; + +``` +{% include example_scripts/sum_matrix.r %} +``` +{: .language-r} + +## Readability + +Comments! + +## Debugging + +``` +#!/bin/bash -e +``` +{: .language-bash} + +Exit bash script on error + +``` +#!/bin/bash -x +``` +{: .language-bash} + +Print environment. + +``` +env +``` +{: .language-bash} + +Print environment, if someone else has problems replicating the problem, it will likely come down to differences in your environment. + +``` +cat $0 +``` +{: .language-bash} + +Will print your input Slurm script to you output, this can help identify when changes in your submission script leads to errors. + +## Version control + +Version control is when changes to a document are tracked over time. + +In many cases you may be using the same piece of code across multiple environments, in these situations it can be difficult to keep track of changes made and your code can begin to diverge. Setting up version control like Git can save a lot of time. + +### Portability + + + +## Testing + +More often than not, problems come in the form of typos, or other small errors that become apparent within the first few seconds/minutes of script. + +Running on login node? + +Control + c to kill. + +{% include links.md %} diff --git a/docs/Scientific_Computing/Training/Intro_HPC/14-environment-variables.md b/docs/Scientific_Computing/Training/Intro_HPC/14-environment-variables.md new file mode 100644 index 000000000..b13cc5ca6 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/14-environment-variables.md @@ -0,0 +1,258 @@ +--- +title: Environment Variables +teaching: 10 +exercises: 5 +questions: +- "How are variables set and accessed in the Unix shell?" +- "How can I use variables to change how a program runs?" +objectives: +- "Understand how variables are implemented in the shell" +- "Read the value of an existing variable" +- "Create new variables and change their values" +- "Change the behaviour of a program using an environment variable" +- "Explain how the shell uses the `PATH` variable to search for executables" +keypoints: +- "Shell variables are by default treated as strings" +- "Variables are assigned using \"`=`\" and recalled using the variable's name prefixed by \"`$`\"" +- "Use \"`export`\" to make an variable available to other programs" +- "The `PATH` variable defines the shell's search path" +--- + +> ## Episode provenance +> +> This episode has been remixed from the +> [Shell Extras episode on Shell Variables](https://github.com/carpentries-incubator/shell-extras/blob/gh-pages/_episodes/08-environment-variables.md) +> and the [HPC Shell episode on scripts](https://github.com/hpc-carpentry/hpc-shell/blob/gh-pages/_episodes/05-scripts.md) +{: .callout} + +The shell is just a program, and like other programs, it has variables. +Those variables control its execution, +so by changing their values +you can change how the shell behaves (and with a little more effort how other +programs behave). + +Variables +are a great way of saving information under a name you can access later. In +programming languages like Python and R, variables can store pretty much +anything you can think of. In the shell, they usually just store text. The best +way to understand how they work is to see them in action. + +Let's start by running the command `set` and looking at some of the variables +in a typical shell session: + +~~~ +$ set +~~~ +{: .language-bash} + +~~~ +COMPUTERNAME=TURING +HOME=/home/vlad +HOSTNAME=TURING +HOSTTYPE=i686 +NUMBER_OF_PROCESSORS=4 +PATH=/Users/vlad/bin:/usr/local/git/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin +PWD=/home/vlad +UID=1000 +USERNAME=vlad +... +~~~ +{: .output} + +As you can see, there are quite a few — in fact, +four or five times more than what's shown here. +And yes, using `set` to *show* things might seem a little strange, +even for Unix, but if you don't give it any arguments, +it might as well show you things you *could* set. + +Every variable has a name. +All shell variables' values are strings, +even those (like `UID`) that look like numbers. +It's up to programs to convert these strings to other types when necessary. +For example, if a program wanted to find out how many processors the computer +had, it would convert the value of the `NUMBER_OF_PROCESSORS` variable from a +string to an integer. + +## Showing the Value of a Variable + +Let's show the value of the variable `HOME`: + +~~~ +$ echo HOME +~~~ +{: .language-bash} + +~~~ +HOME +~~~ +{: .output} + +That just prints "HOME", which isn't what we wanted +(though it is what we actually asked for). +Let's try this instead: + +~~~ +$ echo $HOME +~~~ +{: .language-bash} + +~~~ +/home/vlad +~~~ +{: .output} + +The dollar sign tells the shell that we want the *value* of the variable +rather than its name. +This works just like wildcards: +the shell does the replacement *before* running the program we've asked for. +Thanks to this expansion, what we actually run is `echo /home/vlad`, +which displays the right thing. + +## Creating and Changing Variables + +Creating a variable is easy — we just assign a value to a name using "=" +(we just have to remember that the syntax requires that there are _no_ spaces +around the `=`!): + +~~~ +$ SECRET_IDENTITY=Dracula +$ echo $SECRET_IDENTITY +~~~ +{: .language-bash} + +~~~ +Dracula +~~~ +{: .output} + +To change the value, just assign a new one: + +~~~ +$ SECRET_IDENTITY=Camilla +$ echo $SECRET_IDENTITY +~~~ +{: .language-bash} + +~~~ +Camilla +~~~ +{: .output} + +## Environment variables + +When we ran the `set` command we saw there were a lot of variables whose names +were in upper case. That's because, by convention, variables that are also +available to use by _other_ programs are given upper-case names. Such variables +are called _environment variables_ as they are shell variables that are defined +for the current shell and are inherited by any child shells or processes. + +To create an environment variable you need to `export` a shell variable. For +example, to make our `SECRET_IDENTITY` available to other programs that we call +from our shell we can do: + +~~~ +$ SECRET_IDENTITY=Camilla +$ export SECRET_IDENTITY +~~~ +{: .language-bash} + +You can also create and export the variable in a single step: + +~~~ +$ export SECRET_IDENTITY=Camilla +~~~ +{: .language-bash} + +> ## Using environment variables to change program behaviour +> +> Set a shell variable `TIME_STYLE` to have a value of `iso` and check this +> value using the `echo` command. +> +> Now, run the command `ls` with the option `-l` (which gives a long format). +> +> `export` the variable and rerun the `ls -l` command. Do you notice any +> difference? +> +> > ## Solution +> > +> > The `TIME_STYLE` variable is not _seen_ by `ls` until is exported, at which +> > point it is used by `ls` to decide what date format to use when presenting +> > the timestamp of files. +> > +> {: .solution} +{: .challenge} + +You can see the complete set of environment variables in your current shell +session with the command `env` (which returns a subset of what the command +`set` gave us). **The complete set of environment variables is called +your _runtime environment_ and can affect the behaviour of the programs you +run**. + +{% include {{ site.snippets }}/scheduler/print-sched-variables.snip %} + +To remove a variable or environment variable you can use the `unset` command, +for example: + +~~~ +$ unset SECRET_IDENTITY +~~~ +{: .language-bash} + +## The `PATH` Environment Variable + +Similarly, some environment variables (like `PATH`) store lists of values. +In this case, the convention is to use a colon ':' as a separator. +If a program wants the individual elements of such a list, +it's the program's responsibility to split the variable's string value into +pieces. + +Let's have a closer look at that `PATH` variable. +Its value defines the shell's search path for executables, +i.e., the list of directories that the shell looks in for runnable programs +when you type in a program name without specifying what directory it is in. + +For example, when we type a command like `analyze`, +the shell needs to decide whether to run `./analyze` or `/bin/analyze`. +The rule it uses is simple: +the shell checks each directory in the `PATH` variable in turn, +looking for a program with the requested name in that directory. +As soon as it finds a match, it stops searching and runs the program. + +To show how this works, +here are the components of `PATH` listed one per line: + +~~~ +/Users/vlad/bin +/usr/local/git/bin +/usr/bin +/bin +/usr/sbin +/sbin +/usr/local/bin +~~~ +{: .output} + +On our computer, +there are actually three programs called `analyze` +in three different directories: +`/bin/analyze`, +`/usr/local/bin/analyze`, +and `/users/vlad/analyze`. +Since the shell searches the directories in the order they're listed in `PATH`, +it finds `/bin/analyze` first and runs that. +Notice that it will *never* find the program `/users/vlad/analyze` +unless we type in the full path to the program, +since the directory `/users/vlad` isn't in `PATH`. + +This means that I can have executables in lots of different places as long as +I remember that I need to to update my `PATH` so that my shell can find them. + +What if I want to run two different versions of the same program? +Since they share the same name, if I add them both to my `PATH` the first one +found will always win. +In the next episode we'll learn how to use helper tools to help us manage our +runtime environment to make that possible without us needing to do a lot of +bookkeeping on what the value of `PATH` (and other important environment +variables) is or should be. + +{% include links.md %} diff --git a/docs/Scientific_Computing/Training/Intro_HPC/bash_shell.md b/docs/Scientific_Computing/Training/Intro_HPC/bash_shell.md new file mode 100644 index 000000000..501e218be --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/bash_shell.md @@ -0,0 +1,901 @@ +--- +title: "Navigating Files and Directories" +teaching: 30 +exercises: 10 +questions: +- "How can I move around the cluster filesystem" +- "How can I see what files and directories I have?" +- "How can I make new files and directories." +objectives: +- "Create, edit, manipulate and remove files from command line" +- "Translate an absolute path into a relative path and vice versa." +- "Use options and arguments to change the behaviour of a shell command." +- "Demonstrate the use of tab completion and explain its advantages." +keypoints: +- "The file system is responsible for managing information on the disk." +- "Information is stored in files, which are stored in directories (folders)." +- "Directories can also store other directories, which then form a directory tree." +- "`cd [path]` changes the current working directory." +- "`ls [path]` prints a listing of a specific file or directory; `ls` on its own lists the current working directory." +- "`pwd` prints the user's current working directory." +- "`cp [file] [path]` copies [file] to [path]" +- "`mv [file] [path]` moves [file] to [path]" +- "`rm [file]` deletes [file]" +- "`/` on its own is the root directory of the whole file system." +- "Most commands take options (flags) that begin with a `-`." +- "A relative path specifies a location starting from the current location." +- "An absolute path specifies a location from the root of the file system." +- "Directory names in a path are separated with `/` on Unix, but `\\` on Windows." +- "`..` means 'the directory above the current one'; `.` on its own means 'the current directory'." +--- +> ## The Unix Shell +> +> This episode will be a quick introduction to the Unix shell, only the bare minimum required to use the cluster. +> +> The Software Carpentry '[Unix Shell](https://swcarpentry.github.io/shell-novice/)' lesson covers the subject in more depth, we recommend you check it out. +> +{: .callout} + +The part of the operating system responsible for managing files and directories +is called the **file system**. +It organizes our data into files, +which hold information, +and directories (also called 'folders'), +which hold files or other directories. + +Understanding how to navigate the file system using command line is essential for using an HPC. + +The NeSI filesystem looks something like this: + +![The file system is made up of a root directory that contains sub-directories +titled home, nesi, and system files](../fig/NesiFiletree.svg) + +The directories that are relevant to us are. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LocationDefault StorageDefault FilesBackupAccess Speed
Home is for user-specific files such as configuration files, environment setup, source code, etc./home/<username>20GB1,000,000DailyNormal
Project is for persistent project-related data, project-related software, etc./nesi/project/<projectcode>100GB100,000DailyNormal
Nobackup is a 'scratch space', for data you don't need to keep long term. Old data is periodically deleted from nobackup/nesi/nobackup/<projectcode>10TB1,000,000NoneFast
+ +### Managing your data and storage (backups and quotas) + +NeSI performs backups of the `/home` and `/nesi/project` (persistent) filesystems. However, backups are only captured once per day. So, if you edit or change code or data and then immediately delete it, it likely cannot be recovered. Note, as the name suggests, NeSI does **not** backup the `/nesi/nobackup` filesystem. + +Protecting critical data from corruption or deletion is primarily your +responsibility. Ensure you have a data management plan and stick to the plan to reduce the chance of data loss. Also important is managing your storage quota. To check your quotas, use the `nn_storage_quota` command, eg + +{% include {{ site.snippets }}/filedir/sinfo.snip %} + +As well as disk space, 'inodes' are also tracked, this is the *number* of files. + +Notice that the project space for this user is over quota and has been locked, meaning no more data can be added. When your space is locked you will need to move or remove data. Also note that none of the nobackup space is being used. Likely data from project can be moved to nobackup. `nn_storage_quota` uses cached data, and so will no immediately show changes to storage use. + +For more details on our persistent and nobackup storage systems, including data retention and the nobackup autodelete schedule, +please see our [Filesystem and Quota](https://docs.nesi.org.nz/Storage/File_Systems_and_Quotas/NeSI_File_Systems_and_Quotas/) documentation. + + +Directories are like *places* — at any time +while we are using the shell, we are in exactly one place called +our **current working directory**. +Commands mostly read and write files in the +current working directory, i.e. 'here', so knowing where you are before running +a command is important. + +First, let's find out where we are by running the command `pwd` for '**p**rint **w**orking **d**irectory'. + +``` +{{ site.remote.prompt }} pwd +``` + +{: .language-bash} + +``` +/home/ +``` + +{: .output} + +The output we see is what is known as a 'path'. +The path can be thought of as a series of directions given to navigate the file system. + +At the top is the **root directory** +that holds all the files in a filesystem. + +We refer to it using a slash character, `/`, on its own. +This is what the leading slash in `/home/` is referring to, it is telling us our path starts at the root directory. + +Next is `home`, as it is the next part of the path we know it is inside the root directory, +we also know that home is another directory as the path continues. +Finally, stored inside `home` is the directory with your username. + +> ## Slashes +> +> Notice that there are two meanings for the `/` character. +> When it appears at the front of a file or directory name, +> it refers to the root directory. When it appears *inside* a path, +> it's just a separator. +{: .callout} + +As you may now see, using a bash shell is strongly dependent on the idea that +your files are organized in a hierarchical file system. +Organizing things hierarchically in this way helps us keep track of our work: +it's possible to put hundreds of files in our home directory, +just as it's possible to pile hundreds of printed papers on our desk, +but it's a self-defeating strategy. + +## Listing the contents of directories + +To **l**i**s**t the contents of a directory, we use the command `ls` followed by the path to the directory whose contents we want listed. + +We will now list the contents of the directory we we will be working from. We can +use the following command to do this: + +``` +{{ site.remote.prompt }} ls {{ site.working_dir[0] }} +``` + +{: .language-bash} + +``` +{{ site.working_dir[1] }} +``` + +{: .output} + +You should see a directory called `{{ site.working_dir[1] }}`, and possibly several other directories. For the purposes of this workshop you will be working within `{{ site.working_dir | join: '/' }}` + +> ## Command History +> +> You can cycle through your previous commands with the and keys. +> A convenient way to repeat your last command is to type then enter. +> +{: .callout} + +> ## `ls` Reading Comprehension +> +> What command would you type to get the following output +> +> ``` +> original pnas_final pnas_sub +> ``` +> +> {: .output} +> +> ![A directory tree below the Users directory where "/Users" contains the +directories "backup" and "thing"; "/Users/backup" contains "original", +"pnas_final" and "pnas_sub"; "/Users/thing" contains "backup"; and +"/Users/thing/backup" contains "2012-12-01", "2013-01-08" and +"2013-01-27"](../fig/filesystem-challenge.svg) +> +> 1. `ls pwd` +> 2. `ls backup` +> 3. `ls /Users/backup` +> 4. `ls /backup` +> +> > ## Solution +> > +> > 1. No: `pwd` is not the name of a directory. +> > 2. Possibly: It depends on your current directory (we will explore this more shortly). +> > 3. Yes: uses the absolute path explicitly. +> > 4. No: There is no such directory. +> {: .solution} +{: .challenge} + +## Moving about + +Currently we are still in our home directory, we want to move into the`project` directory from the previous command. + +The command to **c**hange **d**irectory is `cd` followed by the path to the directory we want to move to. + +The `cd` command is akin to double clicking a folder in a graphical interface. + +We will use the following command: + +``` +{{ site.remote.prompt }} cd {{ site.working_dir | join: '/' }} +``` + +{: .language-bash} + +``` +``` + +{: .output} +You will notice that `cd` doesn't print anything. This is normal. Many shell commands will not output anything to the screen when successfully executed. +We can check we are in the right place by running `pwd`. + +``` +{{ site.remote.prompt }} pwd +``` + +{: .language-bash} + +``` +{{ site.working_dir | join: '/' }} +``` + +{: .output} + +## Creating directories + + + +As previously mentioned, it is general useful to organise your work in a hierarchical file structure to make managing and finding files easier. It is also is especially important when working within a shared directory with colleagues, such as a project, to minimise the chance of accidentally affecting your colleagues work. So for this workshop you will each make a directory using the `mkdir` command within the workshops directory for you to personally work from. + +``` +{{ site.remote.prompt }} mkdir +``` + +{: .language-bash} + +You should then be able to see your new directory is there using `ls`. + +``` +{{ site.remote.prompt }} ls {{ site.working_dir | join: '/' }} +``` + +{: .language-bash} + +{% include {{ site.snippets }}/filedir/dir-contents1.snip %} + +## General Syntax of a Shell Command + +We are now going to use `ls` again but with a twist, this time we will also use what are known as **options**, **flags** or **switches**. +These options modify the way that the command works, for this example we will add the flag `-l` for "long listing format". + +``` +{{ site.remote.prompt }} ls -l {{ site.working_dir | join: '/' }} +``` + +{: .language-bash} + +{% include {{ site.snippets }}/filedir/dir-contents2.snip %} + +We can see that the `-l` option has modified the command and now our output has listed all the files in alphanumeric order, which can make finding a specific file easier. +It also includes information about the file size, time of its last modification, and permission and ownership information. + +Most unix commands follow this basic structure. +![Structure of a Unix command](../fig/Unix_Command_Struc.svg) + +The **prompt** tells us that the terminal is accepting inputs, prompts can be customised to show all sorts of info. + +The **command**, what are we trying to do. + +**Options** will modify the behavior of the command, multiple options can be specified. +Options will either start with a single dash (`-`) or two dashes (`--`).. +Often options will have a short and long format e.g. `-a` and `--all`. + +**Arguments** tell the command what to operate on (usually files and directories). + +Each part is separated by spaces: if you omit the space +between `ls` and `-l` the shell will look for a command called `ls-l`, which +doesn't exist. Also, capitalization can be important. +For example, `ls -s` will display the size of files and directories alongside the names, +while `ls -S` will sort the files and directories by size. + +Another useful option for `ls` is the `-a` option, lets try using this option together with the `-l` option: + +``` +{{ site.remote.prompt }} ls -la +``` + +{: .language-bash} + +{% include {{ site.snippets }}/filedir/dir-contents3.snip %} + +Single letter options don't usually need to be separate. In this case `ls -la` is performing the same function as if we had typed `ls -l -a`. + +You might notice that we now have two extra lines for directories `.` and `..`. These are hidden directories which the `-a` option has been used to reveal, you can make any file or directory hidden by beginning their filenames with a `.`. + +These two specific hidden directories are special as they will exist hidden inside every directory, with the `.` hidden directory representing your current directory and the `..` hidden directory representing the **parent** directory above your current directory. + +> ## Exploring More `ls` Flags +> +> You can also use two options at the same time. What does the command `ls` do when used +> with the `-l` option? What about if you use both the `-l` and the `-h` option? +> +> Some of its output is about properties that we do not cover in this lesson (such +> as file permissions and ownership), but the rest should be useful +> nevertheless. +> +> > ## Solution +> > +> > The `-l` option makes `ls` use a **l**ong listing format, showing not only +> > the file/directory names but also additional information, such as the file size +> > and the time of its last modification. If you use both the `-h` option and the `-l` option, +> > this makes the file size '**h**uman readable', i.e. displaying something like `5.3K` +> > instead of `5369`. +> {: .solution} +{: .challenge} + +## Relative paths + +You may have noticed in the last command we did not specify an argument for the directory path. +Until now, when specifying directory names, or even a directory path (as above), +we have been using what are known as **absolute paths**, which work no matter where you are currently located on the machine +since it specifies the full path from the top level root directory. + +An **absolute path** always starts at the root directory, which is indicated by a +leading slash. The leading `/` tells the computer to follow the path from +the root of the file system, so it always refers to exactly one directory, +no matter where we are when we run the command. + +Any path without a leading `/` is a **relative path**. + +When you use a relative path with a command +like `ls` or `cd`, it tries to find that location starting from where we are, +rather than from the root of the file system. + +In the previous command, since we did not specify an **absolute path** it ran the command on the relative path from our current directory +(implicitly using the `.` hidden directory), and so listed the contents of our current directory. + +We will now navigate to the parent directory, the simplest way do this is to use the relative path `..`. + +``` +{{ site.remote.prompt }} cd .. +``` + +{: .language-bash} + +We should now be back in `{{ site.working_dir[0] }}`. + +``` +{{ site.remote.prompt }} pwd +``` + +{: .language-bash} + +``` +{{ site.working_dir[0] }} +``` + +{: .output} + +## Tab completion + + Sometimes file paths and file names can be very long, making typing out the path tedious. + One trick you can use to save yourself time is to use something called **tab completion**. + If you start typing the path in a command and there is only one possible match, + if you hit tab the path will autocomplete (until there are more than one possible matches). + +For example, if you type: + +``` +{{ site.remote.prompt }} cd {{ site.working_dir | last | slice: 0,3 }} +``` +{: .language-bash} + +and then press Tab (the tab key on your keyboard), +the shell automatically completes the directory name for you (since there is only one possible match): + +``` +{{ site.remote.prompt }} cd {{ site.working_dir | last }}/ +``` +{: .language-bash} + + However, you want to move to your personal working directory. If you hit Tab once you will + likely see nothing change, as there are more than one possible options. Hitting Tab + a second time will print all possible autocomplete options. + +``` +cwal219/ riom/ harrellw/ +``` +{: .output} + +Now entering in the first few characters of the path (just enough that the possible options are no longer ambiguous) and pressing Tab again, should complete the path. + + Now press Enter to execute the command. + +``` +{{ site.remote.prompt }} cd {{ site.working_dir | last }}/ +``` +{: .language-bash} + +Check that we've moved to the right place by running `pwd`. + +``` +{{ site.working_dir | join: '/' }}/ +``` + +> ## Two More Shortcuts +> +> The shell interprets a tilde (`~`) character at the start of a path to +> mean "the current user's home directory". For example, if Nelle's home +> directory is `/home/nelle`, then `~/data` is equivalent to +> `/home/nelle/data`. This only works if it is the first character in the +> path: `here/there/~/elsewhere` is *not* `here/there//home/nelle/elsewhere`. +> +> Another shortcut is the `-` (dash) character. `cd` will translate `-` into +> *the previous directory I was in*, which is faster than having to remember, +> then type, the full path. This is a *very* efficient way of moving +> *back and forth between two directories* -- i.e. if you execute `cd -` twice, +> you end up back in the starting directory. +> +> The difference between `cd ..` and `cd -` is +> that the former brings you *up*, while the latter brings you *back*. +> +{: .callout} + +> ## Absolute vs Relative Paths +> +> Starting from `/home/amanda/data`, +> which of the following commands could Amanda use to navigate to her home directory, +> which is `/home/amanda`? +> +> 1. `cd .` +> 2. `cd /` +> 3. `cd home/amanda` +> 4. `cd ../..` +> 5. `cd ~` +> 6. `cd home` +> 7. `cd ~/data/..` +> 8. `cd` +> 9. `cd ..` +> +> > ## Solution +> > +> > 1. No: `.` stands for the current directory. +> > 2. No: `/` stands for the root directory. +> > 3. No: Amanda's home directory is `/home/amanda`. +> > 4. No: this command goes up two levels, i.e. ends in `/home`. +> > 5. Yes: `~` stands for the user's home directory, in this case `/home/amanda`. +> > 6. No: this command would navigate into a directory `home` in the current directory if it exists. +> > 7. Yes: unnecessarily complicated, but correct. +> > 8. Yes: shortcut to go back to the user's home directory. +> > 9. Yes: goes up one level. +> {: .solution} +{: .challenge} + +> ## Relative Path Resolution +> +> Using the filesystem diagram below, if `pwd` displays `/Users/thing`, +> what will `ls ../backup` display? +> +> 1. `../backup: No such file or directory` +> 2. `2012-12-01 2013-01-08 2013-01-27` +> 3. `original pnas_final pnas_sub` +> +> ![A directory tree below the Users directory where "/Users" contains the +directories "backup" and "thing"; "/Users/backup" contains "original", +"pnas_final" and "pnas_sub"; "/Users/thing" contains "backup"; and +"/Users/thing/backup" contains "2012-12-01", "2013-01-08" and +"2013-01-27"](../fig/filesystem-challenge.svg) +> +> > ## Solution +> > +> > 1. No: there *is* a directory `backup` in `/Users`. +> > 2. No: this is the content of `Users/thing/backup`, +> > but with `..`, we asked for one level further up. +> > 3. Yes: `../backup/` refers to `/Users/backup/`. +> > +> {: .solution} +{: .challenge} + +> ## Clearing your terminal +> +> If your screen gets too cluttered, you can clear your terminal using the +> `clear` command. You can still access previous commands using +> and to move line-by-line, or by scrolling in your terminal. +{: .callout} + +> ## Listing in Reverse Chronological Order +> +> By default, `ls` lists the contents of a directory in alphabetical +> order by name. The command `ls -t` lists items by time of last +> change instead of alphabetically. The command `ls -r` lists the +> contents of a directory in reverse order. +> Which file is displayed last when you combine the `-t` and `-r` flags? +> Hint: You may need to use the `-l` flag to see the +> last changed dates. +> +> > ## Solution +> > +> > The most recently changed file is listed last when using `-rt`. This +> > can be very useful for finding your most recent edits or checking to +> > see if a new output file was written. +> {: .solution} +{: .challenge} + +> ## Globbing +> +> One of the most powerful features of bash is *filename expansion*, otherwise known as *globbing*. +> This allows you to use *patterns* to match a file name (or multiple files), +> which will then be operated on as if you had typed out all of the matches. +> +> `*` is a **wildcard**, which matches zero or more characters. +> +> Inside the `{{ site.working_dir | join: '/' }}` directory there is a directory called `birds` +> +>``` +>{{ site.remote.prompt }} cd {{ site.working_dir | join: '/' }}/birds +>{{ site.remote.prompt }} ls +>``` +> {: .language-bash} +> +> ``` +> kaka.txt kakapo.jpeg kea.txt kiwi.jpeg pukeko.jpeg +> ``` +> {: .output} +> +> In this example there aren't many files, but it is easy to imagine a situation where you have hundreds or thousads of files you need to filter through, and globbing is the perfect tool for this. Using the wildcard character the command +> +>``` +>{{ site.remote.prompt }} ls ka* +>``` +> {: .language-bash} +> +> Will return: +> +>``` +>kaka.txt kakapo.jpeg +>``` +> {: .output} +> +> Since the pattern `ka*` will match `kaka.txt`and `kakapo.jpeg` as these both start with "ka". While the command: +> +>``` +>{{ site.remote.prompt }} ls *.jpeg +>``` +> {: .language-bash} +> +> Will return: +> +>``` +>kakapo.jpeg kiwi.jpeg pukeko.jpeg +>``` +> {: .output} +> +> As `*.jpeg` will match `kakapo.jpeg`, `kiwi.jpeg` and `pukeko.jpeg` as they all end in `.jpeg` +> You can use multiple wildcards as well with the command: +> +>``` +>{{ site.remote.prompt }} ls k*a.* +>``` +> {: .language-bash} +> +> Returning: +> +>``` +>kaka.txt kea.txt +>``` +> {: .output} +> +> As `k*a.*` will match just `kaka.txt` and `kea.txt` +> +> `?` is also a wildcard, but it matches exactly one character. So the command: +> +>``` +>{{ site.remote.prompt }} ls ????.* +>``` +> {: .language-bash} +> +> Would return: +>``` +>kaka.txt kiwi.jpeg +>``` +> {: .output} +> +> As `kaka.txt` and `kiwi.jpeg` the only files which have four characters, followed by a `.` then any number and combination of characters. +> +> When the shell sees a wildcard, it expands the wildcard to create a +> list of matching filenames *before* running the command that was +> asked for. As an exception, if a wildcard expression does not match +> any file, Bash will pass the expression as an argument to the command +> as it is. +> However, generally commands like `wc` and `ls` see the lists of +> file names matching these expressions, but not the wildcards +> themselves. It is the shell, not the other programs, that deals with +> expanding wildcards. +{: .callout} + +> ## List filenames matching a pattern +> +> Running `ls` in a directory gives the output +> `cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb` +> +> Which `ls` command(s) will +> produce this output? +> +> `ethane.pdb methane.pdb` +> +> 1. `ls *t*ane.pdb` +> 2. `ls *t?ne.*` +> 3. `ls *t??ne.pdb` +> 4. `ls ethane.*` +> +>> ## Solution +>> +>> The solution is `3.` +>> +>> `1.` shows all files whose names contain zero or more characters (`*`) +>> followed by the letter `t`, +>> then zero or more characters (`*`) followed by `ane.pdb`. +>> This gives `ethane.pdb methane.pdb octane.pdb pentane.pdb`. +>> +>> `2.` shows all files whose names start with zero or more characters (`*`) followed by +>> the letter `t`, +>> then a single character (`?`), then `ne.` followed by zero or more characters (`*`). +>> This will give us `octane.pdb` and `pentane.pdb` but doesn't match anything +>> which ends in `thane.pdb`. +>> +>> `3.` fixes the problems of option 2 by matching two characters (`??`) between `t` and `ne`. +>> This is the solution. +>> +>> `4.` only shows files starting with `ethane.`. +> {: .solution} +{: .challenge} + +include in terminal excersise (delete slurm files later on maybe?) + +## Create a text file + +Now let's create a file. To do this we will use a text editor called Nano to create a file called `draft.txt`: + +``` +{{ site.remote.prompt }} nano draft.txt +``` +{: .language-bash} + +> ## Which Editor? +> +> When we say, '`nano` is a text editor' we really do mean 'text': it can +> only work with plain character data, not tables, images, or any other +> human-friendly media. We use it in examples because it is one of the +> least complex text editors. However, because of this trait, it may +> not be powerful enough or flexible enough for the work you need to do +> after this workshop. On Unix systems (such as Linux and macOS), +> many programmers use [Emacs](http://www.gnu.org/software/emacs/) or +> [Vim](http://www.vim.org/) (both of which require more time to learn), +> or a graphical editor such as +> [Gedit](http://projects.gnome.org/gedit/). On Windows, you may wish to +> use [Notepad++](http://notepad-plus-plus.org/). Windows also has a built-in +> editor called `notepad` that can be run from the command line in the same +> way as `nano` for the purposes of this lesson. +> +> No matter what editor you use, you will need to know where it searches +> for and saves files. If you start it from the shell, it will (probably) +> use your current working directory as its default location. If you use +> your computer's start menu, it may want to save files in your desktop or +> documents directory instead. You can change this by navigating to +> another directory the first time you 'Save As...' +{: .callout} + +Let's type in a few lines of text. +Once we're happy with our text, we can press Ctrl+O +(press the Ctrl or Control key and, while +holding it down, press the O key) to write our data to disk +(we'll be asked what file we want to save this to: +press Return to accept the suggested default of `draft.txt`). + +
screenshot of nano text editor in action
+ +Once our file is saved, we can use Ctrl+X to quit the editor and +return to the shell. + +> ## Control, Ctrl, or ^ Key +> +> The Control key is also called the 'Ctrl' key. There are various ways +> in which using the Control key may be described. For example, you may +> see an instruction to press the Control key and, while holding it down, +> press the X key, described as any of: +> +> * `Control-X` +> * `Control+X` +> * `Ctrl-X` +> * `Ctrl+X` +> * `^X` +> * `C-x` +> +> In nano, along the bottom of the screen you'll see `^G Get Help ^O WriteOut`. +> This means that you can use `Control-G` to get help and `Control-O` to save your +> file. +{: .callout} + +`nano` doesn't leave any output on the screen after it exits, +but `ls` now shows that we have created a file called `draft.txt`: + +``` +{{ site.remote.prompt }} ls +``` +{: .language-bash} + +``` +draft.txt +``` +{: .output} + +## Copying files and directories + +In a future lesson, we will be running the R script ```{{ site.working_dir | join: '/' }}/{{ site.example.script }}```, but as we can't all work on the same file at once you will need to take your own copy. This can be done with the **c**o**p**y command `cp`, at least two arguments are needed the file (or directory) you want to copy, and the directory (or file) where you want the copy to be created. We will be copying the file into the directory we made previously, as this should be your current directory the second argument can be a simple `.`. + +``` +{{ site.remote.prompt }} cp {{ site.working_dir | join: '/' }}/{{ site.example.script }} . +``` +{: .output} + +We can check that it did the right thing using `ls` + +``` +{{ site.remote.prompt }} ls +``` +{: .language-bash} + +``` +draft.txt {{ site.example.script }} +``` +{: .output} + +## Other File operations + +`cat` stands for concatenate, meaning to link or merge things together. It is primarily used for printing the contents of one or more files to the standard output. +`head` and `tail` will print the first or last lines (head or tail) of the specified file(s). By default it will print 10 lines, but a specific number of lines can be specified with the `-n` option. +`mv` to **m**o**v**e move a file, is used similarly to `cp` taking a source argument(s) and a destination argument. +`rm` will **r**e**m**ove move a file and only needs one argument. + +The `mv` command is also used to rename a file, for example `mv my_fiel my_file`. This is because as far as the computer is concerned *moving and renaming a file are the same operation*. + +In order to `cp` a directory (and all its contents) the `-r` for [recursive](https://en.wikipedia.org/wiki/Recursion) option must be used. +The same is true when deleting directories with `rm` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
commandnameusage
cpcopycp file1 file2
cp -r directory1/ directory2/
mvmovemv file1 file2
mv directory1/ directory2/
rmremoverm file1 file2
rm -r directory1/ directory2/
+ +For `mv` and `cp` if the destination path (final argument) is an existing directory the file will be placed inside that directory with the same name as the source. + +> ## Moving vs Copying +> +> When using the `cp` or `rm` commands on a directory the 'recursive' flag `-r` must be used, but `mv` *does not* require it? +> +>> ## Solution +>> +>> We mentioned previously that as far the computer is concerned, *renaming* is the same operation as *moving*. +>> Contrary to what the commands name implies, *all moving is actually renaming*. +>> The data on the hard drive stays in the same place, +>> only the label applied to that block of memory is changed. +>> To copy a directory, each *individual file* inside that directory must be read, and then written to the copy destination. +>> To delete a directory, each *individual file* in the directory must be marked for deletion, +>> however when moving a directory the files inside are the data inside the directory is not interacted with, +>> only the parent directory is "renamed" to a different place. +>> +>> This is also why `mv` is faster than `cp` as no reading of the files is required. +> {: .solution} +{: .challenge} + +> ## Unsupported command-line options +> +> If you try to use an option (flag) that is not supported, `ls` and other commands +> will usually print an error message similar to: +> +> ``` +> $ ls -j +> ``` +> {: .language-bash} +> +> ``` +> ls: invalid option -- 'j' +> Try 'ls --help' for more information. +> ``` +> {: .error} +{: .callout} + +## Getting help + +Commands will often have many **options**. Most commands have a `--help` flag, as can be seen in the error above. You can also use the manual pages (aka manpages) by using the `man` command. The manual page provides you with all the available options and their use in more detail. For example, for thr `ls` command: + +``` +{{ site.remote.prompt }} man ls +``` +{: .language-bash} + +``` +Usage: ls [OPTION]... [FILE]... +List information about the FILEs (the current directory by default). +Sort entries alphabetically if neither -cftuvSUX nor --sort is specified. + +Mandatory arguments to long options are mandatory for short options, too. + -a, --all do not ignore entries starting with . + -A, --almost-all do not list implied . and .. + --author with -l, print the author of each file + -b, --escape print C-style escapes for nongraphic characters + --block-size=SIZE scale sizes by SIZE before printing them; e.g., + '--block-size=M' prints sizes in units of + 1,048,576 bytes; see SIZE format below + -B, --ignore-backups do not list implied entries ending with ~ + -c with -lt: sort by, and show, ctime (time of last + modification of file status information); + with -l: show ctime and sort by name; + otherwise: sort by ctime, newest first + -C list entries by columns + --color[=WHEN] colorize the output; WHEN can be 'always' (default + if omitted), 'auto', or 'never'; more info below + -d, --directory list directories themselves, not their contents + -D, --dired generate output designed for Emacs' dired mode + -f do not sort, enable -aU, disable -ls --color + -F, --classify append indicator (one of */=>@|) to entries +...       ...       ... +``` +{: .output} + +To navigate through the `man` pages, +you may use and to move line-by-line, +or try B and Spacebar to skip up and down by a full page. +To search for a character or word in the `man` pages, +use / followed by the character or word you are searching for. +Sometimes a search will result in multiple hits. If so, you can move between hits using N (for moving forward) and Shift+N (for moving backward). + +To **quit** the `man` pages, press Q. + +> ## Manual pages on the web +> +> Of course, there is a third way to access help for commands: +> searching the internet via your web browser. +> When using internet search, including the phrase `unix man page` in your search +> query will help to find relevant results. +> +> GNU provides links to its +> [manuals](http://www.gnu.org/manual/manual.html) including the +> [core GNU utilities](http://www.gnu.org/software/coreutils/manual/coreutils.html), +> which covers many commands introduced within this lesson. +{: .callout} diff --git a/docs/Scientific_Computing/Training/Intro_HPC/filesystem_basics.md b/docs/Scientific_Computing/Training/Intro_HPC/filesystem_basics.md new file mode 100644 index 000000000..5dbef2d76 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/filesystem_basics.md @@ -0,0 +1,214 @@ +--- +title: "NeSI Filesystem" +teaching: 15 +exercises: 5 +questions: +- "Where is the best place to store my data?" +- "How do I recover deleted files?" +- "How do I find out how much disk space I have?" +objectives: +- "Learn about the NeSI filesystems, and when to use each one." +keypoints: +- "" + +--- + +The NeSI filesystem looks something like this: + +![The file system is made up of a root directory that contains sub-directories +titled home, nesi, and system files](../fig/NesiFiletree.svg) + +The directories that are relevant to us are. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LocationDefault StorageDefault FilesBackupAccess Speed
Home is for user-specific files such as configuration files, environment setup, source code, etc./home/<username>20GB1,000,000DailyNormal
Project is for persistent project-related data, project-related software, etc./nesi/project/<projectcode>100GB100,000DailyNormal
Nobackup is a 'scratch space', for data you don't need to keep long term. Old data is periodically deleted from nobackup/nesi/nobackup/<projectcode>10TB1,000,000NoneFast
+ +### Managing your data and storage (backups and quotas) + +NeSI performs backups of the `/home` and `/nesi/project` (persistent) filesystems. However, backups are only captured once per day. So, if you edit or change code or data and then immediately delete it, it likely cannot be recovered. Note, as the name suggests, NeSI does **not** backup the `/nesi/nobackup` filesystem. + +Protecting critical data from corruption or deletion is primarily your +responsibility. Ensure you have a data management plan and stick to the plan to reduce the chance of data loss. Also important is managing your storage quota. To check your quotas, use the `nn_storage_quota` command, eg + +{% include {{ site.snippets }}/filedir/sinfo.snip %} + +As well as disk space, 'inodes' are also tracked, this is the *number* of files. + +Notice that the project space for this user is over quota and has been locked, meaning no more data can be added. When your space is locked you will need to move or remove data. Also note that none of the nobackup space is being used. Likely data from project can be moved to nobackup. `nn_storage_quota` uses cached data, and so will no immediately show changes to storage use. + +For more details on our persistent and nobackup storage systems, including data retention and the nobackup autodelete schedule, +please see our [Filesystem and Quota](https://docs.nesi.org.nz/Storage/File_Systems_and_Quotas/NeSI_File_Systems_and_Quotas/) documentation. + +### Working Directory + +We will be working from the directory `{{ site.working_dir[-1] }}`. + +``` +{{ site.remote.prompt }} cd {{ site.working_dir | join: '/' }} +``` + +{: .language-bash} + +### Creating directories + + + +As previously mentioned, it is general useful to organise your work in a hierarchical file structure to make managing and finding files easier. It is also is especially important when working within a shared directory with colleagues, such as a project, to minimise the chance of accidentally affecting your colleagues work. So for this workshop you will each make a directory using the `mkdir` command within the workshops directory for you to personally work from. + +``` +{{ site.remote.prompt }} mkdir +``` + +{: .language-bash} + +You should then be able to see your new directory is there using `ls`. + +``` +{{ site.remote.prompt }} ls {{ site.working_dir | join: '/' }} +``` + +{: .language-bash} + +{% include {{ site.snippets }}/filedir/dir-contents1.snip %} + +## Create a text file + +Now let's create a file. To do this we will use a text editor called Nano to create a file called `draft.txt`: + +We will want to do this from inside the directory we just created. + +``` +{{ site.remote.prompt }} cd +{{ site.remote.prompt }} nano draft.txt +``` + +{: .language-bash} + +> ## Which Editor? +> +> When we say, '`nano` is a text editor' we really do mean 'text': it can +> only work with plain character data, not tables, images, or any other +> human-friendly media. We use it in examples because it is one of the +> least complex text editors. However, because of this trait, it may +> not be powerful enough or flexible enough for the work you need to do +> after this workshop. On Unix systems (such as Linux and macOS), +> many programmers use [Emacs](http://www.gnu.org/software/emacs/) or +> [Vim](http://www.vim.org/) (both of which require more time to learn), +> or a graphical editor such as +> [Gedit](http://projects.gnome.org/gedit/). On Windows, you may wish to +> use [Notepad++](http://notepad-plus-plus.org/). Windows also has a built-in +> editor called `notepad` that can be run from the command line in the same +> way as `nano` for the purposes of this lesson. +> +> No matter what editor you use, you will need to know where it searches +> for and saves files. If you start it from the shell, it will (probably) +> use your current working directory as its default location. If you use +> your computer's start menu, it may want to save files in your desktop or +> documents directory instead. You can change this by navigating to +> another directory the first time you 'Save As...' +{: .callout} + +Let's type in a few lines of text. +Once we're happy with our text, we can press Ctrl+O +(press the Ctrl or Control key and, while +holding it down, press the O key) to write our data to disk +(we'll be asked what file we want to save this to: +press Return to accept the suggested default of `draft.txt`). + +
screenshot of nano text editor in action
+ +Once our file is saved, we can use Ctrl+X to quit the editor and +return to the shell. + +> ## Control, Ctrl, or ^ Key +> +> The Control key is also called the 'Ctrl' key. There are various ways +> in which using the Control key may be described. For example, you may +> see an instruction to press the Control key and, while holding it down, +> press the X key, described as any of: +> +> * `Control-X` +> * `Control+X` +> * `Ctrl-X` +> * `Ctrl+X` +> * `^X` +> * `C-x` +> +> In nano, along the bottom of the screen you'll see `^G Get Help ^O WriteOut`. +> This means that you can use `Control-G` to get help and `Control-O` to save your +> file. +{: .callout} + +`nano` doesn't leave any output on the screen after it exits, +but `ls` now shows that we have created a file called `draft.txt`: + +``` +{{ site.remote.prompt }} ls +``` + +{: .language-bash} + +``` +draft.txt +``` + +{: .output} + +## Copying files and directories + +In a future lesson, we will be running the R script ```{{ site.working_dir | join: '/' }}/{{ site.example.script }} ```, but as we can't all work on the same file at once you will need to take your own copy. This can be done with the **c**o**p**y command `cp`, at least two arguments are needed the file (or directory) you want to copy, and the directory (or file) where you want the copy to be created. We will be copying the file into the directory we made previously, as this should be your current directory the second argument can be a simple `.`. + +``` +{{ site.remote.prompt }} cp {{ site.working_dir | join: '/' }}/{{ site.example.script }} . +``` + +{: .output} + +We can check that it did the right thing using `ls` + +``` +{{ site.remote.prompt }} ls +``` + +{: .language-bash} + +``` +draft.txt {{ site.example.script }} +``` + +{: .output} diff --git a/docs/Scientific_Computing/Training/Intro_HPC/modules.md b/docs/Scientific_Computing/Training/Intro_HPC/modules.md new file mode 100644 index 000000000..232bcae18 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/modules.md @@ -0,0 +1,258 @@ +--- +title: "Accessing software via Modules" +teaching: 15 +exercises: 5 +questions: +- "How do we load and unload software packages?" +objectives: +- "Load and use a software package." +- "Explain how the shell environment changes when the module mechanism loads or unloads packages." +keypoints: +- "Load software with `module load softwareName`." +- "Unload software with `module unload`" +- "The module system handles software versioning and package conflicts for you + automatically." +--- + +On a high-performance computing system, it is seldom the case that the software +we want to use is available when we log in. It is installed, but we will need +to "load" it before it can run. + +Before we start using individual software packages, however, we should +understand the reasoning behind this approach. The three biggest factors are: + +- software incompatibilities +- versioning +- dependencies + +Software incompatibility is a major headache for programmers. Sometimes the +presence (or absence) of a software package will break others that depend on +it. Two of the most famous examples are Python 2 and 3 and C compiler versions. +Python 3 famously provides a `python` command that conflicts with that provided +by Python 2. Software compiled against a newer version of the C libraries and +then used when they are not present will result in a nasty `'GLIBCXX_3.4.20' +not found` error, for instance. + + + +Software versioning is another common issue. A team might depend on a certain +package version for their research project - if the software version was to +change (for instance, if a package was updated), it might affect their results. +Having access to multiple software versions allows a set of researchers to +prevent software versioning issues from affecting their results. + +Dependencies are where a particular software package (or even a particular +version) depends on having access to another software package (or even a +particular version of another software package). For example, the VASP +materials science software may depend on having a particular version of the +FFTW (Fastest Fourier Transform in the West) software library available for it +to work. + +## Environment + +Before understanding environment modules we first need to understand what is meant by _environment_. + +The environment is defined by it's _environment variables_. + +_Environment Variables_ are writable named-variables. + +We can assign a variable named "FOO" with the value "bar" using the syntax. + +``` +{{ site.remote.prompt }} FOO="bar" +``` +{: .language-bash} + +Convention is to name fixed variables in all caps. + +Our new variable can be referenced using `$FOO`, you could also use `${FOO}`, +enclosing a variable in curly brackets is good practice as it avoids possible ambiguity. + +``` +{{ site.remote.prompt }} $FOO +``` +{: .language-bash} + +``` +-bash: bar: command not found +``` +{: .output} + +We got an error here because the variable is evalued _in the terminal_ then executed. +If we just want to print the variable we can use the command, + +``` +{{ site.remote.prompt }} echo $FOO +``` +{: .language-bash} +``` +bar +``` +{: .output} + +We can get a full list of environment variables using the command, + +``` +{{ site.remote.prompt }} env +``` +{: .language-bash} +{% include {{ site.snippets }}/modules/env-output.snip %} + +These variables control many aspects of how your terminal, and any software launched from your terminal works. + +## Environment Modules + +Environment modules are the solution to these problems. A _module_ is a +self-contained description of a software package -- it contains the +settings required to run a software package and, usually, encodes required +dependencies on other software packages. + +There are a number of different environment module implementations commonly +used on HPC systems: the two most common are _TCL modules_ and _Lmod_. Both of +these use similar syntax and the concepts are the same so learning to use one +will allow you to use whichever is installed on the system you are using. In +both implementations the `module` command is used to interact with environment +modules. An additional subcommand is usually added to the command to specify +what you want to do. For a list of subcommands you can use `module -h` or +`module help`. As for all commands, you can access the full help on the _man_ +pages with `man module`. + +### Purging Modules + +Depending on how you are accessing the HPC the modules you have loaded by default will be different. So before we start listing our modules we will first use the `module purge` command to clear all but the minimum default modules so that we are all starting with the same modules. + +``` +{{ site.remote.prompt }} module purge +``` +{: .language-bash} + +``` + +The following modules were not unloaded: + (Use "module --force purge" to unload all): + + 1) XALT/minimal 2) slurm 3) NeSI +``` +{: .output} + +Note that `module purge` is informative. It lets us know that all but a minimal default +set of packages have been unloaded (and how to actually unload these if we +truly so desired). + +We are able to unload individual modules, unfortunately within the NeSI system it does not always unload it's dependencies, therefore we recommend `module purge` to bring you back to a state where only those modules needed to perform your normal work on the cluster. + +`module purge` is a useful tool for ensuring repeatable research by guaranteeing that the environment that you build your software stack from is always the same. This is important since some modules have the potential to silently effect your results if they are loaded (or not loaded). + +### Listing Available Modules + +To see available software modules, use `module avail`: + +``` +{{ site.remote.prompt }} module avail +``` +{: .language-bash} + +{% include {{ site.snippets }}/modules/available-modules.snip %} + +### Listing Currently Loaded Modules + +You can use the `module list` command to see which modules you currently have +loaded in your environment. On {{ site.remote.name }} you will have a few default modules loaded when you login. + +``` +{{ site.remote.prompt }} module list +``` +{: .language-bash} + +{% include {{ site.snippets }}/modules/module-list-default.snip %} + +## Loading and Unloading Software + +You can load software using the `module load` command. In this example we will be using the programming language _R_. + +Initially, R is not loaded. We can test this by using the `which` +command. `which` looks for programs the same way that Bash does, so we can use +it to tell us where a particular piece of software is stored. + +``` +{{ site.remote.prompt }} which R +``` +{: .language-bash} + +{% include {{ site.snippets }}/modules/missing-r.snip %} + +The important bit here being: + +``` +/usr/bin/which: no R in (...) +``` + +Now lets try loading the R environment module, and try again. + +{% include {{ site.snippets }}/modules/module-load-r.snip %} + +> ## Tab Completion +> +> The module command also supports tab completion. You may find this the easiest way to find the right software. +{: .callout} + +So, what just happened? + +To understand the output, first we need to understand the nature of the `$PATH` +environment variable. `$PATH` is a special environment variable that controls +where a UNIX system looks for software. Specifically `$PATH` is a list of +directories (separated by `:`) that the OS searches through for a command +before giving up and telling us it can't find it. As with all environment +variables we can print it out using `echo`. + +{% include {{ site.snippets }}/modules/r-module-path.snip %} + +You'll notice a similarity to the output of the `which` command. However, in this case, +there are a lot more directories at the beginning. When we +ran the `module load` command, it added many directories to the beginning of our +`$PATH`. + +The path to NeSI XALT utility will normally show up first. This helps us track software usage, but the more important directory is the second one: `/opt/nesi/CS400_centos7_bdw/R/4.2.1-gimkl-2022a/bin` Let's examine what's there: + +{% include {{ site.snippets }}/modules/r-ls-dir-command.snip %} + +`module load` "loads" not only the specified software, but it also loads software dependencies. That is, the software that the application you load requires to run. + +{% include {{ site.snippets }}/modules/software-dependencies.snip %} + +Before moving onto the next session lets use `module purge` again to return to the minimal environment. + +``` +{{ site.remote.prompt }} module purge +``` +{: .language-bash} + +``` +The following modules were not unloaded: + (Use "module --force purge" to unload all): + + 1) XALT/minimal 2) slurm 3) NeSI +``` +{: .output} + +## Software Versioning + +So far, we've learned how to load and unload software packages. However, we have not yet addressed the issue of software versioning. At +some point or other, you will run into issues where only one particular version +of some software will be suitable. Perhaps a key bugfix only happened in a +certain version, or version _X_ broke compatibility with a file format you use. +In either of these example cases, it helps to be very specific about what +software is loaded. + +Let's examine the output of `module avail` more closely. + +``` +{{ site.remote.prompt }} module avail +``` +{: .language-bash} + +{% include {{ site.snippets }}/modules/available-modules.snip %} + +{% include {{ site.snippets }}/modules/wrong-python-version.snip %} + +{% include links.md %} diff --git a/docs/Scientific_Computing/Training/Intro_HPC/parallel.md b/docs/Scientific_Computing/Training/Intro_HPC/parallel.md new file mode 100644 index 000000000..7771d2d82 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/parallel.md @@ -0,0 +1,202 @@ +--- +title: "What is Parallel Computing" +teaching: 20 +exercises: 10 +questions: +- "How do we execute a task in parallel?" +- "What benefits arise from parallel execution?" +- "What are the limits of gains from execution in parallel?" +- "What is the difference between implicit and explicit parallelisation." +objectives: +- "Prepare a job submission script for the parallel executable." +keypoints: +- "Parallel programming allows applications to take advantage of + parallel hardware; serial code will not 'just work.'" +- "There are multiple ways you can run " +--- + +## Methods of Parallel Computing + +To understand the different types of Parallel Computing we first need to clarify some terms. + +{% include figure.html url="" max-width="40%" + file="/fig/clusterDiagram.png" + alt="Node anatomy" caption="" %} + +**CPU**: Unit that does the computations. + +**Task**: One or more CPUs that share memory. + +**Node**: The physical hardware. The upper limit on how many CPUs can be in a task. + +**Shared Memory**: When multiple CPUs are used within a single task. + +**Distributed Memory**: When multiple tasks are used. + +Which methods are available to you is largely dependent on the nature of the problem and software being used. + +### Shared-Memory (SMP) + +Shared-memory multiproccessing divides work among _CPUs_ or _threads_, all of these threads require access to the same memory. + +Often called *Multithreading*. + +This means that all CPUs must be on the same node, most Mahuika nodes have 72 CPUs. + +Shared memory parallelism is used in our example script `{{ site.example.script }}`. + +Number of threads to use is specified by the Slurm option `--cpus-per-task`. + +### Distributed-Memory (MPI) + +Distributed-memory multiproccessing divides work among _tasks_, a task may contain multiple CPUs (provided they all share memory, as discussed previously). + +Message Passing Interface (MPI) is a communication standard for distributed-memory multiproccessing. While there are other standards, often 'MPI' is used synonymously with Distributed parallelism. + +Each task has it's own exclusive memory, tasks can be spread across multiple nodes, communicating via and _interconnect_. This allows MPI jobs to be much larger than shared memory jobs. It also means that memory requirements are more likely to increase proportionally with CPUs. + +Distributed-Memory multiproccessing predates shared-memory multiproccessing, and is more common with classical high performance applications (older computers had one CPU per node). + +Number of tasks to use is specified by the Slurm option `--ntasks`, because the number of tasks ending up on one node is variable you should use `--mem-per-cpu` rather than `--mem` to ensure each task has enough. + +Tasks cannot share cores, this means in most circumstances leaving `--cpus-per-task` unspecified will get you `2`. + +Using a combination of Shared and Distributed memory is called _Hybrid Parallel_. + +### GPGPU's + +GPUs compute large number of simple operations in parallel, making them well suited for Graphics Processing (hence the name), or any other large matrix operations. + +On NeSI, GPU's are specialised pieces of hardware that you request in addition to your CPUs and memory. + +You can find an up-to-date(ish) list of GPUs available on NeSI in our [Support Documentation](https://docs.nesi.org.nz/Scientific_Computing/The_NeSI_High_Performance_Computers/Available_GPUs_on_NeSI/) + +GPUs can be requested using `--gpus-per-node=:` + +Depending on the GPU type, we *may* also need to specify a partition using `--partition`. + +> ## GPU Job Example +> +> Create a new script called `gpu-job.sl` +> +> ``` +> #!/bin/bash -e +> +> #SBATCH --job-name gpu-job +> #SBATCH --account {{site.sched.projectcode}} +> #SBATCH --output %x.out +> #SBATCH --mem-per-cpu 2G +> #SBATCH --gpu-per-node P100:1 +> +> module load CUDA +> nvidia-smi +> ``` +> {: .language-bash} +> +> then submit with +> +> ``` +> {{ site.remote.prompt }} sbatch gpu-job.sl +> ``` +> {: .language-bash} +> +> > ## Solution +> > +> > ``` +> > {{ site.remote.prompt }} cat gpu-job.out +> > +> > ``` +> > {: .language-bash} +> > +> > ``` +> > Tue Mar 12 19:40:51 2024 +> > +-----------------------------------------------------------------------------+ +> > | NVIDIA-SMI 525.85.12 Driver Version: 525.85.12 CUDA Version: 12.0 | +> > |-------------------------------+----------------------+----------------------+ +> > | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | +> > | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | +> > | | | MIG M. | +> > |===============================+======================+======================| +> > | 0 Tesla P100-PCIE... On | 00000000:05:00.0 Off | 0 | +> > | N/A 28C P0 24W / 250W | 0MiB / 12288MiB | 0% Default | +> > | | | N/A | +> > +-------------------------------+----------------------+----------------------+ +> > +> > +-----------------------------------------------------------------------------+ +> > | Processes: | +> > | GPU GI CI PID Type Process name GPU Memory | +> > | ID ID Usage | +> > |=============================================================================| +> > | No running processes found | +> > +-----------------------------------------------------------------------------+ +> > ``` +> > {: .output} +> {: .solution} +{: .challenge} + +### Job Array + +Job arrays are not "multiproccessing" in the same way as the previous two methods. +Ideal for _embarrassingly parallel_ problems, where there are little to no dependencies between the different jobs. + +Can be thought of less as running a single job in parallel and more about running multiple serial-jobs simultaneously. +Often this will involve running the same process on multiple inputs. + +Embarrassingly parallel jobs should be able to scale without any loss of efficiency. If this type of parallelisation is an option, it will almost certainly be the best choice. + +A job array can be specified using `--array` + +If you are writing your own code, then this is something you will probably have to specify yourself. + +## How to Utilise Multiple CPUs + +Requesting extra resources through Slurm only means that more resources will be available, it does not guarantee your program will be able to make use of them. + +Generally speaking, Parallelism is either _implicit_ where the software figures out everything behind the scenes, or _explicit_ where the software requires extra direction from the user. + +### Scientific Software + +The first step when looking to run particular software should always be to read the documentation. +On one end of the scale, some software may claim to make use of multiple cores implicitly, but this should be verified as the methods used to determine available resources are not guaranteed to work. + +Some software will require you to specify number of cores (e.g. `-n 8` or `-np 16`), or even type of paralellisation (e.g. `-dis` or `-mpi=intelmpi`). + +Occasionally your input files may require rewriting/regenerating for every new CPU combintation (e.g. domain based parallelism without automatic partitioning). + +### Writing Code + +Occasionally requesting more CPUs in your Slurm job is all that is required and whatever program you are running will automagically take advantage of the additional resources. +However, it's more likely to require some amount of effort on your behalf. + +It is important to determine this before you start requesting more resources through Slurm + +If you are writing your own code, some programming languages will have functions that can make use of multiple CPUs without requiring you to changes your code. +However, unless that function is where the majority of time is spent, this is unlikely to give you the performance you are looking for. + +*Python: [Multiproccessing](https://docs.python.org/3/library/multiprocessing.html)* (not to be confused with `threading` which is not really parallel.) + +*MATLAB: [Parpool](https://au.mathworks.com/help/parallel-computing/parpool.html)* + +## Summary + +| Name | Other Names | Slurm Option | Pros/cons | +| - | - | - | - | +| Shared Memory Parallelism | Multithreading, Multiproccessing | `--cpus-per-task` | | +| Distrubuted Memory Parallelism | MPI, OpenMPI | `--ntasks` and add `srun` before command | | +| Hybrid | | `--ntasks` and `--cpus-per-task` and add `srun` before command | | +| Job Array | | `--array` | | +| General Purpose GPU | | `--gpus-per-node` | | + +> ## Running a Parallel Job. +> +> Pick one of the method of Paralellism mentioned above, and modify your `example.sl` script to use this method. +> +> +> > ## Solution +> > +> > What does the printout say at the start of your job about number and location of node. +> > {: .output} +> {: .solution} +{: .challenge} + +{% include links.md %} diff --git a/docs/Scientific_Computing/Training/Intro_HPC/resources.md b/docs/Scientific_Computing/Training/Intro_HPC/resources.md new file mode 100644 index 000000000..e9fdc9465 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/resources.md @@ -0,0 +1,376 @@ +--- +title: "Using resources effectively" +teaching: 20 +exercises: 10 +questions: +- "How can I review past jobs?" +- "How can I use this knowledge to create a more accurate submission script?" +objectives: +- "Understand how to look up job statistics and profile code." +- "Understand job size implications." +- "Understand problems and limitations involved in using multiple CPUs." +keypoints: +- "As your task gets larger, so does the potential for inefficiencies." +- "The smaller your job (time, CPUs, memory, etc), the faster it will schedule." +math: True +--- + + +## What Resources? + +Last time we submitted a job, we did not specify a number of CPUs, and therefore +we were provided the default of `2` (1 _core_). + +As a reminder, our slurm script `example_job.sl` currently looks like this. + +``` +{% include example_scripts/example_job.sl.1 %} +``` + +{: .language-bash} + +We will now submit the same job again with more CPUs. +We ask for more CPUs using by adding `#SBATCH --cpus-per-task 4` to our script. +Your script should now look like this: + +``` +{% include example_scripts/example_job.sl.2 %} +``` + +{: .language-bash} + +And then submit using `sbatch` as we did before. + +``` +{{ site.remote.prompt }} sbatch example_job.sl +``` + +{: .language-bash} + +{% include {{ site.snippets }}/scheduler/basic-job-script.snip %} + +> ## Watch +> +> We can prepend any command with `watch` in order to periodically (default 2 seconds) run a command. e.g. `watch +> squeue --me` will give us up to date information on our running jobs. +> Care should be used when using `watch` as repeatedly running a command can have adverse effects. +> Exit `watch` with ctrl + c. +{: .callout} + +Note in squeue, the number under cpus, should be '4'. + +Checking on our job with `sacct`. +Oh no! + +{% include {{ site.snippets }}/scaling/OOM.snip %} +{: .language-bash} + +To understand why our job failed, we need to talk about the resources involved. + +Understanding the resources you have available and how to use them most efficiently is a vital skill in high performance computing. + +Below is a table of common resources and issues you may face if you do not request the correct amount. + + + + + + + + + + + + + + + + + + + + + + + + + + +
Not enoughToo Much
CPU The job will run more slowly than expected, and so may run out of time and get killed for exceeding its time limit.The job will wait in the queue for longer.
+ You will be charged for CPUs regardless of whether they are used or not.
+ Your fair share score will fall more. +
Memory Your job will fail, probably with an 'OUT OF MEMORY' error, segmentation fault or bus error (may not happen immediately).The job will wait in the queue for longer.
+ You will be charged for memory regardless of whether it is used or not.
+ Your fair share score will fall more.
Walltime The job will run out of time and be terminated by the scheduler.The job will wait in the queue for longer.
+ +## Measuring Resource Usage of a Finished Job + +Since we have already run a job (successful or otherwise), this is the best source of info we currently have. +If we check the status of our finished job using the `sacct` command we learned earlier. + +``` +{{ site.remote.prompt }} sacct +``` + +{: .language-bash} + +{% include {{ site.snippets }}/scheduler/basic-job-status-sacct.snip %} + +With this information, we may determine a couple of things. + +Memory efficiency can be determined by comparing ReqMem (requested memory) with MaxRSS (maximum used memory), MaxRSS is given in KB, so a unit conversion is usually required. + + + +
+ +$$ {Efficiency_{mem} = { MaxRSS \over ReqMem}} $$ + +
+ +So for the above example we see that 0.1GB (102048K) of our requested 1GB meaning the memory efficincy was about 10%. + +CPU efficiency can be determined by comparing TotalCPU(CPU time), with the maximum possible CPU time. The maximum possible CPU time equal to Alloc (number of allocated CPUs) multiplied by Elapsed (Walltime, actual time passed). + + + +$$ {Efficiency_{cpu} = { TotalCPU \over {Elapsed \times Alloc}}} $$ + +
+ +For the above example 33 seconds of computation was done, + +where the maximum possible computation time was **96 seconds** (2 CPUs multiplied by 48 seconds), meaning the CPU efficiency was about 35%. + +Time Efficiency is simply the Elapsed Time divided by Time Requested. + +
+ +$$ {Efficiency_{time} = { Elapsed \over Requested}} $$ + + + +
+ +48 seconcds out of 15 minutes requested give a time efficiency of about 5% + +> ## Efficiency Exercise +> +> Calculate for the job shown below, +> +> ``` +> JobID JobName Alloc Elapsed TotalCPU ReqMem MaxRSS State +> --------------- ---------------- ----- ----------- ------------ ------- -------- ---------- +> 37171050 Example-job 8 00:06:03 00:23:04 32G FAILED +> 37171050.batch batch 8 00:06:03 23:03.999 14082672k FAILED +> 37171050.extern extern 8 00:06:03 00:00.001 0 COMPLETED +> ``` +> +> a. CPU efficiency. +> +> b. Memory efficiency. +> +> > ## Solution +> > +> > a. CPU efficiency is `( 23 / ( 8 * 6 ) ) x 100` or around **48%**. +> > +> > b. Memory efficiency is `( 14 / 32 ) x 100` or around **43%**. +> {: .solution} +{: .challenge} + +For convenience, NeSI has provided the command `nn_seff ` to calculate **S**lurm **Eff**iciency (all NeSI commands start with `nn_`, for **N**eSI **N**IWA). + +``` +{{ site.remote.prompt }} nn_seff +``` + +{: .language-bash} + +{% include {{ site.snippets }}/resources/seff.snip %} + +Knowing what we do now about job efficiency, lets submit the previous job again but with more appropriate resources. + +``` +{% include example_scripts/example_job.sl.2 %} +``` +{: .language-bash} + + +``` +{{ site.remote.prompt }} sbatch example_job.sl +``` +{: .language-bash} + +Hopefully we will have better luck with this one! + +### A quick description of Simultaneous Multithreading - SMT (aka Hyperthreading) + +Modern CPU cores have 2 threads of operation that can execute independently of one +another. SMT is the technology that allows the 2 threads within one physical core to present +as multiple logical cores, sometimes referred to as virtual CPUS (vCPUS). + +Note: _Hyperthreading_ is Intel's marketing name for SMT. Both Intel and AMD +CPUs have SMT technology. + +Some types of processes can take advantage of multiple threads, and can gain a +performance boost. Some software is +specifically written as multi-threaded. You will need to check or test if your +code can take advantage of threads (we can help with this). + +However, because each thread shares resources on the physical core, +there can be conflicts for resources such as onboard cache. +This is why not all processes get a performance boost from SMT and in fact can +run slower. These types of jobs should be run without multithreading. There +is a Slurm parameter for this: `--hint=nomultithread` + +SMT is why you are provided 2 CPUs instead of 1 as we do not allow +2 different jobs to share a core. This also explains why you will sometimes +see CPU efficiency above 100%, since CPU efficiency is based on core and not thread. + +For more details please see our [documentation on Hyperthreading +](https://docs.nesi.org.nz/Scientific_Computing/Running_Jobs_on_Maui_and_Mahuika/Hyperthreading/) + +## Measuring the System Load From Currently Running Tasks + +On Mahuika, we allow users to connect directly to compute nodes from the +login node. This is useful to check on a running job and see how it's doing, however, we +only allow you to connect to nodes on which you have running jobs. + +The most reliable way to check current system stats is with `htop`. +`htop` is an interactive process viewer that can be launched from command line. + +### Finding job node + +Before we can check on our job, we need to find out where it is running. +We can do this with the command `squeue --me`, and looking under the 'NODELIST' column. + +``` +{{ site.remote.prompt }} squeue --me +``` + +{: .language-bash} + +{% include {{ site.snippets }}/resources/get-job-node.snip %} + +Now that we know the location of the job (wbn189) we can use `ssh` to run `htop` _on that node_. + +``` +{{ site.remote.prompt }} ssh wbn189 -t htop -u $USER +``` + +{: .language-bash} + +You may get a message: + +``` +ECDSA key fingerprint is SHA256:############################################ +ECDSA key fingerprint is MD5:9d:############################################ +Are you sure you want to continue connecting (yes/no)? +``` + +{: .language-bash} + +If so, type `yes` and Enter + +You may also need to enter your cluster password. + +If you cannot connect, it may be that the job has finished and you have lost permission to `ssh` to that node. + +### Reading Htop + +You may see something like this, + +{% include {{ site.snippets }}/resources/monitor-processes-top.snip %} + +Overview of the most important fields: + +* `PID`: What is the numerical id of each process? +* `USER`: Who started the process? +* `RES`: What is the amount of memory currently being used by a process (in + bytes)? +* `%CPU`: How much of a CPU is each process using? Values higher than 100 + percent indicate that a process is running in parallel. +* `%MEM`: What percent of system memory is a process using? +* `TIME+`: How much CPU time has a process used so far? Processes using 2 CPUs + accumulate time at twice the normal rate. +* `COMMAND`: What command was used to launch a process? + +To exit press q. + +Running this command as is will show us information on tasks running on the login node (where we should not be running resource intensive jobs anyway). + +## Running Test Jobs + +As you may have to run several iterations before you get it right, you should choose your test job carefully. +A test job should not run for more than 15 mins. This could involve using a smaller input, coarser parameters or using a subset of the calculations. +As well as being quick to run, you want your test job to be quick to start (e.g. get through queue quickly), the best way to ensure this is keep the resources requested (memory, CPUs, time) small. +Similar as possible to actual jobs e.g. same functions etc. +Use same workflow. (most issues are caused by small issues, typos, missing files etc, your test job is a jood chance to sort out these issues.). +Make sure outputs are going somewhere you can see them. + +> ## Serial Test +> +> Often a good first test to run, is to execute your job _serially_ e.g. using only 1 CPU. +> This not only saves you time by being fast to start, but serial jobs can often be easier to debug. +> If you confirm your job works in its most simple state you can identify problems caused by +> paralellistaion much more easily. +{: .callout} + +You generally should ask for 20% to 30% more time and memory than you think the job will use. +Testing allows you to become more more precise with your resource requests. We will cover a bit more on running tests in the last lesson. + +> ## Efficient way to run tests jobs using debug QOS (Quality of Service) +> +> Before submitting a large job, first submit one as a test to make +> sure everything works as expected. Often, users discover typos in their submit +> scripts, incorrect module names or possibly an incorrect pathname after their job +> has queued for many hours. Be aware that your job is not fully scanned for +> correctness when you submit the job. While you may get an immediate error if your +> SBATCH directives are malformed, it is not until the job starts to run that the +> interpreter starts to process the batch script. +> +> NeSI has an easy way for you to test your job submission. One can employ the debug +> QOS to get a short, high priority test job. Debug jobs have to run within 15 +> minutes and cannot use more that 2 nodes. To use debug QOS, add or change the +> following in your batch submit script +> +>``` +>#SBATCH --qos=debug +>#SBATCH --time=15:00 +> ``` +> +>{: .language-bash} +> +> Adding these SBATCH directives will provide your job with the highest priority +> possible, meaning it should start to run within a few minutes, provided +> your resource request is not too large. +{: .callout} + +## Initial Resource Requirements + +As we have just discussed, the best and most reliable method of determining resource requirements is from testing, +but before we run our first test there are a couple of things you can do to start yourself off in the right area. + +### Read the Documentation + +NeSI maintains documentation that does have some guidance on using resources for some software +However, as you noticed in the Modules lessons, we have a lot of software. So it is also advised to search +the web for others that may have written up guidance for getting the most out of your specific software. + +### Ask Other Users + +If you know someone who has used the software before, they may be able to give you a ballpark figure. + + + +> ## Next Steps +> +> You can use this knowledge to set up the +> next job with a closer estimate of its load on the system. +> A good general rule +> is to ask the scheduler for **30%** more time and memory than you expect the +> job to need. +{: .callout} + +{% include links.md %} diff --git a/docs/Scientific_Computing/Training/Intro_HPC/scaling.md b/docs/Scientific_Computing/Training/Intro_HPC/scaling.md new file mode 100644 index 000000000..a76c6b5ff --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/scaling.md @@ -0,0 +1,60 @@ +--- +title: "Scaling" +teaching: 10 +exercises: 35 +questions: +- "How do we go from running a job on a small number of CPUs to a larger one." +objectives: +- "Understand scaling procedure." +keypoints: +- Start small. +- Test one thing at a time (unit tests). +- Record everything. +--- + +The aim of these tests will be to establish how a jobs requirements change with size (CPUs, inputs) and ultimately figure out the best way to run your jobs. +Unfortunately we cannot assume speedup will be linear (e.g. double CPUs won't usually half runtime, doubling the size of your input data won't necessarily double runtime) therefore more testing is required. This is called *scaling testing*. + +In order to establish an understanding of the scaling properties we may have to repeat this test several times, giving more resources each iteration. + +## Scaling Behavior + +### Amdahl's Law + +Most computational tasks will have a certain amount of work that must be computed serially. + +![Larger fractions of parallel code will have closer to linear scaling performance.](../fig/AmdahlsLaw2.svg) + +Eventually your performance gains will plateau. + +The fraction of the task that can be run in parallel determines the point of this plateau. +Code that has no serial components is said to be "embarrassingly parallel". + +It is worth noting that Amdahl's law assumes all other elements of scaling are happening with 100% efficient, in reality there are additional computational and communication overheads. + +> ## Scaling Exercise +> +> 1. Find your name in the [spreadsheet]({{ site.exercise }}) and modify your `example_job.sl` to request +> "x" `--cpus-per-task`. +> For example `#SBATCH --cpus-per-task 10`. +> 2. Estimate memory requirement based on our previous runs and the cpus requested, memory +> is specified with the `--mem ` flag, it does not accept decimal values, however you may +> specify a unit (`K`|`M`|`G`), if no unit is specified it is assumed to be `M`. +> For example `#SBATCH --mem 1200`. +> 3. Now submit your job, we will include an extra argument `--acctg-freq 1`. +> By default SLURM records job data every 30 seconds. +> This means any job running for less than 30 +> seconds will not have it's memory use recorded. +> Submit the job with `sbatch --acctg-freq 1 example_job.sl`. +> 4. Watch the job with `squeue --me` or `watch squeue --me`. +> 5. On completion of job, use `nn_seff `. +> 6. Record the jobs "Elapsed", "TotalCPU", and "Memory" values in the spreadsheet. (Hint: They are the first +> numbers after the percentage efficiency in output of `nn_seff`). Make sure you have entered the values in the correct format and there is a tick next to each entry. ![Correctly entered data in spreadsheet.](../fig/correct-spreadsheet-entry.png) +> +> > ## Solution +> > +> > [spreadsheet]({{ site.exercise }}) +> {: .solution} +{: .challenge} + +{% include links.md %} diff --git a/docs/Scientific_Computing/Training/Intro_HPC/scheduler.md b/docs/Scientific_Computing/Training/Intro_HPC/scheduler.md new file mode 100644 index 000000000..ba3980ef4 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/scheduler.md @@ -0,0 +1,338 @@ +--- +title: "Scheduler Fundamentals" +teaching: 15 +exercises: 10 +questions: +- "What is a scheduler and why does a cluster need one?" +- "How do I launch a program to run on a compute node in the cluster?" +- "How do I capture the output of a program that is run on a node in the + cluster?" +objectives: +- "Run a simple script on the login node, and through the scheduler." +- "Use the batch system command line tools to monitor the execution of your + job." +- "Inspect the output and error files of your jobs." +- "Find the right place to put large datasets on the cluster." +keypoints: +- "The scheduler handles how compute resources are shared between users." +- "A job is just a shell script." +- "Request _slightly_ more resources than you will need." +--- + +## Job Scheduler + +An HPC system might have thousands of nodes and thousands of users. How do we +decide who gets what and when? How do we ensure that a task is run with the +resources it needs? This job is handled by a special piece of software called +the _scheduler_. On an HPC system, the scheduler manages which jobs run where +and when. + +The following illustration compares these tasks of a job scheduler to a waiter +in a restaurant. If you can relate to an instance where you had to wait for a +while in a queue to get in to a popular restaurant, then you may now understand +why sometimes your job do not start instantly as in your laptop. + +{% include figure.html max-width="75%" caption="" + file="/fig/restaurant_queue_manager.svg" + alt="Compare a job scheduler to a waiter in a restaurant" %} + +The scheduler used in this lesson is {{ site.sched.name }}. Although +{{ site.sched.name }} is not used everywhere, running jobs is quite similar +regardless of what software is being used. The exact syntax might change, but +the concepts remain the same. + +## Interactive vs Batch + +So far, whenever we have entered a command into our terminals, we have received the response immediately in the same terminal, this is said to be an _interactive session_. + +[//]: # TODO ??Diagram?? + +This is all well for doing small tasks, but what if we want to do several things one after another without without waiting in-between? Or what if we want to repeat a series of command again later? + +This is where _batch processing_ becomes useful, this is where instead of entering commands directly to the terminal we write them down in a text file or _script_. Then, the script can be _executed_ by calling it with `bash`. + +[//]: # TODO ??Diagram?? + +Lets try this now, create and open a new file in your current directory called `example_job.sh`. +(If you prefer another text editor than nano, feel free to use that), we will put to use some things we have learnt so far. + +``` +{{ site.remote.prompt }} nano example_job.sh +``` +{: .language-bash} + + +``` +{% include example_scripts/example_job.sh %} +``` +{: .language-bash} + +> ## shebang +> +> _shebang_ or _shabang_, also referred to as _hashbang_ is the character sequence consisting of the number sign (aka: hash) and exclamation mark (aka: bang): `#!` at the beginning of a script. It is used to describe the _interpreter_ that will be used to run the script. In this case we will be using the Bash Shell, which can be found at the path `/bin/bash`. The job scheduler will give you an error if your script does not start with a shebang. +> +{: .callout} + +We can now run this script using +``` +{{ site.remote.prompt }} bash example_job.sh +``` +{: .language-bash} + +``` +Loading required package: foreach +Loading required package: iterators +Loading required package: parallel +[1] "Using 1 cpus to sum [ 2.000000e+04 x 2.000000e+04 ] matrix." +[1] "0% done..." +... +[1] "99% done..." +[1] "100% done..." +[1] "Sum is '10403.632886'." +Done! +``` +{: .output} + +You will get the output printed to your terminal as if you had just run those commands one after another. + +> ## Cancelling Commands +> +> You can kill a currently running task by pressing the keys ctrl + c. +> If you just want your terminal back, but want the task to continue running you can 'background' it by pressing ctrl + v. +> Note, a backgrounded task is still attached to your terminal session, and will be killed when you close the terminal (if you need to keep running a task after you log out, have a look at [tmux](https://docs.nesi.org.nz/Getting_Started/Cheat_Sheets/tmux-Reference_sheet/)). +{: .callout} + +## Scheduled Batch Job + +Up until now the scheduler has not been involved, our scripts were run directly on the login node (or Jupyter node). + +First lets rename our batch script script to clarify that we intend to run it though the scheduler. + +``` +mv example_job.sh example_job.sl +``` +{: .output} + +> ## File Extensions +> +> A files extension in this case does not in any way affect how a script is read, +> it is just another part of the name used to remind users what type of file it is. +> Some common conventions: +> `.sh`: **Sh**ell Script. +> `.sl`: **Sl**urm Script, a script that includes a *slurm header* and is intended to be submitted to the cluster. +> `.out`: Commonly used to indicate the file contains the std**out** of some process. +> `.err`: Same as `.out` but for std**err**. +{: .callout} + +In order for the job scheduler to do it's job we need to provide a bit more information about our script. +This is done by specifying _slurm parameters_ in our batch script. Each of these parameters must be preceded by the special token `#SBATCH` and placed _after_ the _shebang_, but before the content of the rest of your script. + +{% include figure.html max-width="100%" caption="" + file="/fig/parts_slurm_script.svg" + alt="slurm script is a regular bash script with a slurm header after the shebang" %} + +These parameters tell SLURM things around how the script should be run, like memory, cores and time required. + +All the parameters available can be found by checking `man sbatch` or on the online [slurm documentation](https://slurm.schedmd.com/sbatch.html). + +[//]: # TODO ??Vet table + +{% include {{ site.snippets }}/scheduler/option-flags-list.snip %} +> ## Comments +> +> Comments in UNIX shell scripts (denoted by `#`) are ignored by the bash interpreter. +> Why is it that we start our slurm parameters with `#` if it is going to be ignored? +> > ## Solution +> > Commented lines are ignored by the bash interpreter, but they are _not_ ignored by slurm. +> > The `{{ site.sched.comment }}` parameters are read by slurm when we _submit_ the job. When the job starts, +> > the bash interpreter will ignore all lines starting with `#`. +> > +> > This is similar to the _shebang_ mentioned earlier, +> > when you run your script, the system looks at the `#!`, then uses the program at the subsequent +> > path to interpret the script, in our case `/bin/bash` (the program 'bash' found in the 'bin' directory). +> {: .solution} +{: .challenge} + +Note that just *requesting* these resources does not make your job run faster, +nor does it necessarily mean that you will consume all of these resources. It +only means that these are made available to you. Your job may end up using less +memory, or less time, or fewer tasks or nodes, than you have requested, and it +will still run. + +It's best if your requests accurately reflect your job's requirements. We'll +talk more about how to make sure that you're using resources effectively in a +later episode of this lesson. + +Now, rather than running our script with `bash` we _submit_ it to the scheduler using the command `sbatch` (**s**lurm **batch**). + +``` +{{ site.remote.prompt }} {{ site.sched.submit.name }} {% if site.sched.submit.options != '' %}{{ site.sched.submit.options }} {% endif %}example_job.sl +``` +{: .language-bash} + +{% include {{ site.snippets }}/scheduler/basic-job-script.snip %} + +And that's all we need to do to submit a job. Our work is done -- now the +scheduler takes over and tries to run the job for us. + +## Checking on Running/Pending Jobs + +While the job is waiting +to run, it goes into a list of jobs called the *queue*. To check on our job's +status, we check the queue using the command +`{{ site.sched.status }}` (**s**lurm **queue**). We will need to filter to see only our jobs, by including either the flag `--user ` or `--me`. + +``` +{{ site.remote.prompt }} {{ site.sched.status }} {{ site.sched.flag.me }} +``` +{: .language-bash} + +{% include {{ site.snippets }}/scheduler/basic-job-status.snip %} + +We can see many details about our job, most importantly is it's _STATE_, the most common states you might see are.. + +- `PENDING`: The job is waiting in the queue, likely waiting for resources to free up or higher prioroty jobs to run. +because other jobs have priority. +- `RUNNING`: The job has been sent to a compute node and it is processing our commands. +- `COMPLETED`: Your commands completed successfully as far as Slurm can tell (e.g. exit 0). +- `FAILED`: (e.g. exit not 0). +- `CANCELLED`: +- `TIMEOUT`: Your job has running for longer than your `--time` and was killed. +- `OUT_OF_MEMORY`: Your job tried to use more memory that it is allocated (`--mem`) and was killed. + +## Cancelling Jobs + +Sometimes we'll make a mistake and need to cancel a job. This can be done with +the `{{ site.sched.del }}` command. + + + + + +In order to cancel the job, we will first need its 'JobId', this can be found in the output of '{{ site.sched.status }} {{ site.sched.flag.me }}'. + +``` +{{ site.remote.prompt }} {{site.sched.del }} 231964 +``` +{: .language-bash} + +A clean return of your command prompt indicates that the request to cancel the job was +successful. + +Now checking `{{ site.sched.status }}` again, the job should be gone. + +``` +{{ site.remote.prompt }} {{ site.sched.status }} {{ site.sched.flag.me }} +``` +{: .language-bash} + +{% include {{ site.snippets }}/scheduler/terminate-job-cancel.snip %} + +(If it isn't wait a few seconds and try again). + +{% include {{ site.snippets }}/scheduler/terminate-multiple-jobs.snip %} + +## Checking Finished Jobs + +There is another command `{{ site.sched.hist }}` (**s**lurm **acc**oun**t**) that includes jobs that have finished. +By default `{{ site.sched.hist }}` only includes jobs submitted by you, so no need to include additional commands at this point. + +``` +{{ site.remote.prompt }} {{ site.sched.hist }} +``` +{: .language-bash} + +{% include {{ site.snippets }}/scheduler/basic-job-status-sacct.snip %} + +Note that despite the fact that we have only run one job, there are three lines shown, this because each _job step_ is also shown. +This can be suppressed using the flag `-X`. + +> ## Where's the Output? +> +> On the login node, when we ran the bash script, the output was printed to the terminal. +> Slurm batch job output is typically redirected to a file, by default this will be a file named `slurm-.out` in the directory where the job was submitted, this can be changed with the slurm parameter `--output`. +{: .discussion} +> +> > ## Hint +> > +> > You can use the _manual pages_ for {{ site.sched.name }} utilities to find +> > more about their capabilities. On the command line, these are accessed +> > through the `man` utility: run `man `. You can find the same +> > information online by searching > "man ". +> > +> > ``` +> > {{ site.remote.prompt }} man {{ site.sched.submit.name }} +> > ``` +> > {: .language-bash} +> {: .solution} +{: .challenge} + +{% include {{ site.snippets }}/scheduler/print-sched-variables.snip %} + +[//]: # TODO ??Sacct more info on checking jobs. Checking log files during run. + + + + +{% include links.md %} + +[fshs]: https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard +[hisat]: https://ccb.jhu.edu/software/hisat2/index.shtml diff --git a/docs/Scientific_Computing/Training/Intro_HPC/what_is_a_cluster.md b/docs/Scientific_Computing/Training/Intro_HPC/what_is_a_cluster.md new file mode 100644 index 000000000..d21addf19 --- /dev/null +++ b/docs/Scientific_Computing/Training/Intro_HPC/what_is_a_cluster.md @@ -0,0 +1,93 @@ +--- +title: "Working on a remote HPC system" +# teaching: 10 +teaching: 20 +exercises: 0 +questions: +- "What is an HPC system?" +- "How does an HPC system work?" +- "How do I log in to a remote HPC system?" +objectives: +- "Connect to a remote HPC system." +- "Understand the general HPC system architecture." +keypoints: +- "An HPC system is a set of networked machines." +- "HPC systems typically provide login nodes and a set of compute nodes." +- "The resources found on independent (compute) nodes can vary in volume and + type (amount of RAM, processor architecture, availability of network mounted + filesystems, etc.)." +- "Files saved on shared storage are available on all nodes." +- "The login node is a shared machine: be considerate of other users." +--- + +## What Is an HPC System? + +The words "cloud", "cluster", and the phrase "high-performance computing" or +"HPC" are used a lot in different contexts and with various related meanings. +So what do they mean? And more importantly, how do we use them in our work? + +A *Remote* computer is one you have no access to physically and must connect via a network (as opposed to *Local*) + +*Cloud* refers to remote computing resources +that are provisioned to users on demand or as needed. + +*HPC*, *High Performance Computer*, *High Performance Computing* or *Supercomputer* are all general terms for a large or powerful computing resource. + +*Cluster* is a more specific term describing a type of supercomputer comprised of multiple smaller computers (nodes) working together. Almost all supercomputers are clusters. + +![NeSI-HPC-Facility](../fig/NeSI-HPC-Facility.jpg) + +## Access + +You will connect to a cluster over the internet either with a web client (Jupyter) or with SSH (**S**ecure **Sh**ell). Your main interface with the cluster will be using command line. + +## Nodes + +Individual computers that compose a cluster are typically called *nodes*. +On a cluster, there are different types of nodes for different +types of tasks. The node where you are now will be different depending on +how you accessed the cluster. + +Most of you (using JupyterHub) will be on an interactive *compute node*. +This is because Jupyter sessions are launched as a job. If you are using SSH to connect to the cluster, you will be on a +*login node*. Both JupyterHub and SSH login nodes serve as an access point to the cluster. + + + +The real work on a cluster gets done by the *compute nodes*. +Compute nodes come in many shapes and sizes, but generally are dedicated to long +or hard tasks that require a lot of computational resources. + +## What's in a Node? + +A node is similar in makeup to a regular desktop or laptop, composed of *CPUs* (sometimes also called *processors* or *cores*), *memory* +(or *RAM*), and *disk* space. Although, where your laptop might have 8 CPUs and 16GB of memory, a compute node will have hundreds of cores and GB of memory. + +* **CPUs** are a computer's tool for running programs and calculations. + +* **Memory** is for short term storage, containing the information currently being operated on by the CPUs. + +* **Disk** is for long term storage, data stored here is permanent, i.e. still there even if the computer has been restarted. +It is common for nodes to connect to a shared, remote disk. + +{% include figure.html url="" max-width="40%" + file="/fig/clusterDiagram.png" + alt="Node anatomy" caption="" %} + +> ## Differences Between Nodes +> +> Many HPC clusters have a variety of nodes optimized for particular workloads. +> Some nodes may have larger amount of memory, or specialized resources such as +> Graphical Processing Units (GPUs). +{: .callout} + +> ## Dedicated Transfer Nodes +> +> If you want to transfer larger amounts of data to or from the cluster, NeSI +> offers dedicated transfer nodes using the Globus service. More information on using Globus for large data transfer to and from +> the cluster can be found here: [Globus Transfer Service](https://docs.nesi.org.nz/Storage/Data_Transfer_Services/Globus_Quick_Start_Guide/) +{: .callout} + +{% include links.md %} +[fshs]: https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard diff --git a/docs/Scientific_Computing/Training/Introduction_to_computing_on_the_NeSI_HPC_YouTube_Recordings.md b/docs/Scientific_Computing/Training/Introduction_to_computing_on_the_NeSI_HPC_YouTube_Recordings.md deleted file mode 100644 index 4f4a69389..000000000 --- a/docs/Scientific_Computing/Training/Introduction_to_computing_on_the_NeSI_HPC_YouTube_Recordings.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -created_at: '2022-07-26T21:43:02Z' -tags: [] -title: Introduction to computing on the NeSI HPC (YouTube Recordings) -vote_count: 0 -vote_sum: 0 -zendesk_article_id: 5209502688655 -zendesk_section_id: 5203123172239 ---- - -- [Introduction to computing on the NeSI HPC (Part 1)](https://www.youtube.com/watch?v=RrFAb8Atsc0&list=PLvbRzoDQPkuFsIzAWaIiYgs-kConq-Hjw) -- [Introduction to computing on the NeSI HPC platform (Part 2)](https://www.youtube.com/watch?v=8TNcFZvXSao&list=PLvbRzoDQPkuFsIzAWaIiYgs-kConq-Hjw&index=2) -- [Introduction to computing on the NeSI HPC (Part 3)](https://www.youtube.com/watch?v=0Vw4b7yY8o8&list=PLvbRzoDQPkuFsIzAWaIiYgs-kConq-Hjw&index=3) -- [Introduction to computing on the NeSI HPC (Part 4)](https://www.youtube.com/watch?v=kXf6RkRQ6tU&list=PLvbRzoDQPkuFsIzAWaIiYgs-kConq-Hjw&index=4) From 525836c1c7d2232424ee293b12e8c370d8303bca Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Thu, 4 Dec 2025 19:34:55 +1300 Subject: [PATCH 02/23] moving to fin inside new struct --- .../Intro_HPC/14-environment-variables.md | 0 .../Training/Intro_HPC/Bash_shell.md} | 1 + .../Training/Intro_HPC/Filesystem_basics.md} | 0 .../Training/Intro_HPC/Modules.md} | 0 .../Training/Intro_HPC/Parallel.md} | 0 .../Training/Intro_HPC/Resources.md} | 0 .../Training/Intro_HPC/Scaling.md} | 0 .../Training/Intro_HPC/Scheduler.md} | 0 .../Intro_HPC/What_Is_a_HPC_cluster.md} | 22 +++---------------- .../Training/Intro_HPC/writing_good_code.md} | 0 .../Training/Intro_HPC/035-filedir-cont.md | 5 ----- 11 files changed, 4 insertions(+), 24 deletions(-) rename docs/{Scientific_Computing => Getting_Started/Getting_Help}/Training/Intro_HPC/14-environment-variables.md (100%) rename docs/{Scientific_Computing/Training/Intro_HPC/bash_shell.md => Getting_Started/Getting_Help/Training/Intro_HPC/Bash_shell.md} (99%) rename docs/{Scientific_Computing/Training/Intro_HPC/filesystem_basics.md => Getting_Started/Getting_Help/Training/Intro_HPC/Filesystem_basics.md} (100%) rename docs/{Scientific_Computing/Training/Intro_HPC/modules.md => Getting_Started/Getting_Help/Training/Intro_HPC/Modules.md} (100%) rename docs/{Scientific_Computing/Training/Intro_HPC/parallel.md => Getting_Started/Getting_Help/Training/Intro_HPC/Parallel.md} (100%) rename docs/{Scientific_Computing/Training/Intro_HPC/resources.md => Getting_Started/Getting_Help/Training/Intro_HPC/Resources.md} (100%) rename docs/{Scientific_Computing/Training/Intro_HPC/scaling.md => Getting_Started/Getting_Help/Training/Intro_HPC/Scaling.md} (100%) rename docs/{Scientific_Computing/Training/Intro_HPC/scheduler.md => Getting_Started/Getting_Help/Training/Intro_HPC/Scheduler.md} (100%) rename docs/{Scientific_Computing/Training/Intro_HPC/what_is_a_cluster.md => Getting_Started/Getting_Help/Training/Intro_HPC/What_Is_a_HPC_cluster.md} (83%) rename docs/{Scientific_Computing/Training/Intro_HPC/095-writing-good-code.md => Getting_Started/Getting_Help/Training/Intro_HPC/writing_good_code.md} (100%) delete mode 100644 docs/Scientific_Computing/Training/Intro_HPC/035-filedir-cont.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/14-environment-variables.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/14-environment-variables.md similarity index 100% rename from docs/Scientific_Computing/Training/Intro_HPC/14-environment-variables.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/14-environment-variables.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/bash_shell.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Bash_shell.md similarity index 99% rename from docs/Scientific_Computing/Training/Intro_HPC/bash_shell.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/Bash_shell.md index 501e218be..431641f7a 100644 --- a/docs/Scientific_Computing/Training/Intro_HPC/bash_shell.md +++ b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Bash_shell.md @@ -28,6 +28,7 @@ keypoints: - "Directory names in a path are separated with `/` on Unix, but `\\` on Windows." - "`..` means 'the directory above the current one'; `.` on its own means 'the current directory'." --- + > ## The Unix Shell > > This episode will be a quick introduction to the Unix shell, only the bare minimum required to use the cluster. diff --git a/docs/Scientific_Computing/Training/Intro_HPC/filesystem_basics.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Filesystem_basics.md similarity index 100% rename from docs/Scientific_Computing/Training/Intro_HPC/filesystem_basics.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/Filesystem_basics.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/modules.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Modules.md similarity index 100% rename from docs/Scientific_Computing/Training/Intro_HPC/modules.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/Modules.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/parallel.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Parallel.md similarity index 100% rename from docs/Scientific_Computing/Training/Intro_HPC/parallel.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/Parallel.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/resources.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Resources.md similarity index 100% rename from docs/Scientific_Computing/Training/Intro_HPC/resources.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/Resources.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/scaling.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scaling.md similarity index 100% rename from docs/Scientific_Computing/Training/Intro_HPC/scaling.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scaling.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/scheduler.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scheduler.md similarity index 100% rename from docs/Scientific_Computing/Training/Intro_HPC/scheduler.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scheduler.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/what_is_a_cluster.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/What_Is_a_HPC_cluster.md similarity index 83% rename from docs/Scientific_Computing/Training/Intro_HPC/what_is_a_cluster.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/What_Is_a_HPC_cluster.md index d21addf19..442f1af71 100644 --- a/docs/Scientific_Computing/Training/Intro_HPC/what_is_a_cluster.md +++ b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/What_Is_a_HPC_cluster.md @@ -1,23 +1,7 @@ --- -title: "Working on a remote HPC system" -# teaching: 10 -teaching: 20 -exercises: 0 -questions: -- "What is an HPC system?" -- "How does an HPC system work?" -- "How do I log in to a remote HPC system?" -objectives: -- "Connect to a remote HPC system." -- "Understand the general HPC system architecture." -keypoints: -- "An HPC system is a set of networked machines." -- "HPC systems typically provide login nodes and a set of compute nodes." -- "The resources found on independent (compute) nodes can vary in volume and - type (amount of RAM, processor architecture, availability of network mounted - filesystems, etc.)." -- "Files saved on shared storage are available on all nodes." -- "The login node is a shared machine: be considerate of other users." +description: Introduction to basic terminology and principles of High Performance Computing +tags: + - training --- ## What Is an HPC System? diff --git a/docs/Scientific_Computing/Training/Intro_HPC/095-writing-good-code.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/writing_good_code.md similarity index 100% rename from docs/Scientific_Computing/Training/Intro_HPC/095-writing-good-code.md rename to docs/Getting_Started/Getting_Help/Training/Intro_HPC/writing_good_code.md diff --git a/docs/Scientific_Computing/Training/Intro_HPC/035-filedir-cont.md b/docs/Scientific_Computing/Training/Intro_HPC/035-filedir-cont.md deleted file mode 100644 index ff8933246..000000000 --- a/docs/Scientific_Computing/Training/Intro_HPC/035-filedir-cont.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Navigating Files and Directories (Continued)" -layout: break -break: 50 ---- \ No newline at end of file From 1999422405fd0fdd4dd5a467b91612f9b3950845 Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Wed, 7 Jan 2026 17:04:39 +1300 Subject: [PATCH 03/23] initial edits --- docs/Batch_Computing/Batch_Computing_Guide.md | 1 + .../Submitting_your_first_job.md | 140 +++--------------- .../Cheat_Sheets/Slurm-Reference_Sheet.md | 2 +- 3 files changed, 25 insertions(+), 118 deletions(-) diff --git a/docs/Batch_Computing/Batch_Computing_Guide.md b/docs/Batch_Computing/Batch_Computing_Guide.md index 0e205f791..4ab9864da 100644 --- a/docs/Batch_Computing/Batch_Computing_Guide.md +++ b/docs/Batch_Computing/Batch_Computing_Guide.md @@ -17,6 +17,7 @@ Depending on the needs of your batch jobs, you may need to specify the partition ## Slurm job basics Please see [Submitting your first job](Submitting_your_first_job.md) for a detailed tutorial with instructions and examples. +We also have a [Slurm reference sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md). ### Batch scripts diff --git a/docs/Batch_Computing/Submitting_your_first_job.md b/docs/Batch_Computing/Submitting_your_first_job.md index 1e7a6ec11..a0a61e4b5 100644 --- a/docs/Batch_Computing/Submitting_your_first_job.md +++ b/docs/Batch_Computing/Submitting_your_first_job.md @@ -3,139 +3,45 @@ created_at: '2019-01-07T01:10:28Z' tags: - slurm - scheduler -vote_count: 8 -vote_sum: 8 -zendesk_article_id: 360000684396 -zendesk_section_id: 360000189716 +- tutorial +description: Tutorial on how to submit your first Slurm job --- -## Environment Modules +!!! prerequisite "" + This tutorial assumes basic familiarity with bash and the terminal. + Please see at least the first three lessons of the [Software Carpentry Unix Shell lessons](https://swcarpentry.github.io/shell-novice/). -Modules are a convenient way to provide access to applications on the cluster. They prepare the environment you need to run an application. +## Writing your first batch script -For a full list of module commands run `man module`. +## Submitting your first batch script -| Command | Description | -| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `module spider [ ]` | List all modules whose names, including version strings, contain ``. If the `` argument is not supplied, list all available modules. | -| `module show ` | Show the contents of the module given by ``. If only the module name (e.g. `Python`) is given, show the default module of that name. If both name and version are given, show that particular version module. | -| `module load ` | Load the module (name and version) given by ``. If no version is given, load the default version. | -| `module list [ ]` | List all currently loaded modules whose names, including version strings, contain ``. If the `` argument is not supplied, list all currently loaded modules. | +## Checking the queue -## Slurm +## Checking on previous jobs -Jobs on the HPC are submitted in the form of a *batch script* containing the code you want to run and a header of information needed by our job scheduler *Slurm*. +## Useful Slurm commands -## Creating a batch script +There are two good sources for quick references on using Slurm: -Create a new file and open it with `nano myjob.sl` +- our [Slurm Reference Sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md) +- the official [Slurm documentation](https://slurm.schedmd.com/) and [cheatsheet](https://slurm.schedmd.com/pdfs/summary.pdf) -```sl -#!/bin/bash -e +Below is a summary of the commands you are likely to use on a regular basis while using Mahuika. -#SBATCH --job-name=SerialJob # job name (shows up in the queue) -#SBATCH --time=00:01:00 # Walltime (HH:MM:SS) -#SBATCH --mem=512MB # Memory in MB -#SBATCH --qos=debug # debug QOS for high priority job tests +### `sbatch` -pwd # Prints working directory -``` +### `srun` -Copy in the above text and save and exit the text editor with 'ctrl + x'. +### `salloc` -Note: `#!/bin/bash` is expected by Slurm. +### `squeue` -Note: if you are a member of multiple accounts you should add the line +### `sacct` -```sl -#SBATCH --account= -``` +### `scancel` -## Testing +## Next steps -We recommend testing your job using the debug Quality of Service (QOS). -The debug QOS can be gained by adding the `sbatch` command line option `--qos=debug`. -This adds 5000 to the job priority so raises it above all non-debug jobs, but is limited to one small job per user at a time: no more than 15 minutes and no more than 2 nodes. +[Slurm Best Practices](SLURM-Best_Practice.md) -!!! warning - Please do not run your code on the login node. - Any processes running on the login node for long periods of time or using large numbers of CPUs will be terminated. - -## Submitting - -Jobs are submitted to the scheduler using: - -```bash -sbatch myjob.sl -``` - -You should receive an output - -Submitted batch job 1748836 - -`sbatch` can take command line arguments similar to those used in the shell script through SBATCH pragmas - -You can find more details on its use on the [Slurm Documentation](https://slurm.schedmd.com/archive/{{config.extra.slurm}}/sbatch.html) - -## Job Queue - -The currently queued jobs can be checked using - -```bash -squeue -``` - -You can filter to just your jobs by adding the flag - -```bash -squeue -u usr9999 -``` - -You can also filter to just your jobs using - -```bash -squeue --me -``` - -You can find more details on its use on the [Slurm Documentation](https://slurm.schedmd.com/archive/{{config.extra.slurm}}/squeue.html). - -You can check all jobs submitted by you in the past day using: - -```bash -sacct -``` - -Or since a specified date using: - -```bash -sacct -S YYYY-MM-DD -``` - -Each job will show as multiple lines, one line for the parent job and then additional lines for each job step. - -!!! tip - - `sacct -X` Only show parent processes. - - `sacct --state=PENDING/RUNNING/FAILED/CANCELLED/TIMEOUT` Filter jobs by state. - -You can find more details on its use on the [Slurm Documentation](https://slurm.schedmd.com/archive/{{config.extra.slurm}}/sacct.html). - -## Cancelling - -`scancel ` will cancel the job described by ``. -You can obtain the job ID by using `sacct` or `squeue`. - -!!! tip - - `scancel -u [username]` Kill all jobs submitted by you. - - `scancel {[n1]..[n2]}` Kill all jobs with an id between `[n1]` and `[n2]`. - -You can find more details on its use on the [Slurm Documentation](https://slurm.schedmd.com/archive/{{config.extra.slurm}}/scancel.html). - -## Job Output - -When the job completes, or in some cases earlier, two files will be -added to the directory in which you were working when you submitted the -job: - -`slurm-[jobid].out` containing standard output. - -`slurm-[jobid].err` containing standard error. +[Checking resource usage](Checking_resource_usage.md) diff --git a/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md b/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md index 39cc74362..4853324d8 100644 --- a/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md +++ b/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md @@ -8,7 +8,7 @@ description: Quick list of the most commonly used Slurm commands, flags, and env --- If you are unsure about using our job scheduler Slurm, more details can -be found on [Submitting_your_first_job](../../Batch_Computing/Submitting_your_first_job.md). +be found on [Batch Computing Guide](../../Batch_Computing/Batch_Computing_Guide.md) and we have a self-paced tutorial on [Submitting your first job](../../Batch_Computing/Submitting_your_first_job.md). ## Slurm Commands From 044f1ebe264931bfae6de58e6a9bbf69e0a80a09 Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Thu, 8 Jan 2026 10:45:54 +1300 Subject: [PATCH 04/23] squeue info --- .../Submitting_your_first_job.md | 12 +++++++++++- docs/assets/images/squeue.png | Bin 0 -> 125282 bytes 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 docs/assets/images/squeue.png diff --git a/docs/Batch_Computing/Submitting_your_first_job.md b/docs/Batch_Computing/Submitting_your_first_job.md index a0a61e4b5..98aa94ef5 100644 --- a/docs/Batch_Computing/Submitting_your_first_job.md +++ b/docs/Batch_Computing/Submitting_your_first_job.md @@ -9,7 +9,7 @@ description: Tutorial on how to submit your first Slurm job !!! prerequisite "" This tutorial assumes basic familiarity with bash and the terminal. - Please see at least the first three lessons of the [Software Carpentry Unix Shell lessons](https://swcarpentry.github.io/shell-novice/). + The first three lessons of the [Software Carpentry Unix Shell lessons](https://swcarpentry.github.io/shell-novice/) covers the information needed. ## Writing your first batch script @@ -17,6 +17,16 @@ description: Tutorial on how to submit your first Slurm job ## Checking the queue +All users have the ability to view the entire queue for the cluster by running the command `squeue`. +This will list all jobs running or waiting to run on Mahuika, which can be quite a large number. + +![Example of `squeue`](../../assets/images/squeue.png) + +It is often far more useful to look at the status of running or queued jobs that you submitted, and there is a shortcut to help with this: `squeue --me`. +This will return information on only the jobs that you have in the queue. + +By default, `squeue` will return X columns of information, but you can request additional fields. + ## Checking on previous jobs ## Useful Slurm commands diff --git a/docs/assets/images/squeue.png b/docs/assets/images/squeue.png new file mode 100644 index 0000000000000000000000000000000000000000..dbf4efca345d00104cc8734e211c715117698b48 GIT binary patch literal 125282 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 Ad;kCd literal 0 HcmV?d00001 From 8b4727aed7cb9719076ae9b0ecfefc0d3d2feb9a Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Thu, 8 Jan 2026 11:24:47 +1300 Subject: [PATCH 05/23] minor changes --- .../Submitting_your_first_job.md | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/docs/Batch_Computing/Submitting_your_first_job.md b/docs/Batch_Computing/Submitting_your_first_job.md index 98aa94ef5..9beb91613 100644 --- a/docs/Batch_Computing/Submitting_your_first_job.md +++ b/docs/Batch_Computing/Submitting_your_first_job.md @@ -15,6 +15,8 @@ description: Tutorial on how to submit your first Slurm job ## Submitting your first batch script +`sbatch` + ## Checking the queue All users have the ability to view the entire queue for the cluster by running the command `squeue`. @@ -27,8 +29,14 @@ This will return information on only the jobs that you have in the queue. By default, `squeue` will return X columns of information, but you can request additional fields. +## Interacting with running jobs + +`scancel` + ## Checking on previous jobs +`sacct` + ## Useful Slurm commands There are two good sources for quick references on using Slurm: @@ -36,20 +44,6 @@ There are two good sources for quick references on using Slurm: - our [Slurm Reference Sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md) - the official [Slurm documentation](https://slurm.schedmd.com/) and [cheatsheet](https://slurm.schedmd.com/pdfs/summary.pdf) -Below is a summary of the commands you are likely to use on a regular basis while using Mahuika. - -### `sbatch` - -### `srun` - -### `salloc` - -### `squeue` - -### `sacct` - -### `scancel` - ## Next steps [Slurm Best Practices](SLURM-Best_Practice.md) From 881c0dba03e44d7b6f5487fd3ce665649822623b Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Fri, 9 Jan 2026 13:38:16 +1300 Subject: [PATCH 06/23] incorporating hpc-intro materials --- docs/Batch_Computing/.pages.yml | 2 +- docs/Batch_Computing/Batch_Computing_Guide.md | 2 +- .../Submitting_your_first_job.md | 51 ------ .../Tutorial:_Submitting_your_first_job.md | 149 ++++++++++++++++++ docs/Batch_Computing/Using_GPUs.md | 2 +- .../Accessing_the_HPCs/VSCode.md | 2 +- .../Cheat_Sheets/Slurm-Reference_Sheet.md | 2 +- .../OnDemand/Apps/JupyterLab/index.md | 2 +- docs/redirect_map.yml | 1 + 9 files changed, 156 insertions(+), 57 deletions(-) delete mode 100644 docs/Batch_Computing/Submitting_your_first_job.md create mode 100644 docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md diff --git a/docs/Batch_Computing/.pages.yml b/docs/Batch_Computing/.pages.yml index 70daa8fcf..2d39b002a 100644 --- a/docs/Batch_Computing/.pages.yml +++ b/docs/Batch_Computing/.pages.yml @@ -1,6 +1,5 @@ nav: - Batch_Computing_Guide.md - - Submitting_your_first_job.md - Hardware.md - Job_prioritisation.md - SLURM-Best_Practice.md @@ -8,4 +7,5 @@ nav: - Job_Checkpointing.md - Fair_Share.md - Checksums.md + - Tutorial:_Submitting_your_first_job.md - "*" diff --git a/docs/Batch_Computing/Batch_Computing_Guide.md b/docs/Batch_Computing/Batch_Computing_Guide.md index 4ab9864da..eae8d1adc 100644 --- a/docs/Batch_Computing/Batch_Computing_Guide.md +++ b/docs/Batch_Computing/Batch_Computing_Guide.md @@ -16,7 +16,7 @@ Depending on the needs of your batch jobs, you may need to specify the partition ## Slurm job basics -Please see [Submitting your first job](Submitting_your_first_job.md) for a detailed tutorial with instructions and examples. +Please see [Submitting your first job](Tutorial:_Submitting_your_first_job.md) for a detailed tutorial with instructions and examples. We also have a [Slurm reference sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md). ### Batch scripts diff --git a/docs/Batch_Computing/Submitting_your_first_job.md b/docs/Batch_Computing/Submitting_your_first_job.md deleted file mode 100644 index 9beb91613..000000000 --- a/docs/Batch_Computing/Submitting_your_first_job.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -created_at: '2019-01-07T01:10:28Z' -tags: -- slurm -- scheduler -- tutorial -description: Tutorial on how to submit your first Slurm job ---- - -!!! prerequisite "" - This tutorial assumes basic familiarity with bash and the terminal. - The first three lessons of the [Software Carpentry Unix Shell lessons](https://swcarpentry.github.io/shell-novice/) covers the information needed. - -## Writing your first batch script - -## Submitting your first batch script - -`sbatch` - -## Checking the queue - -All users have the ability to view the entire queue for the cluster by running the command `squeue`. -This will list all jobs running or waiting to run on Mahuika, which can be quite a large number. - -![Example of `squeue`](../../assets/images/squeue.png) - -It is often far more useful to look at the status of running or queued jobs that you submitted, and there is a shortcut to help with this: `squeue --me`. -This will return information on only the jobs that you have in the queue. - -By default, `squeue` will return X columns of information, but you can request additional fields. - -## Interacting with running jobs - -`scancel` - -## Checking on previous jobs - -`sacct` - -## Useful Slurm commands - -There are two good sources for quick references on using Slurm: - -- our [Slurm Reference Sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md) -- the official [Slurm documentation](https://slurm.schedmd.com/) and [cheatsheet](https://slurm.schedmd.com/pdfs/summary.pdf) - -## Next steps - -[Slurm Best Practices](SLURM-Best_Practice.md) - -[Checking resource usage](Checking_resource_usage.md) diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md new file mode 100644 index 000000000..21e6a8bb3 --- /dev/null +++ b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md @@ -0,0 +1,149 @@ +--- +created_at: '2019-01-07T01:10:28Z' +tags: +- slurm +- scheduler +- tutorial +description: Tutorial on how to submit your first Slurm job +--- + +!!! prerequisite "" + This tutorial assumes basic familiarity with bash and the terminal. + The first three lessons of the [Software Carpentry Unix Shell lessons](https://swcarpentry.github.io/shell-novice/) covers the information needed. + +# Overview + +The exercises in this tutorial should take approximately 10 minutes to complete. + +## Questions + +- What is a scheduler and why does a cluster need one? +- How do I launch a program to run on a compute node in the cluster? +- How do I capture the output of a program that is run on a node in the cluster? + +## Objectives + +- Run a simple script through the scheduler +- Use the batch system command line tools to monitor the execution of your job +- Inspect the output and error files of your jobs + +# What is a job scheduler? + +An HPC system might have thousands of nodes and thousands of users. +How do we decide who gets what and when? +How do we ensure that a task is run with the resources it needs? +This job is handled by a special piece of software called the scheduler. +On an HPC system, the scheduler manages which jobs run where and when. + +The following illustration compares these tasks of a job scheduler to a waiter in a restaurant. +If you can relate to an instance where you had to wait for a while in a queue to get in to a popular restaurant, then you may now understand why sometimes your job do not start instantly as in your laptop. + +![]() + +The scheduler used in this lesson is [Slurm](https://slurm.schedmd.com/). +Although Slurm is not used everywhere, running jobs is quite similar regardless of what software is being used. +The exact syntax might change, but the concepts remain the same. + +# What is a batch job? + +Typically, when we enter a command into our terminal, we receive a response immediately in the same terminal. +This is what we call an *interactive session*. + +This is all well for doing small tasks, but what if we want to do several things one after another without without waiting in-between? +Or what if we want to repeat a series of command again later? + +This is where *batch* processing becomes useful, this is where instead of entering commands directly to the terminal we write them down in a text file or script. +Then, the script can be executed by calling it with bash. + +## Writing your first batch script + +Let's try this now, create and open a new file in your current directory called `example_job.sh`. +(If you prefer another text editor than `nano`, feel free to use that) + +```sh +10:00:00 login01 $ nano example_job.sh +``` + + +```sh +#!/bin/bash -e + +module purge +module load R +Rscript sum_matrix.r +echo "Done!" +``` + +!!! info "shebang" + *shebang* or *shabang*, also referred to as *hashbang* is the character sequence consisting of the number sign (aka: hash) and exclamation mark (aka: bang): `#!` at the beginning of a script. + It is used to describe the interpreter that will be used to run the script. + In this case we will be using the Bash Shell, which can be found at the path `/bin/bash`. + The job scheduler will give you an error if your script does not start with a shebang. + + We recommend using `#!/bin/bash -e` instead of plain `#!/bin/bash`, so that the failure of any command within the script will cause your job to stop immediately rather than attempting to continue on with an unexpected environment or erroneous intermediate data. + +We can now run this script using + +```sh +10:00:00 login01 $ bash example_job.sh +``` + +```sh +The following modules were not unloaded: + (Use "module --force purge" to unload all): + + 1) NeSI/zen3 +Running non-MPI task +Shared Memory Running on 'login01.hpc.nesi.org.nz' with 1 CPU(s) +Summing [ 6.000000e+04 x 4.000000e+04 ] matrix, seed = '0' + 1% done... + 2% done... +... + 98% done... + 99% done... + 100% done... +(Non-MPI) Sums to -29910.135471 +Done! +``` + +!!! info "Cancelling commands" + You can kill a currently running task by pressing the keys `ctrl + c`. + If you just want your terminal back, but want the task to continue running you can ‘background’ it by pressing `ctrl + v`. + Note, a backgrounded task is still attached to your terminal session, and will be killed when you close the terminal (if you need to keep running a task after you log out, have a look at [tmux](https://github.com/tmux/tmux/wiki)). + +## Scheduling your batch job + +`sbatch` + +## Checking your running/pending jobs + +All users have the ability to view the entire queue for the cluster by running the command `squeue`. +This will list all jobs running or waiting to run on Mahuika, which can be quite a large number. + +![Example of `squeue`](../../assets/images/squeue.png) + +It is often far more useful to look at the status of running or queued jobs that you submitted, and there is a shortcut to help with this: `squeue --me`. +This will return information on only the jobs that you have in the queue. + +By default, `squeue` will return X columns of information, but you can request additional fields. + +## Interacting with running jobs + +`scancel` + +## Checking on finished jobs + +`sacct` + +## Useful Slurm commands + +There are two good sources for quick references on using Slurm: + +- our [Slurm Reference Sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md) +- the official [Slurm documentation](https://slurm.schedmd.com/) and [cheatsheet](https://slurm.schedmd.com/pdfs/summary.pdf) + +# Key points + +- The scheduler handles how compute resources are shared between users +- A job is just a shell script +- Request *slightly* more resources than you need diff --git a/docs/Batch_Computing/Using_GPUs.md b/docs/Batch_Computing/Using_GPUs.md index 66b1768a9..76ddc94a1 100644 --- a/docs/Batch_Computing/Using_GPUs.md +++ b/docs/Batch_Computing/Using_GPUs.md @@ -18,7 +18,7 @@ This page provides generic information about how to access GPUs through the Slur ## Request GPU resources using Slurm -To request a GPU for your [Slurm job](Submitting_your_first_job.md), add +To request a GPU for your [Slurm job](Tutorial:_Submitting_your_first_job.md), add the following option in the header of your submission script: ```sl diff --git a/docs/Getting_Started/Accessing_the_HPCs/VSCode.md b/docs/Getting_Started/Accessing_the_HPCs/VSCode.md index b35fc7729..420fb37d3 100644 --- a/docs/Getting_Started/Accessing_the_HPCs/VSCode.md +++ b/docs/Getting_Started/Accessing_the_HPCs/VSCode.md @@ -83,7 +83,7 @@ Clicking on these will open a connection to that machine, you will then be promp You may find that VSCode is not utilising your preferred versions of software (e.g. when debugging or linting your Python code). -As the NeSI cluster utilises [Environment Modules](../../Batch_Computing/Submitting_your_first_job.md#environment-modules), changing the executable used is not just a matter of changing the path in VSCode configuration, as the libraries required will not be loaded. +As the NeSI cluster utilises [Environment Modules](../../Batch_Computing/Tutorial:_Submitting_your_first_job.md#environment-modules), changing the executable used is not just a matter of changing the path in VSCode configuration, as the libraries required will not be loaded. The only way to make sure that VSCode has access to a suitable environment, is to load the required modules in your `~/.bashrc` diff --git a/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md b/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md index 4853324d8..0d8e320e8 100644 --- a/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md +++ b/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md @@ -8,7 +8,7 @@ description: Quick list of the most commonly used Slurm commands, flags, and env --- If you are unsure about using our job scheduler Slurm, more details can -be found on [Batch Computing Guide](../../Batch_Computing/Batch_Computing_Guide.md) and we have a self-paced tutorial on [Submitting your first job](../../Batch_Computing/Submitting_your_first_job.md). +be found on [Batch Computing Guide](../../Batch_Computing/Batch_Computing_Guide.md) and we have a self-paced tutorial on [Submitting your first job](../../Batch_Computing/Tutorial:_Submitting_your_first_job.md). ## Slurm Commands diff --git a/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md b/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md index f2052402e..15150c536 100644 --- a/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md +++ b/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md @@ -8,7 +8,7 @@ Jupyter allows you to create notebooks that contain live code, equations, visualisations and explanatory text. There are many uses for Jupyter, including data cleaning, analytics and visualisation, machine learning, numerical simulation, managing -[Slurm job submissions](../../../../Batch_Computing/Submitting_your_first_job.md) +[Slurm job submissions](../../../../Batch_Computing/Tutorial:_Submitting_your_first_job.md) and workflows and much more. ## Accessing Jupyter on NeSI diff --git a/docs/redirect_map.yml b/docs/redirect_map.yml index 17506fa2f..d6e6c7160 100644 --- a/docs/redirect_map.yml +++ b/docs/redirect_map.yml @@ -175,3 +175,4 @@ Software/Parallel_Computing/Parallel_Execution.md : Software/Parallel_Computing/ Software/Parallel_Computing/Job_Arrays.md : Batch_Computing/Job_Arrays.md Getting_Started/FAQs/Login_Troubleshooting.md : Getting_Started/Accessing_the_HPCs/Login_Troubleshooting.md Batch_Computing/Batch_Computing_ : Batch_Computing/Batch_Computing_Guide.md +Batch_Computing/Submitting_your_first_job.md : Batch_Computing/Tutorial:_Submitting_your_first_job.md From 6ae50d3636b5d8421178f801e038285c541b314e Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Fri, 9 Jan 2026 16:38:24 +1300 Subject: [PATCH 07/23] eod commit --- .../Tutorial:_Submitting_your_first_job.md | 83 +++++++++++++++++-- 1 file changed, 75 insertions(+), 8 deletions(-) diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md index 21e6a8bb3..d96d6b148 100644 --- a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md +++ b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md @@ -46,7 +46,7 @@ The exact syntax might change, but the concepts remain the same. # What is a batch job? -Typically, when we enter a command into our terminal, we receive a response immediately in the same terminal. +Typically, when we enter a command into our terminal, we receive a response immediately in the same terminal. This is what we call an *interactive session*. This is all well for doing small tasks, but what if we want to do several things one after another without without waiting in-between? @@ -79,7 +79,7 @@ echo "Done!" It is used to describe the interpreter that will be used to run the script. In this case we will be using the Bash Shell, which can be found at the path `/bin/bash`. The job scheduler will give you an error if your script does not start with a shebang. - + We recommend using `#!/bin/bash -e` instead of plain `#!/bin/bash`, so that the failure of any command within the script will cause your job to stop immediately rather than attempting to continue on with an unexpected environment or erroneous intermediate data. We can now run this script using @@ -87,7 +87,7 @@ We can now run this script using ```sh 10:00:00 login01 $ bash example_job.sh ``` - + ```sh The following modules were not unloaded: (Use "module --force purge" to unload all): @@ -106,22 +106,89 @@ Summing [ 6.000000e+04 x 4.000000e+04 ] matrix, seed = '0' Done! ``` +You will get the output printed to your terminal as if you had just run those commands one after another. + !!! info "Cancelling commands" - You can kill a currently running task by pressing the keys `ctrl + c`. + You can kill a currently running task by pressing the keys `ctrl + c`. If you just want your terminal back, but want the task to continue running you can ‘background’ it by pressing `ctrl + v`. Note, a backgrounded task is still attached to your terminal session, and will be killed when you close the terminal (if you need to keep running a task after you log out, have a look at [tmux](https://github.com/tmux/tmux/wiki)). ## Scheduling your batch job -`sbatch` +Up until now the scheduler has not been involved, our scripts were run directly on the login node. + +First let's rename our batch script to clarify that we intend to run it though the scheduler. + +```sh +mv example_job.sh example_job.sl +``` + +!!! info "File extensions" + A file's extension in this case does not in any way affect how a script is read, it is just another part of the name used to remind users what type of file it is. + Some common conventions: + + - `.sh`: **Sh**ell script + - `.sl`: **Sl**urm script + - `.out`: Commonly used to indicate the file contains the std**out** of some process + - `.err`: Same as `.out` but for std**err** + +In order for the job scheduler to do its job we need to provide a bit more information about our script. +This is done by specifying Slurm parameters in our batch script. +Each of these parameters must be preceded by the special token `#SBATCH` and placed after the shebang, but before the content of the rest of your script. + +![]() + +These parameters tell Slurm things around how the script should be run, like memory, cores and time required. + +All the parameters available can be found by checking `man sbatch` or on the online [Slurm documentation](https://slurm.schedmd.com/). + +| Parameter | Example | Description | +|-------------- | -------------- | -------------- | +| Job name | `#SBATCH --job-name=MyJob` | The name that will appear when using `squeue` or `sacct` | +| Account | `#SBATCH --account=nesi12345` | The account your core hours will be 'charged' to | +| Time | `#SBATCH --time=DD-HH:MM:SS` | Job max walltime | +| Memory | `#SBATCH --mem=1500M` | Memory required per node | +| Output | `#SBATCH --output=%j_output.out` | Path and name of the standard output file | +| Number of tasks | `#SBATCH --ntasks=2` | Will start 2 [MPI tasks](https://docs.nesi.org.nz/Software/Parallel_Computing/Parallel_Computing/#shared-memory-parallelisation) | +| CPUs per task | `#SBATCH --cpus-per-task` | Will request 10 CPUs per task | + +!!! question "Comments" + Comments in UNIX shell scripts (denoted by `#`) are ignored by the bash interpreter. + Why is it that we start our Slurm parameters with `#` if it is going to be ignored? + + Solution: + + Commented lines are ignored by the bash interpreter, but they are *not* ignored by Slurm. + The `#SBATCH` parameters are read by Slurm when we *submit* the job. + When the job starts, the bash interpreter will ignore all lines starting with `#`. + + This is similar to the *shebang* mentioned earlier, when you run your script, the system looks at the `#!`, then uses the program at the subsequent path to interpret the script, in our case `/bin/bash` (the program `bash` found in the `bin` directory). + +Note that just *requesting* these resources does not make your job run faster, nor does it necessarily mean that you will consume all of these resources. +It only means that these are made available to you. +Your job may end up using less memory, or less time, or fewer tasks or nodes, than you have requested, and it will still run. + +It’s best if your requests accurately reflect your job’s requirements. +We’ll talk more about how to make sure that you’re using resources effectively in a later episode of this lesson. + +Now, rather than running our script with `bash` we submit it to the scheduler using the command `sbatch` (**s**lurm **batch**). + +```sh +10:00:00 login01 $ sbatch example_job.sl +``` + +```sh +Submitted batch job 360064 +``` + +And that’s all we need to do to submit a job. +Our work is done – now the scheduler takes over and tries to run the job for us. ## Checking your running/pending jobs All users have the ability to view the entire queue for the cluster by running the command `squeue`. This will list all jobs running or waiting to run on Mahuika, which can be quite a large number. -![Example of `squeue`](../../assets/images/squeue.png) - It is often far more useful to look at the status of running or queued jobs that you submitted, and there is a shortcut to help with this: `squeue --me`. This will return information on only the jobs that you have in the queue. @@ -135,7 +202,7 @@ By default, `squeue` will return X columns of information, but you can request a `sacct` -## Useful Slurm commands +## References for Slurm commands There are two good sources for quick references on using Slurm: From 80cd16e2b166023304889e54c52dcdb97e80c4e1 Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Mon, 12 Jan 2026 10:54:57 +1300 Subject: [PATCH 08/23] finished adding info from hpc-intro --- .../Tutorial:_Submitting_your_first_job.md | 139 ++++++++++++++++-- 1 file changed, 126 insertions(+), 13 deletions(-) diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md index d96d6b148..706ddc309 100644 --- a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md +++ b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md @@ -186,28 +186,141 @@ Our work is done – now the scheduler takes over and tries to run the job for u ## Checking your running/pending jobs -All users have the ability to view the entire queue for the cluster by running the command `squeue`. -This will list all jobs running or waiting to run on Mahuika, which can be quite a large number. +While the job is waiting to run, it goes into a list of jobs called the queue. +To check on our job’s status, we check the queue using the command `squeue` (**s**lurm **queue**). +We will need to filter to see only our jobs, by including either the flag `--user ` or `--me`. -It is often far more useful to look at the status of running or queued jobs that you submitted, and there is a shortcut to help with this: `squeue --me`. -This will return information on only the jobs that you have in the queue. +```sh +10:00:00 login01 $ squeue --me +``` + +```sh +JOBID USER ACCOUNT NAME CPUS MIN_MEM PARTITI START_TIME TIME_LEFT STATE NODELIST(REASON) +231964 yourUsername nesi12345 example_job.sl 1 300M large N/A 1:00 PENDING (Priority) +``` + + +We can see many details about our job, most importantly is it’s STATE, the most common states you might see are.. + +- `PENDING`: The job is waiting in the queue, likely waiting for resources to free up or higher priority jobs to run. +- `RUNNING`: The job has been sent to a compute node and it is processing our commands. +- `COMPLETED`: Your commands completed successfully as far as Slurm can tell (e.g. `exit 0`). +- `FAILED`: (e.g. `exit` not `0`). +- `CANCELLED`: See the next section +- `TIMEOUT`: Your job has running for longer than your `--time` and was killed. +- `OUT_OF_MEMORY`: Your job tried to use more memory that it is allocated (`--mem`) and was killed. + +## Cancelling queued or running jobs + +Sometimes we’ll make a mistake and need to cancel a job. +This can be done with the `scancel` command. + +In order to cancel the job, we will first need its `JobId`, this can be found in the output of `squeue --me`. + +```sh +10:00:00 login01 $ scancel 231964 +``` + +A clean return of your command prompt indicates that the request to cancel the job was successful. + +Now checking `squeue` again, the job should be gone. + +```sh +10:00:00 login01 $ squeue --me +``` + +```sh +JOBID USER ACCOUNT NAME CPUS MIN_MEM PARTITI START_TIME TIME_LEFT STATE NODELIST(REASON) +``` -By default, `squeue` will return X columns of information, but you can request additional fields. +(If it isn’t wait a few seconds and try again). -## Interacting with running jobs +!!! question "Cancelling multiple jobs" + We can also cancel all of our jobs at once using the `-u` option. + This will delete all jobs for a specific user (in this case, yourself). + Note that you can only delete your own jobs. -`scancel` + Try submitting multiple jobs and then cancelling them all. -## Checking on finished jobs + Solution: + + First submit a trio of jobs: + + ```sh + 10:00:00 login01 $ sbatch example_job.sl + 10:00:00 login01 $ sbatch example_job.sl + 10:00:00 login01 $ sbatch example_job.sl + ``` + + Then cancel all of them: + + ```sh + 10:00:00 login01 $ scancel --user yourUsername + ``` + + +## Checking finished jobs + +There is another command `sacct` (**s**lurm **acc**oun**t**) that includes jobs that have finished. +By default `sacct` only includes jobs submitted by you, so no need to include additional commands at this point. + +```sh +10:00:00 login01 $ sacct +``` + +```sh +JobID JobName Alloc Elapsed TotalCPU ReqMem MaxRSS State +--------------- ---------------- ----- ----------- ------------ ------- -------- ---------- +31060451 example_job.sl 2 00:00:48 00:33.548 1G CANCELLED +31060451.batch batch 2 00:00:48 00:33.547 102048K CANCELLED +31060451.extern extern 2 00:00:48 00:00:00 0 CANCELLED +``` + +Note that despite the fact that we have only run one job, there are three lines shown, this because each job step is also shown. +This can be suppressed using the flag `-X`. + +!!! info "Where's the output?" + On the login node, when we ran the bash script, the output was printed to the terminal. + Slurm batch job output is typically redirected to a file, by default this will be a file named `slurm-.out` in the directory where the job was submitted, this can be changed with the slurm parameter `--output`. + + +!!! tip "More info on Slurm" + You can use the manual pages for Slurm utilities to find more about their capabilities. + On the command line, these are accessed through the man utility: run `man `. + You can find the same information online by searching: 'man ". + + ```sh + 10:00:00 login01 $ man sbatch + ``` + + There are two additional good sources for quick references on using Slurm: + + - our [Slurm Reference Sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md) + - the official [Slurm documentation](https://slurm.schedmd.com/) and [cheatsheet](https://slurm.schedmd.com/pdfs/summary.pdf) + +!!! question "Job environment variables" + When Slurm runs a job, it sets a number of environment variables for the job. + One of these will let us check what directory our job script was submitted from. + The `SLURM_SUBMIT_DIR` variable is set to the directory from which our job was submitted. + Using the `SLURM_SUBMIT_DIR` variable, modify your job so that it prints out the location from which the job was submitted. + + Solution: -`sacct` + ```sh + 10:00:00 login01 $ nano example_job.sh + 10:00:00 login01 $ cat example_job.sh + ``` -## References for Slurm commands + ```sh + #!/bin/bash -e + #SBATCH --time 00:00:30 -There are two good sources for quick references on using Slurm: + echo -n "This script is running on " + hostname -- our [Slurm Reference Sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md) -- the official [Slurm documentation](https://slurm.schedmd.com/) and [cheatsheet](https://slurm.schedmd.com/pdfs/summary.pdf) + echo "This job was launched in the following directory:" + echo ${SLURM_SUBMIT_DIR} + ``` # Key points From a7debb1c06c5cd3d97082767d335d1d05ac67a80 Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Mon, 12 Jan 2026 11:24:53 +1300 Subject: [PATCH 09/23] trying to fix sidebar toc --- .../Tutorial:_Submitting_your_first_job.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md index 706ddc309..9f28b9fad 100644 --- a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md +++ b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md @@ -11,23 +11,23 @@ description: Tutorial on how to submit your first Slurm job This tutorial assumes basic familiarity with bash and the terminal. The first three lessons of the [Software Carpentry Unix Shell lessons](https://swcarpentry.github.io/shell-novice/) covers the information needed. -# Overview +## Overview The exercises in this tutorial should take approximately 10 minutes to complete. -## Questions +### Questions - What is a scheduler and why does a cluster need one? - How do I launch a program to run on a compute node in the cluster? - How do I capture the output of a program that is run on a node in the cluster? -## Objectives +### Objectives - Run a simple script through the scheduler - Use the batch system command line tools to monitor the execution of your job - Inspect the output and error files of your jobs -# What is a job scheduler? +## What is a job scheduler? An HPC system might have thousands of nodes and thousands of users. How do we decide who gets what and when? @@ -44,7 +44,7 @@ The scheduler used in this lesson is [Slurm](https://slurm.schedmd.com/). Although Slurm is not used everywhere, running jobs is quite similar regardless of what software is being used. The exact syntax might change, but the concepts remain the same. -# What is a batch job? +## What is a batch job? Typically, when we enter a command into our terminal, we receive a response immediately in the same terminal. This is what we call an *interactive session*. @@ -55,7 +55,7 @@ Or what if we want to repeat a series of command again later? This is where *batch* processing becomes useful, this is where instead of entering commands directly to the terminal we write them down in a text file or script. Then, the script can be executed by calling it with bash. -## Writing your first batch script +### Writing your first batch script Let's try this now, create and open a new file in your current directory called `example_job.sh`. (If you prefer another text editor than `nano`, feel free to use that) @@ -113,7 +113,7 @@ You will get the output printed to your terminal as if you had just run those co If you just want your terminal back, but want the task to continue running you can ‘background’ it by pressing `ctrl + v`. Note, a backgrounded task is still attached to your terminal session, and will be killed when you close the terminal (if you need to keep running a task after you log out, have a look at [tmux](https://github.com/tmux/tmux/wiki)). -## Scheduling your batch job +### Scheduling your batch job Up until now the scheduler has not been involved, our scripts were run directly on the login node. @@ -184,7 +184,7 @@ Submitted batch job 360064 And that’s all we need to do to submit a job. Our work is done – now the scheduler takes over and tries to run the job for us. -## Checking your running/pending jobs +### Checking your running/pending jobs While the job is waiting to run, it goes into a list of jobs called the queue. To check on our job’s status, we check the queue using the command `squeue` (**s**lurm **queue**). @@ -210,7 +210,7 @@ We can see many details about our job, most importantly is it’s STATE, the mos - `TIMEOUT`: Your job has running for longer than your `--time` and was killed. - `OUT_OF_MEMORY`: Your job tried to use more memory that it is allocated (`--mem`) and was killed. -## Cancelling queued or running jobs +### Cancelling queued or running jobs Sometimes we’ll make a mistake and need to cancel a job. This can be done with the `scancel` command. @@ -259,7 +259,7 @@ JOBID USER ACCOUNT NAME CPUS MIN_MEM PARTITI START_TIME T ``` -## Checking finished jobs +### Checking finished jobs There is another command `sacct` (**s**lurm **acc**oun**t**) that includes jobs that have finished. By default `sacct` only includes jobs submitted by you, so no need to include additional commands at this point. @@ -322,7 +322,7 @@ This can be suppressed using the flag `-X`. echo ${SLURM_SUBMIT_DIR} ``` -# Key points +## Key points - The scheduler handles how compute resources are shared between users - A job is just a shell script From cb9eba5aa67985f878308f7e5cdbc586279534ca Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Mon, 12 Jan 2026 14:20:12 +1300 Subject: [PATCH 10/23] removed shebang from input examples (users always copy paste). Changed some code block types --- .../Tutorial:_Submitting_your_first_job.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md index 9f28b9fad..2bdbf1d5d 100644 --- a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md +++ b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md @@ -61,7 +61,7 @@ Let's try this now, create and open a new file in your current directory called (If you prefer another text editor than `nano`, feel free to use that) ```sh -10:00:00 login01 $ nano example_job.sh +nano example_job.sh ``` @@ -85,10 +85,10 @@ echo "Done!" We can now run this script using ```sh -10:00:00 login01 $ bash example_job.sh +bash example_job.sh ``` -```sh +```out The following modules were not unloaded: (Use "module --force purge" to unload all): @@ -174,10 +174,10 @@ We’ll talk more about how to make sure that you’re using resources effective Now, rather than running our script with `bash` we submit it to the scheduler using the command `sbatch` (**s**lurm **batch**). ```sh -10:00:00 login01 $ sbatch example_job.sl +sbatch example_job.sl ``` -```sh +```out Submitted batch job 360064 ``` @@ -191,7 +191,7 @@ To check on our job’s status, we check the queue using the command `squeue` (* We will need to filter to see only our jobs, by including either the flag `--user ` or `--me`. ```sh -10:00:00 login01 $ squeue --me +squeue --me ``` ```sh @@ -218,7 +218,7 @@ This can be done with the `scancel` command. In order to cancel the job, we will first need its `JobId`, this can be found in the output of `squeue --me`. ```sh -10:00:00 login01 $ scancel 231964 +scancel 231964 ``` A clean return of your command prompt indicates that the request to cancel the job was successful. @@ -226,10 +226,10 @@ A clean return of your command prompt indicates that the request to cancel the j Now checking `squeue` again, the job should be gone. ```sh -10:00:00 login01 $ squeue --me +squeue --me ``` -```sh +```out JOBID USER ACCOUNT NAME CPUS MIN_MEM PARTITI START_TIME TIME_LEFT STATE NODELIST(REASON) ``` @@ -247,15 +247,15 @@ JOBID USER ACCOUNT NAME CPUS MIN_MEM PARTITI START_TIME T First submit a trio of jobs: ```sh - 10:00:00 login01 $ sbatch example_job.sl - 10:00:00 login01 $ sbatch example_job.sl - 10:00:00 login01 $ sbatch example_job.sl + sbatch example_job.sl + sbatch example_job.sl + sbatch example_job.sl ``` Then cancel all of them: ```sh - 10:00:00 login01 $ scancel --user yourUsername + scancel --user yourUsername ``` @@ -265,10 +265,10 @@ There is another command `sacct` (**s**lurm **acc**oun**t**) that includes jobs By default `sacct` only includes jobs submitted by you, so no need to include additional commands at this point. ```sh -10:00:00 login01 $ sacct +sacct ``` -```sh +```out JobID JobName Alloc Elapsed TotalCPU ReqMem MaxRSS State --------------- ---------------- ----- ----------- ------------ ------- -------- ---------- 31060451 example_job.sl 2 00:00:48 00:33.548 1G CANCELLED @@ -290,7 +290,7 @@ This can be suppressed using the flag `-X`. You can find the same information online by searching: 'man ". ```sh - 10:00:00 login01 $ man sbatch + man sbatch ``` There are two additional good sources for quick references on using Slurm: @@ -307,8 +307,8 @@ This can be suppressed using the flag `-X`. Solution: ```sh - 10:00:00 login01 $ nano example_job.sh - 10:00:00 login01 $ cat example_job.sh + nano example_job.sh + cat example_job.sh ``` ```sh From e2a4beeb5b0ca442c54d50c2bad5e8c6918b1162 Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Mon, 12 Jan 2026 14:20:53 +1300 Subject: [PATCH 11/23] added cute lil icon --- .../Tutorial:_Submitting_your_first_job.md | 1 + docs/assets/stylesheets/theme.css | 13 +++++++++++-- mkdocs.yml | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md index 2bdbf1d5d..23065fb69 100644 --- a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md +++ b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md @@ -5,6 +5,7 @@ tags: - scheduler - tutorial description: Tutorial on how to submit your first Slurm job +status: tutorial --- !!! prerequisite "" diff --git a/docs/assets/stylesheets/theme.css b/docs/assets/stylesheets/theme.css index 0cd427aeb..9332845af 100644 --- a/docs/assets/stylesheets/theme.css +++ b/docs/assets/stylesheets/theme.css @@ -33,14 +33,22 @@ filter: brightness(0) invert(1); } } + + --md-status--tutorial: url('data:image/svg+xml;charset=utf-8, ') } -/* Logo biggification */ -/* COMMENTED OUT FOR REANNZ LOGO */ + /* Logo biggification */ + /* COMMENTED OUT FOR REANNZ LOGO */ /* .md-header__button.md-logo img, .md-header__button.md-logo svg { height: 4rem; margin: -2rem; } */ + +.md-status--tutorial::after { + mask-image: var(--md-status--tutorial); + -webkit-mask-image: var(--md-status--tutorial); +} + /* Version table stuff */ .md-tag.md-tag-ver{ color: var(--md-code-fg-color); @@ -185,6 +193,7 @@ span.md-status.md-status--deprecated { border-bottom: 1px solid #ccc; font-size: 1.2em; text-align: center; + z-index: 9999; } diff --git a/mkdocs.yml b/mkdocs.yml index e3a9e5c8b..bc6e2cb37 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -64,6 +64,10 @@ markdown_extensions: - def_list extra: slurm: slurm-24.11.6 + status: + - deprecated + - new + - tutorial analytics: provider: google property: G-TVQR4R1F40 From 2c3445cd7361ba4bc242a85873e70596bd8727f5 Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Mon, 12 Jan 2026 15:26:20 +1300 Subject: [PATCH 12/23] queue manager picture --- .../Tutorial:_Submitting_your_first_job.md | 2 +- .../images/restaurant_queue_manager.svg | 7038 +++++++++++++++++ 2 files changed, 7039 insertions(+), 1 deletion(-) create mode 100644 docs/assets/images/restaurant_queue_manager.svg diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md index 23065fb69..427b874b0 100644 --- a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md +++ b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md @@ -39,7 +39,7 @@ On an HPC system, the scheduler manages which jobs run where and when. The following illustration compares these tasks of a job scheduler to a waiter in a restaurant. If you can relate to an instance where you had to wait for a while in a queue to get in to a popular restaurant, then you may now understand why sometimes your job do not start instantly as in your laptop. -![]() +![Queue manager](../assets/images/restaurant_queue_manager.svg) The scheduler used in this lesson is [Slurm](https://slurm.schedmd.com/). Although Slurm is not used everywhere, running jobs is quite similar regardless of what software is being used. diff --git a/docs/assets/images/restaurant_queue_manager.svg b/docs/assets/images/restaurant_queue_manager.svg new file mode 100644 index 000000000..5cdada84e --- /dev/null +++ b/docs/assets/images/restaurant_queue_manager.svg @@ -0,0 +1,7038 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HPC diners + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + Login + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Queue manager + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The queue + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + + + Idle compute node with 6 cores + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Idle compute core + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Reserved + + + + } + + + Reserved compute node with 4 cores + + + + + + + + + + + + + + + + + + + + + + + + + + + + Reserved compute core + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Busy compute core + + + + + + User + + } + + + Busy compute node with 5 cores + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + + Compute node with 4 cores + + + + + + Allocated + + + + + + Idle + + + + + + + + + + + + + + + + + + + + + + + + + + Busy + + + + + + Busy + + + CC-BY-2.0, sabryr + + From baeb197bab727d215892d082198b0fc8c9597221 Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Mon, 12 Jan 2026 16:27:45 +1300 Subject: [PATCH 13/23] slurm script parts breakdown --- .../Tutorial:_Submitting_your_first_job.md | 2 +- docs/assets/images/parts_slurm_script.svg | 97 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 docs/assets/images/parts_slurm_script.svg diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md index 427b874b0..2e36c3639 100644 --- a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md +++ b/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md @@ -137,7 +137,7 @@ In order for the job scheduler to do its job we need to provide a bit more infor This is done by specifying Slurm parameters in our batch script. Each of these parameters must be preceded by the special token `#SBATCH` and placed after the shebang, but before the content of the rest of your script. -![]() +![](../assets/images/parts_slurm_script.svg) These parameters tell Slurm things around how the script should be run, like memory, cores and time required. diff --git a/docs/assets/images/parts_slurm_script.svg b/docs/assets/images/parts_slurm_script.svg new file mode 100644 index 000000000..1897985fc --- /dev/null +++ b/docs/assets/images/parts_slurm_script.svg @@ -0,0 +1,97 @@ + + + +Slurm headershebangkeywordoptionvaluebash commands From a01951d75ef34f8748b11a60c7566ec63dafbb70 Mon Sep 17 00:00:00 2001 From: Jen Reeve Date: Tue, 13 Jan 2026 14:45:58 +1300 Subject: [PATCH 14/23] clean up --- docs/assets/images/squeue.png | Bin 125282 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/assets/images/squeue.png diff --git a/docs/assets/images/squeue.png b/docs/assets/images/squeue.png deleted file mode 100644 index dbf4efca345d00104cc8734e211c715117698b48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125282 zcmb6B1yodh_dbk|iHd@hgoJ>U2q=nx3M1XpqNIX|fRc*jj7mv2D4o(E4N6Ojf|R5n z-QCO#^WW#b@8|vA&;J+eeOb#Tj%Uuyr}n<~bzS@TsNI!2bBf^<3WYkOATO&1!)N_N5e$|R!gg|iWr1mnfX%f$LjF1!CC#0zm|kDf#$(Op)OxEWft9h z)tIsT($kk|{jJXh2mM|ZOH|8Koy_~wO+Y!^Z#pn!lbaXIU&wT0OD;WwEP9j#lB+;8pC}Vb_7JW6^on3;DcF zlr3Z#KFVPHh{QR{sM(ueMHm~M-kX1DBof>51k}p8j4rY_sK;0?a z4NV8I{U z`M$#pR4*Ug;3ZlMiLz7NwfbRjmh@@AwRW4+@E-o$;)gG(QU94MWF}7BEDY1@@rmp4 zzfK+h;xLMFXi=Q%TwSX9rz5EA3*$N5jlLz>tNP=|F&gYQn~YnIl1xx^UOk8ZIDhm> zN6gpsk{j2*Mu)P7y1yzkTNxX^nlPL^PkKzwmidO>wX^4}4x`FRhD9ECPz}gM{_tHS z2z+IHG~GQpc{l);(w?^A(p@XtoxQRH?{d2X)!o${p{%gq|6WjkA!5*V3G$MN-V9Mq z&ugaXO`C6G>xVp>)$Bhi+9w+?zr8>F%#v2+Nr4Za$(~B@Ntl&S*S3ybj-m99%M^Hc zknEVi_o>b!OF;MHMXpChLPvy$1`D1kGTz|RcOPRV-)0=-3dLnivxy(93P!5cmeXV~DTdzh;m^OIE1j7^-G?jkI^e z`H#U^M05zJ$~g)q6A2ix$K=I14hpS`(8FAqiV51T#}CT+-s`H(*M*oCg)WDk;y}+6 z)Tc5srlL%XjJGRAMQkVeFpV8s`^WV&_Rp${M{v{hdERrev3X9*WD;UHo;2?ld0@Ii z6h*COcYVI~#b&%k@11`%t3}FkJHNV9-@^IT2bwWYU+P^cVCp|(??GSs<5qC>W3jHN z961YpL5JIfN-Ztn@PpT{l7rdgWK>iMb+hrAQltK);azLBH!Uq-yA5TnYpZFSX! z>5}nLDzH`htV(=LQOcoMM%dcgOm-Y)P3U#cXTnk~bR~>UT}Zj6<(4#W^juDC_y~DO zg=?66DQwoLY=Mk;y~gJu23Oq*HZ^M11|zxqtW(n9tW0I=_#zR*?OX6X&ErAcxg4}8 zk>iKzUDbg0pnn}w6K^BlvOuQWZi|^##&03HX#63K?0}M=s_jYYSZCEBe{j zP1=0p7Hk!FlNhG2Qp}T4=X}>wzS-{FgB=;p-}thaQAYIG?82OkrBqRdI7_eosNjgReEv##WrUIzL<|ORPGEZhA`47VtQ~XExq^deHHuD<{nXV z{mAQP6O*3Sbt!#p-RPM`UI6!6RCYVG{KmUQfR8$N zwP0!xX7Fa7A^yE}4GiQx`}gF0L5(fXENqDSwVxBef6a5ZOGWO~?&8W;*c45Vg~B*# zEOo|m+Rz49qj9g6*#s?)8{RtjxEX3B0;}!1rAR$R{qDtHLr9slU992nFTJhSCNG~A z;Wp3HWW{S-y@~!;0QP6D;Vgr&Z2P&PkvQ4%eZ=>d*OSg)*^2@9AQ0ex@dd)6t6@ti zEo5lKk+EJLZcsfv8#1w+n_KW;HL4mSb?qD_Eo`^h6_*QHL95^S#E`j5*~I5{#*U>$ zuxuS<*e&rT7{kFnAge3mKG z%?p>yz7&zd+4wZ{g<<|q>w>u5_ICqUm)5yU+D3PJ(18&Ap0$qn>X1#Znsavd@wSLS z8hFaESnC%UWmA;vrj?C-R^b4%;aa-3cWrLHjj5)#qz&8D#5b3*VBt}e+>`Gr@>fnCRick*AIAJ+wbZ z)_Lyb718I>50H|*iEf7|200Zt4AN(Eg%UA zMOm|B@OY`v7X#I<5Egu~XF;M0oyAy5b;C`pDmm9jDN5igmkz@oaiLY!*QPDq zu-uNMdOpgK(vA88rj_dT+u{42zXv?2m6B&qa|JcChmK|B=E#o4yDmB%m_Z0kauK|A zv+31+mLR*&^*FCj_<~CcO$Ue79ZRWeH>?!o zBEKsN@xjZrrA{Qvzvmm^E$zR{kLnntJq=aL#S$J}cfRD^xp(z{qU2Y)!-5r!Di14X zvLN^vI-q&z5Lz?WjTY@zkTOBc4>)V><@`$;xN|HDH z&RQkRu)eru4qqc$AzCncPTv2FqM7B7cwuj}pOVkQ))@#NjmmA8=Qy;>eXd*KOcmZx z@qQGLRlj>EUTHY-bG^SJtTFLe%gV>w997EW&TdC?cVlKCW|LpChx)fhmTmL-sU}6@4w$QxLEJY8Dez z1^yZhe*38?s@CD5FlN;{=I7wgMf+u1p&Gy@(vA0RJ~tfOd3~N(D5iOdO)_`1+%An| zM6UV%6|DO08oQ5h=wNM;ZN(-k)bp+PE3JW;qif!-QnG$Li&mw8ViYB0$;UmXPan9c zIkyU=&NR-V$Z>Ra*H}jU&{00>m$?4Gq`U4vZ6nRvj$XkTDW z>rQ_6P>rO%TpPtXE6V53!xsdy;u+#t{soeo0$;0GMNo^ZIgDLJMm46u1&73DxryVx z(E!hvOBc_^zSK6h?b5h@#v!qCo9S7L>%B|K3W@Wbgg)Hs9a7hDfi0fDPA|#MCoFN> z;2`^@WX2vLfq1|I(I{AR^Aez_u$OXG}BY-Jp>-I8Sh`mOPEZBQ|#MSRUgVTiZX$~ zU#)`rV>UM=W5*NoYh$S?qPbTpuc|q^UTkkSC-Y1ar zu3^! z(r>036 z2fgu;uNC-TtaFEk)|BGUK2O(;D>-?B(%eYWt1NH|5T@y3SvqNGK$;;zwA zo$+<6{bKryd+5rbs-SF82;tVi_`Oe?PK71c+$ogbn$Dbd;-1)ETfNQ1U1is+ZTx({ zyBw3Iena*sFGg)aY0l_U;P~xlqXbQ9cH(*m6tVj`;VAM>_o|gwedvci#ODNm~AHHT4Q8BUq~lG*;MQw#wJ#1ktZhWQ2AVr zp>ZLfF@~~fhEllYmk>nDBOLjD&!|GTyV>Om?6a65jI@k=Syl4aXNm~k_jq_G)B9{L zCJZ;2lOjT{S6H@R%-bkVm*Q>Aq9~r5yclk@eJJ8~8YZ;<>6W5}rSq1dU*`zRMM4r6 z`jny@>yi-}->vipzN!P&JOd9w*_m|Ov>TI~4^{}Q@=H0MBY5tm9Jz$4^{+?$NvU$< zB8=UsEh=>FoQHzG-5;tL!50sj-cIB?&}drHKxb~>R(W32Ia^fRarQ#h+rDWXfH{>0 zWC=xHX-kJc?AEdBkhc_*Uf=v6m0iske$bmDuzGi!4}yL3jW4P({(AAQmmNHCOOBkD zlL17L7Gf55XQZX2_+a8f!Y{j}un^>jspIjQIXnEkoN3=6Vi$g5gB%a8 zUbkDhm(E?o#o{;Bwy<I<%%7IZLd+osHdzmnT8~FWR|xh>(_JsFG^bR-!5k*oJWp zZ}N2VRa(tf#lfUW0lV;!I19Wa-y>knw7(KkMn)*J5*2f}+j)d6vuXr@etMc4mrT!! zB=*7#)!Vg{9;w~#`LfUUGjg|ybd&>Mf0TB}$;!&Q?mzc<$g(KB&(bJfzWbGcZNB!P z((T073y-HP*0ZZ&;R(!Dp+&-(xwi5z^%Yi1FwV83MXrD1-0 z&V+>6Shc2E{3d?n!feq9&P5PbbgMfCUe=Ng64zWbVZ(Fk-U{MwI6fDon->{7vYmn- zIq^1b;fHFrLDSbDDF(~5wKCo2@;KZVVvl3|$I^si{j>!A8U@^90BVjVDqkzTJfZl^ z|5^VJlWzh zSKq~eaj|H?z2&d6seXl@uDxZ?9alFw@=jjotu6PDOOmW;tB;zyzdWzr;QrC2q;pY( zS8=VOP)0sL>0E1TQh54VQL#@`gKNnXX(w|@bXbb(;dtiUk2>9L!ugng^y26CfvkHt z^{LJN3VlNjF{nRYyVRZu<5AwcA@O6nH}4o})z;7XvaHAr$9|&Pi=}z@d&6JsX~p6U zFje#>yX3v%<-!MD_wNm<2f-*_4tX=96(oWTPZDMCdXIUJSSHOJgb%8{i^p@T;i9D4 z+6g{-J*8(NV;K%+ucZw?EWJi!fw8c2-uz(9LPb%sO_j_^``zK=v{^Bux9%6UlaX}Hz{^KXSIc69e_1K^ckF_2H(%u;;PSb4U>LEV?dc|JR>qi279&d9g= zgo6BCNvEY-BAO1TJYCk)qMDgLlZC7PkVh!4&-Ovo(k%e{uVU3JuRmxQJwDu(s=fyG z6%0LKk${deH1;?wS$s4ZWmW@AT+`X6gLor;SR@ zlJnDbx;r%{Wi4kEUG35+m^-f6`5HzTGU%u+NX!YNk}aWd2GqORa#`=mQD$Ga3IA7Iu{!XC^ zp%ouF>#I}853reE-hQ$PdzN08eIH%?#~T1gnqi^!ZyJ6Y%ZvbB8R7nvi||vz{rfRTA6WOOlJ=Kfve-Q!i3Hs~(+vj+AKDQAYq0u31fx*z{_%v5G2OYASNu zQC07?Gu+fR_>e>PbB^*bx63;6TLN)*fLjQFGjuG+P8Is zRV%4SO0~uy-};WE9VOJf2(~6cUHQ;JqE}CjdpPS3c?W9VD=s69u4?KWRjEFP=uA(; zs$|Jdms8Fws!A(c(=+6X1f>Fd9xAbaCL>2Dp=8mWwZqZe%%Va|H01=%tv=(NAr7^S zMkDs7B{&);zcFuqX3t$C(nE6XdaPYMPLgK8y|0{^k0xY)6tJ_Q!gjefvBSJ*h3~X1PpX z4&Fq7I*?$VTye9D!3(>t4DvW zmqa*>-M_&7{Lh}3LdHtl_j+P8L*0sGC4v%CC3|_rGUlobGj`;9T`VwK#rrxzajGB7 zkGXF-6_#GpPRQJ@3+Cz>`k>3N-7XKf#rcHnm!qfHCj=rM7AJ%_AA4QNrlN}fX+bNt z|LldE=-VWLq}O?^xiPs3N@1?MK)DiE4ys8+494q$@j=MZUG?=RKv#WY>gU^!>8y<; z3t~C7Gs*7O>I`2CVc=Q{_wvRqEuT%l^uj5aKYxnU!@hQ>uD~HSLf7!&%zJ%myCP27 zke83;a8F^CbU0COtAq;+p1d`eU$D_i zUFJcT)Dcz^m$|Q8Lhf}tX{5c!F4OMK!<;33^15fVDeAs8vi?I6@#*dZ7};4Gl;iE< zg1GqIq+b4m*&+=$!jch(+lSfN=;6HHp(tD1v1|?J0p1%X6Wr2uo=4R+9 z9HIuOp1U45(Ou!%9_qSCIb7#Cs^X;R?Bik6wV9Jm8Iwy-<#6vNru7vvAH&BA@YazW zr{G+TC>*Y>y7dalM9DP~?#N6KI^BcNmA6^R__eY~(neF4^z!KEC&sRTO)8Lb_av&Z<>KYJYLan#uM3%egC0_jT?XO$J+eGInGD z`G2NK9V$K`5qM%;(J6bAnm+g>a|>7dK`oFgBCih!02Rpz1X+01fe`>~)C2(0A<}7u zu(coNnhNde89FIRz!gALXXJJ=a5f(f3ywVsyf+S0cz#almmfw)0OJp&(3ojHgcU&x zubc@g$&hZ7nS*(W);jhpa_=eVg`}L#^#SRL5srHvVLRlHE2R&Ds7QV=NYeZi|M zCU3IyC^R`13)BMx;i7 zwCpeEU_z+yb_sBq54GrS~7!DrZ+sBjNd zFeD9P4w9*{nG+7Pt^n*6eBE&xtXnoO$x3#U?iq>gE9d6NAJ8PH3TVXZ z62*#dTvrNf<{)k&co(GxOy_zpuMF)93?w1VdgsCXG)P?Y#V_&1-$$&p!s94eqPG)! z(^+pp8C*Fl3>@RRG~qMix>j712TNb%jn=nLn;Ph_e}60R0K|!LF`cyK4rf7ssjO>o z)F4VH!z?8r_XOEY`tt=Yl4D|j?%$Z|G*gQKiUkU%#n2-M^Pd@PA>;#Rm%O>A+*o3d zdi{MWCN&CWtp~hFW0?t%aNc)C3Pcntm&zc^ag%2;HnvOj9I3!4{f(x?=NPs5W^94s zE9`rFERDGb^TlN$zu!e9s_!`~@ChA4zHV1!$s5H*h7yZ!HHvTUD)3FdkXwq5HB^`o zkXgxW`RzU^RDqkge}m)hwzWu4UZ%vHQC1x7a%p>xw(H ziw?j1?qPJ7ay}N>^-Zo%1h<(aUl|$t5S_qW0Ybxi7HRHw%Gt}eXp_TPNJx+p%)!Lob;XDteZG|)U94X1n z#^!FYnpeW`+gEBGZifp&!5wIyIs5Idhu6bhImqGTQMV5{k{5;D^{}%k8hE%*Y2#6v z`HPDh3T(}-*L8FPYK!itdd1%-JXXH=UL0y}mM1ew$6gLI&(r1V04rNLw0j64Kbts| z1W1@H+ya)3@(h-LS7eLO3y+*tvHBO)3oL;$bvcb9l+A^_PF&~V-HgPE6%^`LJjQUX zalz63KbOKgc56Ws{_*Q{oJ9HGt(8iq{H22Ud->Suh30+&(gJdM1QA0Lsh`nKY8xISc~H( z!|OzODms5PPFB&@nXpXw(2(HRi#HhsdmcJ8JiHjNgP31S(&AI}uRGK>OrDGKk8OKpBI;%SA(9){-}DM?I5d{z=N7vjb)s z5cALL{coUP>ns6c0*W={Ob`+IOo(0OB9}BD+L5IN*iKhWJr2=1?c;E^OlR`f`d$hp zucn5%V*S^SlwdRMBr~?JQXqU7qH>eiihi@uN5B^_9dMau0YTEh>h_-;ZqF1E)#&dh z)H7^&98 zSaG8TB}*~vP`((?)Q^WAl)49U`3XJsFpO8{(P~>^&Xe58Bpy`nFt^Ku?F^_`X@?ZY z53A0Shd?ve1M(~WjKa5J=b%6M8_@eUStw*2>e@m~1dXA0WcN9^BfO&@9 zO9EdTs(zm>0%dK=8|6q8-uJ1W`;1K(5gWyj(1FLrLZgSKAXL zU4a@OZcxDaEXq`Kd=+T?@9*M$Mz!LCeHq9~2ybOBEC(@Q-D%4FnXTy*5}PgYljnB4 zoM1`-NmD8*h`gvjY2ToAJF5H;2%!MM*B`9^0&&e~dG{ER2>KK7=qlTq72$XhMEN%u zrzCh3f(JvqFDg&@b@MfU_fkS-te8D*p|I{=O_ky3Yo!$;1r%(K^j|C~Z{j?S6uL)5eoJcNSgwf5R(g-ahc6e- zfvtn0j5}V{#dVqS#qiT+d?TrJp;qd4#*+mtT<>~1qcdKNMhw&P&JOZ?&iyZn1wSSo zt(rGrUnauG!y+S+9d@^71{U*ou*>5s{vPvvBE|TN5kNzbpg_n)Sr3bXJp-Wl*@4^I z?M8@Z7#;csq%i#KD3-0tzqIK|!oH#o%iPv^n5<7`%aT7nT*|qtH#0$7ZuhsQ{kofj zf53-Tu>ykdIWE4&d~(Jn^E!`1I! zI@5BggglMlp*C?^`))Qf9MDs;&3q}%=S>1e))-2vC3jnM;ojj@7;1pM+3k1io7}(~ zf)O2qVq%u)ydHB-l!+Y2q8O$P9C-n#`f#b%HLRC7g!T<3ds5Y#wp$X}PwOv0`~_}m zy)PSH*LyMY9A9f@SEnA^+!obW?LHXj{J=EOKl%;lir_574cU^MXh^mGUV2%rB}KY! z&np}-q~v`pc1lm$Ec9J*wn|x+x8`L8yOydHp|(R*eZ?<^qo|$NdXuS=26xHBx7~GA z^TnS|;iNK0ix*G4HLU~%t`4?%a&<^`uJRB0iLzJrJN?)D$5Ke^KCw5kr`p=EN%(ZX zSxwgw=s_x3;Ov1`8)LRfX%2dyFKng07&Wh&d0-fXPHZ@4QQ^EhsmOji{*i%o8x`o# zU>AzwJo5HPxYDWE-&S;VzC#yD{PzPj*f#{^j3J#eyF0G0z4d7$wL? zoaY00ryO@fJ6gG(rRLCIb|1vha5UbKd+MNVTX}P9Gq6=UG8_`__jq9vWFw_UY0>Xy zv7iu*Lj5KO|B0#c6fua&7tf#PULs-YaMGx_`60zOF@;%nBw=KiG@=}=LtYTd9}Mwl z+wS!YwXDfrNeb-a-inYa<_j_Y1aenOemX5EJkpV`v{9yds(CdY#6&+p9 z6{ZC6^?}jFL)7@v2>u zyrCR8G4Q)narX=O=>xF)q^JvuQ_Pb;smksY8)c!>_Fb~jiA~5>*^_F-O_oia9O3iP z5!kKfM!lw42;K9^2m2PBUz5*`?sbWGwk);KCsCzGz93emafcd^rSa}bFun&Py@NZ} zqcnTytXK*)uI0&}6T%*wTdqFf)-xBR&$VMuc`{z~@rL>O`^1tg?UPn9IxcNyt_(u_ zHg-E!FO4Bhx;}%7bdS99M5hIM-abBdm`lf%t1M&d&z1Ruj5S)1a&5f_gs0jApC8v5 ziLpVkZ-a;jKVYYP`gzSTrALP>;aXWSXrFI^U9}hHe}r33K#W5Ob}LTlInlrWFZF4>TczD|| zw=5_@-@Kt~s!iJAJ+Q5xY^cEH6J*OS=Q)U3jZarE=St`^vs63|M?68;kNVbUNJrhF zXS4^sC0fwXCv%*~_Ms@S@-7?5F;iJ0g-xlIAdG+zQ_r zJc46u{dAQscu*w6S}%t70>^&16O(yBeaeAnYex%vCxG-qWOfv2&8cNmsMYT^R$6Y3 zF*V$V*VjyY&XFHyr<+|1`;Dz4cYLn(!yD@JM{tfR?XGyMhHZe22Wvw;^9X!?yNUHX zb>klHpnuPxu{U-4I5~k7f`(o~F zc_$eRmbjzuA1swk$mnpgvvbIgJ!>H*;*Wr~V^^(8K&se#%jdkh9Vc49Xd)*YB>eVG z{2D`AwcTv|a5P|ASbh_rw?LSX1(OuWw2$`YBMRLw{FgOoZJ;`Z3k{zI0RH~87`Fgu zz;5lXjr5g}5O)(9f(-!=icAOs%q+iv{IiX zSf~JYR%~b95vAhlnac1lC4i6>-fPCbcw*$vertrRINhv7md@#kpT6#rO@1sIlGd>w zCC#Honfc^~>m4CVQJWrqqrT1SUE`3+#osb!U7=At5@`=hooS_TnpD__v%38G8Bm3# zgAy+D*wh#NAOizJRzX#60sZo!vgwN_v;$8Gt84f5zT+FvqaiP_!gm|leD2}c=aJYt zFFT=H0gUXxF?!kLseDn7p~+LKH#-Mxy%Q4O1eVvf_Erg?4`q62;M5Z~L@HGC%X}wO z)fQMyi+9pVEQa_0Hg)-w4iOdt`FuBM-!NMHbM&l5qqlm+z*S0cBbO#C1uTRxfvndI zE;a*O766;Ce*@nE0QIXGI%fp`=jAp+cY#bY-n9u_mpVT6y7%AG>bUX%PouEcX(LE) zU?hjP!K>WJx?}$90z9QOUs}s4Z(}U=p=wU z6if#qc>%)+_KB_xahhSkia=N(MqBU())xE-1nC!rvMR-hTTLQMw2x!Ha2dZKOeH%= zQEBAy$b(bY_Uyzkc`GDt>WrnX-vh@0{%#W*cCx>}seOtQq7<`b4Ysjv>)l6#eq8Q3 zE<7w530M;ZFhKc4z0ZP&&c>S8KlIn(#uVOrvQ-iee%I9dlwcGPOPF5UjbD+ENI?uw zh>w`tg}@E|UUpptcIo9iP8{4ADc=`LVd#vA1!fziFw}}K2Fr=wytBkIcB2CPhzI+7 z&pS7Sg!nVWqB4_uFcy0!k;MWR_od)fPhE1Jlq$5C+QdBwV6YA{dQ?&TM$<(!*TS36 zA0!GHo>y^uscHpmkg@LM3v)rQlO!h$L2Q8YJKOz1cBZ+GZw?3R+@*AT_+apwX}W8v z=#?JP7xg|6$`Bj!CdUFY3^-;QS1EMbi6=oFVpEw$yItNnsV4e6QF6&BOFyH&WYi^3 zv0A{R24qN@;Jzxo$$QF1-}5gzfn{&~XaM7|;P1h27L(LfzA&T_T<%JRWD>vJqw7n; zz!iEO^Y+1+$oa1YXbdx~VB}Ax?Q3*eL|tw@Wj!bL=P8$K#P~VMVa!&O=biO6@2G<5 zf%LT2+r#c&p{jx4*M(Db1?T``447)b5re(|@JiFQl(jHLvnSwMlPlH^x|B`}(Sv%q zwb>k9vz_4)IT}n!FQjR!Aw{k@wGBCtE0QmiGw39!m8thRhdE#U()IyLq_aPqfwm{U ztvJ{cU4r-MaI%2Pdn?%FIvfu%+l4M1wgE3=#PW&xoK-!<1j<&Abw_vK__e{O^Vu$T z*=0DT+sxEFM;%IV^97SqczOCf6y-;SO1!4r^ zfdC^#JvkOXyYW*J3_6D&Glo)vb?1J80}YsN?`sQ78i2hAcQT~g47(`L_tOE2kuX(` zP|iWRIthNVyGPNfUK+8#Bvrq(G@f%LS7$z>XiJLe&o{&>O0=^0bMn)v{LM?#;6V2} z$s{~zI&>9&0e9;*;c;2Vk?*~JEbNf^Q?YOyl)~|ki<|l=Yi8%`z^eAHON3=Zq7moH zpv|xKbN#&Jf3fGE)i0GT6E+~PKgu9}v@6=Ohg#;RP$}aZ4R z_|%DUIAQ>6LqP$%8`wFVK%KUmEo?>j<#M)asn!brXY@u=Nzwop^Kpwxi3s-{`forl zXnAfN%H$5n^l(cqtCo}w(}Sr2#;1VWmIw7veO%+QLbc(n>(&{>mfT?gE~H0+SNy6e zgTeTADFL!O_}!o)TP5+9ki!7fV{48FIv=JNaU6HRpeZB~=F z`AOJI016w1`AJ?#WZ+u+oA4UjI))+}+*WE7LZ|~WY21l(G^Xii%dRlf^tG=!G*=xu zYur}yHPVvynEcQiIVDMJ>@=>mAC3@g_FcYu_;m5R0hS0cg+z4MT!rn`X0@o4#B>6D znM!@=1PLUrg(OhU7a88#PtGQRJ+raib-*pKe@6M^6@(>p#itdI(!JsGqa)ecO;VFp zjs3XW-C5f97dd`fCZC{z&txvf9}?m}8f~>w!C}Wso?N9z8BwY)RyN@TgM}sb%~SKgYw`31FFtdeY3ED}dWO=&BAA?6O;;GVc!Xho8zd z77{tcyMwrPxc6&Tn+>QwDs0`kYXom%sd$y$&4o4>MG~S|=2vlly!rwT(GUJ|$$(Za zvopQd{8N7Lm4@So`Ozw_&+V-ly%H8Kk^^9&*=c!Kmam)VHg2yvArrWt0v41XV3I-n zH=CVizDx>JE?;V>TeXSHVj6W&rW#H2EzyW9s(R@zFgb{u#TiT*oHpGJh+YdQ8lKOT^SP(=ME4CLwLk4lU#% zs6o6iBb<7W197#nG)!uKLH6C0c;@(q9t=mbw6o?P>kq>Kn2kD0xM=3rQp>7RcjSCX zRh^qFyJiY06!hsrcyuxe+z`rlxFWPeseYMAPm9AQQMG6=!j7MNrK&-oj^s*rVZUUn zJ8zk~)yvzwC!FTev#-#sX3>Yw6xhL~gBgk`;T}N{Al8pv5iLnWd~;QYGx|;=Sv!%4$PFU9^nO zi`)=I!JDWSL9?%w#!>5Eo5DqQmzvWg_LoVGEKbuG{d2;vDHI4~6zW5pu!6up`Mury*>r(Xd*Rn$p+aF?1ATJMLNXLFjWb7%27`DFO1>|#b>|6B!-pmds z#6PW`G{W+3t?%jKt0RdmGSJ)wE?fP)>OVVVbl9JoMyOR6JHP+*psYqg@!uG94CxV= zumpK;Q7qOE7_s}BJsnPGsAZL{t~Rll3h^HVrn+2$ga+CVe*bA0@#gXROrz6AcPHk`i1un<$G< zdR>lr`MuOwknW(Cv+UmvOz=)loGaxExtbS@k^E41LIy}uJkE8Au5R&N-9rzy;hAZ$ zydqq`d)?V*b5H1$UifpQHZPxMU@fv!%22jY>ZveYT;yd5qXJAf&HqkjKXj{0snEvg z=W8!R^(oHtpr9N=p_NASJ|F#H5tYPmM(w=yBIo25F6OD)#Q6=Wb>(n}r2X#J?@(tn zWSQM#Zw%$G0-ZxE5ySf7Qo8r$nBGs7+^{yExNYa&`_D|CfYd08^cVrR2c1yVHH>DD zu}68Wj-?EPRoVxtmjSuEO`^~OhnOl`N3!;Wj)Fjgu)mNf0R7KD^k~!E-)jLaVE||3 z1+{B>#a|6=8@9Tz5=fxbZ2!9fO4=Mny^xa5?Egp7jT`(;U&YO;KfyMn4e1XgGLb?th`X>k` zsVxH&DPzK7QNh@Cl>>$NF9crUCBx610F4=eI_nOiuKUWW*x9<-av4wEyiVJn+B!as z3QA-BPj<{rK=LxvOa8yB1X})xlNMwIu#U1`dDAZ9Dn`uXKwDAF^~Ou#@Szil{ms(j zOZ6tuLYPK(Kf{53-fqGZ%+y!A1(p61Z`M@uSx&v=UZXvV%}O_biWFgn@x%%N1sPY% z=sTCnpYCZ^c@(07Ghdl%&?4k*x85hNP_pGEqMuO6|*#nzrxwlW>af%c^aCI3h!B zW<98;-(@=T+a7^FQE2W++da+)I`=mcF_(6;u6>o{g}1s!523rnEtmNqoMxgP*vvj5sEP^)O}rRQ#} zk?M=W?KgMCpvNt0vEgjmFoYHGm5=w4kWCantoP(){|RkU2riqXQPd^W)df(cJ#Ur> z(EBMGf4xvYWnd@lH}HdF-0fk8#{NhC_muxdF4xp#YS2Skn_5^6rc48`q|~gu;a-9! zAvpU9bqfFj5d&#Br;N22T{U9D1Bvj{jtxKH-2YVrNXg5l0M&CG+KOB`X(6Iix`LY% zxP+)P@@~ z=AXXG(Y}2o=PxHeF(mz#5_@D!HQz7;A$%bEKLlJ4?QTIV1qRl`$^8Po2^xedX6zjw z(jL35RiKOZvl}|V}HCGb4i7BENB$<8WGN5axsTh1;Xu!rY@Yo6Er_& zQ&I$d5Cmj*G=9{+ODVc#3p#nIL6lCmHHJxKV@he_n{~uoE7Z4O%z;M2>^zOlG871^ zv5WmoBQqY5`*WPO&F46pMDG0mDF8jOFH5Ed!Mj9-D{Z^=SQHp{P_<5(85qmFATOsl z2xx|Uv zJEQaXxp&)2Tj^R@)h&{q@;iJw0@w^kBYOY@Z(k{m_mZxYpNDsBP#M8affBL*m$Yn) z#D8l6+l7c0AYJ|cT?-&J$9^|B>xXpy_BS@>?_h9S{T>Wuo40G|AMgv2mHtKPYX4@0 zaF#NdfCyh;Wm9FMOA6}vpr`x2P`ZxsQ4?~E!6X|}MKlcut*(%vKq@G(pmzV;UC{c% ziv@jS-nezHg)S=Q|Kkk%tGxb)Q6~>s{6`Eh(gvID2-gL*g*vs5rG?QeLqG(G7`YvR zX1oJZHc6o7k&T7F6bXlny%lkmyV}~3o z;2l;wd3m%d3Z(O@;kN2-o=eRkRh{!2oR%L=&%sgZMCE)bYBRfY5BN^dHUG6E+;?sx z3}~geo~GcRwbQuD2dVv?z}?42Ue2At)SD8vjR;&I1}r-6J9S>jC@mZ`+pCE+G#{Y& ziY^|H30K>c(&Aq0GYTK{^y2`Fb}-Nm&}hB7yf%6WrTj6UoEdyh|0mKvI-6A_ey=Ye zi`*J=gdb-$Y=b68*`S2Qg9W!*%M=Uoi@h$@YrG`(yVpgDauFLO04I?MKz_-UixcVe z1LWq1v722xFNuGU$t#_$pSi-K^sxhPHjv_0thNvYp4jA>4VdvxVy3N9$Hw{7m!lX+ zuvomm>SZPH>j0R8-pP)1g)!rh;cI;C#n9I!1hym4HJjla1v5nXQ!BBxhsXV8bn^|< z+|0_GiUFA)K@-3R179{#q_qkysbeE?U!db`GKwiOR&3dR`*=kO7faE%+c@ z>|XMKj)fTAJO~+MU>U3jsJqLdDlZTQm02z0qirXXA>e{zo-ajP8Cc4_L@)e_lydA)3(HVU&& zG?Md3_|!n^|GyLa_oQt8i`dWg`F~IBAF}>miT%pg0{%bO`y?|6kB+9eVa}6+7zRo+ zyJ>fyQ41cr`;uvI`ulh;xAL`o|9oz_RSpo^jmP5qN6mpnE-{VAj_~Eeu$Qo5NoI$+?mo%vzg{H=zNpi0+{zrXT zBvKzhQGv%%sDojr(MJh!XBF<$T&7{K`{7IO+AB~sX>S;6$T-q*HKB8tnqQlrdTdZ& z&1F>P7k~DwFu*ae4_7Y2IqAQ#Qj0u_;MtE_2pE5|vU_M+Jk^#2{}xve=3aUAq$T^( zi4lQ=E0RW)3Bd@(L*C;sx4ifkBv%}U?SR2F@yZ}3Kw4G*#KmEY6D0=_Yc5zN zIhsZWr}0uj!`Rmc>feY!;=|KsY_HNy(D)|gL_BcgO9Pk)j`mc6y?xe^i8Zm&kV|q? zP|Mg%;Stfk+^$?NA_8+7H=OoQ8^Ed&=B6lH*|KRdk(I=y(3;j zf3nQao!v^ka=eYYX;*G%@*d3oN13}(oF?~e9{x^lNJA=`@rJbILlGc{!XXbXQNq~y zO#l>v1Z|35YUPv4fi80J`~d6tZhQV4YZOZw^J!DEI2$&QyHrT~E`aw59@7#8edk)r z4G|mIdZYO~`LI1zmNvISgS?;&8(eKic-;Cx6Pw2++AN!;o%rm~71A*Qmz4gIJeRVT z-1pV*jTF{_ESNmWAo>@8rIzi+AYH2WZQhro9UACHTN>GwQRq|;4Y$mvC4QTxA2wNS zim9rB7-qGqah{O8um@(UERqd7@=!%_(f`%rjS2OuqwDZ*QoR)S0f_~j_r$Vd4FSW$ zBWYOD3HZSjN?nYU;^Q7=DbA&cZ%Ye%l&Y8YE~+q7Ip6%!QgB&~z$%v*KkDBE53hh| z3|;Hd0-7TIr8{eW%dNRU6RkNu^S@4y^d*2p{+J_4RM#7={ZKiQaxApj%)Ko;W(TnA zAKE?Ka2%mw5MRR9c=N>xA-VT5d+PIbYEPhnVONhRr7>i0(|!->V23yl%_x@@Vdo%E zYN>gvUA*(X%rc628F!~a;veq)-tW9g)@?+>loqTj! z;v~5&6|Mir$v+f8Nc*~hdC~)lg~BBen*TA851A=D!7$)iLQHcBK!8wkpy_khN*V+{ zJFo5zizZ)hZ$8mMo&3%76wGi7qJP3p1Kw82SwUEF>Q@z(8P56Xtx+uy#{yd}Fj?iD zD?7Y~Z%VqCN1Z0pV*4An^_2xb#EIAw=zn*DHP4M8w}_r$M}T+c_K{I|P%A~dJK^y5e7!Vmrp z*hol^{I`xsOGL-T#>=SReY04&Z+7sK9kCjITS2S~29C<%37uQ-pDhkqHA6!b+`p~N zs5^0G@T_@BoFjKo9AYcon21aeC~sdN;0E$Fm3E}-MM z-dQW1)#1D}oA?|JhuyFmo+glxUpTd72UOO?1c@i1iSB&HnhJFKn1a1U8hdllp#qHT zT^FS~Eo*+RraO180~o(@4yIHp`sj($iwF0{(u{|b9l=(^qjLPHbx(!x;%V7WNxMQ~ z7|Ndqy5lg9i@m|Tv?HaV`*?VA(D);wRA$DQe%0<(cmxVfc&lqkx#{Lc%-Iq< z(cHxh`_L<%5!ihNPt1(Khn-Sp6kB-`$|O= zDhi1t5*Z~$g%FC$$S7G&(h!v-BMBvYM)t@`8fI2fgi1tZWXnp(-uLT`&a>+r*Y9`V z_g~lJ>O9YUeLtVi`*R$x6bJA4>(+bz`3LAxYm2vum=2++-LvU&C+6lA6;ucjJ)(K z({G|F@ZYfZ@XFF0*5x`l74K!P)f}W_+q>InWooIBZL z%Yvz%Z5gOfoYzB?FJ6Kx2y8MOkQ(Bgvr@D(jvs^4TJGm_0TqlIj%{(6NAdnSpLI@1 ze$l>-z)mbpM^Yc{1sBsi3Ni!SdQELM;R1eCXCCzuyL+_}?HU+W!WF&GQfSYC&Y^KgA{rzEce|X~PNAq? z2%h@`G&B`rvMdVi((utl^_6o}G$mI!`us4-dQqv7@HN&BN+?C=bgoO^4R#4vwIm`^_`k(0doVC;Gg{vg`?I<+p`+R zHdFIekkckwD)#jmi78_eJa~;fWcf*sneY2!0+qH(zle5d{>uaDI@Wf>Y3SebUD^Xi z0K|*q4S0NU1<674jPLes{{8?CQd|+p<}aSuD?}Y{nUE2Gzd(r|DH8ioGQ(Z|ZihZF zT!shEOD2Rp9iC>RFgQ>|k!5>zR`ImMdE&V#i*o39RXA!_COdIHzH2u`TmY3b$JB@_ ziwv&Nta)6d`>*ctT6iKNQo;j5-~IUUU8XTaf#2dwmGao$cYD3NuiN4b@f0pru2mZ> zMi3F!z$`lCcV9#gPv3^ZlI6l6U`@A>w;N16K=$Iln8??NJNZqjm8=mON~nAyfi;Xd7vxa9ACe!qNdv)7;U>s>3!wiEJ{uLY%D?1Q8} z{45oI<4)xbC;U38q@iAgM5mCUL;rCp^pcyB*=?DM@pI-h^my-hbtqO71D$p&D<)h% z8Ezym(zf_lKsZjMs>11tez1HXObP$5^LmN*)9VrJt3vMJ5tZc-CYF{SW%2vo zclY^-y{QsvqxWfAz2U462M4`MXL!scFD&v)*cIA0`Y#vy!`0o*BgcR6(4ZX)UcU_ge7-V^)9bye;C(y!uWT{NB)c< zWGupN(r(IuOiaQ+yh#CmM@WASbGXGgnu?;?>vpF2!65l#eAvsmlCY$Z$(VWY#MkABE~NmqE?{7J zfRuVxQie0lj+R)XR>R9d;WDlY;Zb<02=@ilnrZsr-ls%mt7e_=-T5_b8mv#rcPGaz zdBk=U%q<|q0K;!a4a6>?^dyxTyr>$~l3=n8N6S7ByM2m(QZ zgQA~)1#feek=8^LC2KqFwAZgu>GY5$@~C%HT@b2zDbeuFzu;x&rlDkmeUtQ4=U3p? znAl{!Qz##At44p?&zhQ%U|-@JlH~W{Z7<{JBn(Vc4Jw6G%h^;o|fHu2(^`vB2+}e-k|4uRl~sB zz3bx^$gFu)E0~%_931ZN=@U?~+2s@d$-dmivdmdz%8e`e1K+A0 z&8LR-dnoI+c^%!n$MvJSt>}?5W5aBf0g4^PmBm6TV{bk2zUI&t`Cu9u%#ko63%nm5 zzz>`XuwFzqFJUs?)kK|24#@&Tvl6@+5JMnM6Rv<&YT?D?8O)*I*ED(xak(TfKNESN z=%AC4)G`Suh1gmk;q}seYI1{`Dgr$oAe3$C$#X#2_5IQ}{`Vl*PG^+ba~1w_A6t|c znRxSyUuW~AF%;OG!-IPQ(emM*+Ey)=i@Er|kVlNNoo~URf({}K7prpKN~hW!3qH#M z=il7X$_5WQF9|n{HFqw2l4w4YmCih8`=_KD|JQiqSW>f07rA$>^caQa{aDN%Z)v_#HrjCd} z1d~u>3Vnx?c)QC-%ZbX9a&f_v((ddkiJzg4gIB_c6Ax> z4I2>j4qkJ8-3$Bobf~rbaJR4F8^B!~<-bQ~*rtpiOYr;=BG|AEzhtRBr{g%|AdDr@ zQG5DJ>Ucvc@bxzM+Ka}VY4hw;Ztn&P_-o%ndP5C3}Rq3a!!QUnT%o6DfY`tndEp5f(1 zDm5&1JMg4GK0bEb=2S5{UJsshD8z-2-){KI67Jv^GK2}`7rv|-mGoymeVdxcn}A)B*z5m8dH+dqCjl8RPDKO-rx2PB1OJ&)i#J=X`5R6*J6Sq9>=o0Bw+H8Kjy{ zU5wsA@|0T55k;KM2>Xh>yd8SdX4f|PVVY&~y(;A&=hWi8D=A3$>dejSTR681#$BJ@ zg(EWd(aLC;tcjDP%4s#HWpmg{yWZyTS62^({0z8FuPHI%D#BK7y1=*0kKfgwt&C6q zN)jI`i$@{K+BLxm798b9LwzQ;`hex66q6#=>2GhB$gDZ4ezxT`qQ`!N5#gaPWM z_rb0DXK#MJk=^8N=lt{#p;N(8IFi$>`INfor%h81Uc$tTZnMv7Wh3owvvfBqR(E-fOfktugYj=Om$L-nf<9;QVaZz zU}}yk^jJyC-E(DXn8LpXMq~IM?o1vpK98H|XZ^Y=0D4Z1?58&qS={ zi*OA=^57hCL)?|P0b+A%ooH^Ezkj_w<*Vq|y8cD^Tix_jyi2^Q9Qi*x%J}>g+3{W_ zydYAA$SL<`bvBCKM_g%1xKJ0?2h%qpZO!M9Lj}vUXtfO{LIisL?S3$HhxGnY0o5?b zzYW_pHV9u2u}B?-Iogx$DvuWf`ZK02hU@c=enP+Re3bHBow7wHRV@j=aHy-FVNWe0 zH942ab$+lvZo>dTp!j;Lh#xLE^yB z?M2*?9KjB5<~GRWeMy(IdQgtr7g(F`kum5f=VzIG4*QVn@r7E3nR*i7c$6#+eY?igIv^lCweea`HR)<%HmDKLe{#Y?*rO{A zIrk<4SG5V!rkChea9B?C2MN4dRtRzSil}8Dk`+AI)u$DH5Twpf8~gqBs;#@v85-L# zN-z`~`zjTc8d+a}&NEqqFjsA6<;I_xYN2aa)dLt(p#Ac4Jlh6-xg8fidWU+I{@ngv zrEGL-xSw zm2Rca+PeJUs)_-Jc&+Aniq?(3kpm0;LjxZ|pG(n?ELqCqWB%>j-ng8XPMI)~sk&{> zSyo^murqX1JB$C?8|Uxg;C$)ro}ZZHOEzf%e^#N! z%G~M6rzUT!FFZYda_6BzidSZFqX43*-_*FUmRdb1JYuE0j4pnK-CTh)8zto1!;{VI z@(h^W2c);)yl|Roqef!jgjs|5j8JLNcRTNcYp31MIV`F79rX7R5XR>qUacv>i_le7 z8J4r)-`H&a*y0r!Wr^hPc463nzi@h&h}xAq_{)Up8vR_K)bbS)71NPnr91PI9q0bE z6VGa!n=c%zSKeY54`=eeIa_dkqQniov<4d;c8EjEY`Dx=O-3D*=HR9cybVe|el zy0;HH=M6{m3rjFar)-Z5_bU;o{4~b51nqC^lmn{6)s{_L&&n=h!dDe&;H#9v6`vc( zyWlL_X4UE=mJOpP*ZMT?e>_2Jzl^Wf`zVH3m{u==10)v*cC&|sa?AHPvpHhQ)U*sr zbpD-pU~H4ckO~-Q__u~eX>LJf!1IIVavlw=j;c?AtVNdu6cWV^+~p`S+fKy}8n`T- z(K)4ObM>;0Xw&C?m5Mvts8k&np~us4-4?N(v-2T zIuusz$!;sEr_x{Q(Z>>*nB-MQTSC8Q=b>T;I&m5zj#$1WLK-(GvicNs7w zK+`_59&oH%NL>-H2oX`SjQ~p2mrF*Wd*35Uj${U8!QF_264*FqhbUqIzkXSw+Lgx~ zsxoNsySLU(J?Yk5ycLIGlt0fB_3JB;yTrSlBez%eo!r!p6rDc_9YUXH*c=;r_E4Po zZmQ`+Xme+_&{yWFOje$hRSq%->K3dj!cuO%Yew_o)0a(5r(EU{Y=)FRHY@Ng-x_Nw zUn=G|KShV3@U?oZ`JO?o=7j>&Y_X=dK8bBm>3*p3NKae4gs81hHCSUi`(DQd>(pjcXv6@uJ zn!)4!N@$dhe0f`U{)kU_1y%J+-$1{!(oS*ZA-ot=7MP)}LOW`s`FsY}#SHlctOzn7^pQt#PPOH zSaFWGyHMb$rnaMU%62-%Ocl*G)sjTGbz$9j{NQA-8G1T|x)q+;7A{XTU-|Mpi|Wy) z_vb@ZypJtlzrg(pp|*&WCoIVSMDG3eE}6}2>eSXLV=&5M#5tt9DJ4|CFMlQWW|UH3 zdWrpn1#jMS8ekx3W}` z6rFfB2mE@W8e{MWV)%Fq%T{`~#T&M+Ofx%@?yUIyrZeA$J>9ILxw}#B8u#sWxAok@ znp|fdb!wuqe`ueV1XphfWr|kvFETU9 z!8(9d(Iw#;^aY>cP=M-6WXxI5DnI(-bpeob@n}7j+6a*ZzErzxr%S4O<8+{HjZ!Ug z!~5TAHzTCXyq(r=W$kv$75EfQvE1QpDow|K(=!KzZ6$^l9nVCY>V~Q-x@cW&Yv3%( z!ec&RfMAG2Xd@l+q!1@xO6tw41}dK`c@-m*MY3#5Iwrx!Cg5?XM{--xk&}ZS=e^zo zWWUc%Z<${T0AjJ8lrw^$ORt|;O>HZx>RHh7hvF&rzfe3~7^6)$F&Sr6m~NgU_XP$)DMFNnFQDeM3q7{wJ z5%D^o1o?4NcQrGrZA&CpC;0Af<6Fn+PRipgy$7uZEL`6M79#bfKG%Ac>do`3;jlw{ zBfB+y7oao4H)>+eaaLFgv*%?8FB80ClJn^nL`u2IVH_A$(Mhwy=JouH*2Y=F#DpIE zk0f@A7l*oXo#4zUKZz?3PTI59CTKJ{r@W!qQkS$Efo z*UwLOaFgdAnJva>)#@sY$RMse`=y&eO5Na=#a&EniX@bc2y~q!4xOiyCCsanCvGpF zebBaqGsbYu(jNXr^_=%1h>e@hY>4001RpqSiGQf4jn%H*aX_b`Y5DDXIw5RH>`TE& zZnkRX!V;J*+A~ifu;{Qk;7%m-|9Jk*v1Yx3{lSRs9rPb#eZNVG5hjzMOw+|RSEm_~ ze36G;nKz-&*P%ft^w*jclPp>!V)2qCyHfy$QPLBPwmVqTG?LBpzCA zQ*8_3XUi^5RfJ^RO*tQ%JkDbIq!& z(}R)?=ebgR6}8RR%N6M#U>qP%=R?Dw{P4>6@_tIb{Z4-}A0n%_>0qnaB_^iJZ&b^Q zOWVa{9a!B#CA!PNHOY$7YGnU~Dv_&sNZ>>H>xE0JbcmTQo{a*Penu%JTOnpog!%%} zL>e1W5HTkhX0%E^Ym#Tx(wU_&%Nwk}gaD#M%q^I)QI|^XLe15vFg>**jyLQXyNd#m zRUiXT1!qnimHR>LgqxIn29zm!UhrXT1guAS5Vc)F6}NVKC8b6EggOqI((W;k6wCdkt?)Z$+ zYM!APZJjjHv&p&|$)nu2R9c(-t*B-IaMxhEyv=5ge@JvV+0)PW($(4NIdiLCW{xQA zAIz9XrKnd3^E%1P!3jqXCI{d*j!0WE^|))(7jUI-k0)7%r{+iGa*sJAo&T%ONk!Ll zEQI)p*w%qAng?s%hw3kzEN?8P-F^(rf~vf4hhGjl)mH5)?_ZBfXMuBWQIg#45 zAc!5ZsP?ej@2Y6{$SS(o2kQ;kw21Y9;vfVj%|4+!D&Ebh-^pFq!Tn-=>4L))s& zJ)dn?%#cA{(s20>EvD{oHd->_2+JBi+Ksq>J{h6okOmRbPGGpKO3P_@N^!mHc|(gX zO!;3pcibJ_-r2LwW_MsiAb?@{D+W{=?%edVwL6H`$n$?xM=hIOK8g9!r08^}TWoz( zwe0qkam2DWrh6V&ABof1s4mWpJH5Bijrhi%iOQOPk7!kHodE@6N6@UB0Rqn!BJgmv z_X@GekBTnhs!$28b%wPV=ggvMN#5-BG6#MDA@2NM(WAU(k{dv8PoC!cA0IfgfB!{6 zIGOIt3H=lchPd`0qt9j_mw{{}`Y~_2T1d3D;t0MvBm~}37RK=ku*9sbv^VMrQ2i`8 zeZ=$z04v@74PH4dWp+sb5AAtAFH~I<+aGjn_tNi}Gpd%++>HD9pa}#d(fWs~-{0Lf z-wZ`|NPeRhStUktIFM%^9!V?vSrgfMW7y*}ad=|#H}13V{ET$j7uoWToUl$(Q)B%t zinzX!*Bz)&d=DF0B^ov5%*hecRVU?+xpI7hTpTRo;dqRO8s%@-iN(sTMY-Ph)hEV^ zr^#M}KHF6OESnOfwktYsmmL@h3}F=C$(oqU+GFI(HF3u9jmxEh)Mu)#eA2!j37Qt& zb7=oOAn>aEw_@6&ab-fytd|aBVHesm|QN0k8 z=<84ycT1P+Yd=&q+%*exxTxu46RfF9Gov2LuBRZlW(o=*3eq8CXxNAN~oT?KxYTTjihF7amm)~O! z@mNa(>^;KpXzTRo^Y*%@TXPO>)l}&^s%lPyKplxGz%8FtN^$W+YN-G9FVh~3L2*O! z+yKc(t;P$0K;`nSJRdM5Q(a;| zlSyAIUCn{O>S7V>s~(NeRX(*3iRx@gry%l11WYh6ynsgy*!-4##Hd7waq z7FK$diDxQqTiiYv8+M8*nCx7wA*gX-D{-3;yzyWI-H%n(;xVPh369UR+mVapEV zDNH$guOWR2v9iJ;Ix_}RouqYAwQck8j2x1KnON~R(MR~HF99URq)^9F8k`vi! zS3SA!R5Zydg7Okq%sdY;D>Jh(HoVQkR~+1Q&~j_Tigo7=owJKLKMU4YEuV=wzX=kR z-uM|k0vMZQfek`r0Q`$SpgNAtc;V>4V43@@U>F`5tPfAgwhPNb!?&Qa0mEXvy#p^v ziXLNj-T|Q#-(vxaZPs7gw_1H#W>Cv}sf4L^(KiHfj~yt}TeuN-)#9pgTQ^YNEOxo) zs6R)#?O|xtD{0&2`#RRXoir>`>`Pk4x?wjS!JgMpkhs__tKDh1-(OTIc%mNLsyMj& zjLs72T|S*_oOEp8bTC!wyHfE^9qAF1NeGT>X3OqAr;Z&1e5AP@J_-&MVq$VOTJiQ~ zW1IXrwtrgw;83gBk&Wf1_d_Opto(9K9i2lg_Vft}e@WWR9KJv*V_{O6nN#4&+fNdx8lD*~B>DxCbPSQrO zyR70JbkK4uU!`MX{8asV%u$eSUU>s?H+UR4zF~vT)_WcrKB>l1V3)1UTB=L=3vsA%`NZ( zv@^H0=aFVcUc|HMK6}lQ1;%~1JN21e?l>FGDx2X><;4pZ*&o|gPE~|Lo^33Y3n!^- zkzL!2ta;-#*CN^N@l?ekv*?2TJn$ypoh97b;kH6Bj*TgK}@+@v#qKXcmSA_4imBtyn@ zR&#Xl^~zr~2K&5wdoObEH>!+BY_QMs2&iq!iI}&PGNO3l_}%3$ebO@mYpAeAY)Ah| z*)KLHsst;{GNP-$CkVT!ICkpCPC17!nUhzwV`5vk$U8~dXdQ5)864$3tWx9PJn*8w z=th~O^gm#cmq}N)J$XoJzuE5}mDhm}dwuP%zC4b-5tulmWTv3NL>z^s5dVf~-k9Ad z@2QK^!S4fZqi?nzteNn#FN-!M4@>X9m5w`R#8&+|Q|Z{ITOSkWtg6|&I0@cv*2wze zhIu$~6e0Hu<51DG{yw)n>h;E^^6s|bBMC)rfwp!o$`pTbn4Xom=gLHUw7P1=OIt?N z-|6owdz!X844Z2{G+*5~DJ@sp@5#VbeWa-FR(EWSF0YRDhvKx=3Lp;-olm>VqX@Iv z$?<16uqb-RY9Rr^qk)ZyYsbdtraw97W6gpdGR7_KD595k5rJ?4FTTcLxVrVW>Y0aS zI_1^BlL#i~Y5W(Rbe-428^5_oeVjd8F&+Bim8}u@_7a4~P%Bck;}hX9^>h{~U{Rm^ z9d$gG1=O*sjSNIWVl~1MTduUi5w|#0SmM(n!Y=}TOU|qk7?1Yrf&~;uJ#Y(ctyp&Y zN^%43TbC!Yc&;XCEA`@!H$DOwKwrBT4(VU1>T3@te@ccJ)jsFfC_Cfe#(F??!%1`I zX+7E=Y+v-^>AD$j3rEtMI-}Mr?Z|owW=|_1aoTX|7TQ<@hKWlCdwlt`*_NwR3*mi* z;n0)%Ijifn3Qf#X$sT6>CmxfljWdaxw-$+_J-ExJx5cB5B$NZsl37FY^)m|$1WA;5MkvtUwoXcWx~$S)=}DK*FE$Y45QaloTQ8; z29iTrXYc(IQA;buK`l1zq0?KjfQB}{K6;3Xsk48XQ`zkGxSNZ$Ze&>l9?iZQ`8lNV z$9lEabaON%VQ8ixu~=ztw!5dlw%KKw%3zhzTs7ynydrI}nOS*je9%Yck$8O{N#NnI z@rseG58A2QBvaL;032O*r-7p4pPtgE-o{Jx;d#WK81T&Owp!x7cqH=xXe)Fa6Grd?A@}{U??!`m0*np zi-nLKc)#-Ese$C%_))W0@K92hF;VSU>T+8LY_#7e>DO$FtAcd)N4%1LZzFCS##k?QBywWLmx!^b z9jl?iW8Kb;TDL!qY{eY}noP&X3v8B?zJA#(u65%gG})8Ta}?i5a7Zg)BoytER51U& zAT}3ZPj8bqziY3Bqo|fDR)4GD#T&GFIhN!^{iEp0odKl_5*R0I%bFdHx30hFZf2g< zFw?6aifbGUlyZ2es~H+_&T-4E6u(~k=2v9*0akIY`(j1VNoOV}YmQSb>AAn+!uZ=^}m8ia66S3VgPxOs5&~K4#kJGkp!29|f z*nYFRxKqJo_!IUnaQa$UdzVYn*NGKm{%htd1(O!C3wTf>b1;W0DVp{Y)w@F`@w1ExJ!2H`&9#@ux_+ zyE_%{U|1>#nO9Z|#FGDZ1ukzM(+&#T|E7pVN~i*!>IVIo0X|PXwm9pwrD6DaV(l& zr_bA^^7HxLRD}GKWFgA}*=C1>e!7y8Gp??Gt)BS3{Fs3K`ni2&9|bMHYbDhFgRzw= z^z_!bh1{yzC<@R^TB&f>9h5%P1}B>&CC&TOQRo{-l9p9!YMvaKXX0)y z!~xksp_i0ia~4vo46|+fT|#efrMKI!IaH z6>o^ocHQnXAxM=X6^k{2R#9oe8(TYB^i7eW)x&wvD|>bkZtngQOtvU)em4OxX4D>I zn`v)paHal|jhAqgRT9J_4L}f4a>zF4-idsBd@ls>vaBdCQ%Vd@%Tslfi;=hZ()M;Z zKq98NgZuh)sWrPWOYxsl>6@P+3NH!Z7CdIJsl^RTM?6(URI+*)HingS-;Ie-m=+_1 zCamniV%zZr--05vWX;95%t)o@AOEvdiiik=bf!}K4|A6!|GKRMLRw^bMg2Ezvmvo{ zOLy#)xl_*}g^%oQbp1u{k1rAJQpwd-2=^jjiD?+&$DF6-t{C%QW*IxW$`)eVZp`P1 zWA!PkwJk|)b}2`Xtfmr=>J#v=*;UaO!(KkrPn9UPf;Y2*PmB7Lm9|;~vM_7F)Y^N3 zpIiQ{$q8u;?osYcD5sC@p%cw5k?y89-g#DnqvO1xVuodb*4k8B2O^kmK8&f|j-5Yx zSNx2WKFh>J1=&GrbaaK`{5yV`waP$IGMCp-&SYpC|oXxaAk(x#N(>q@<2EFyH=vk56geHr?$1a z0Ik6ae$^kV&tJ8jSFIVva|sJ>16oy5_Q7@ysltm&6Chv)9`T)aGZ$>6F^PxLa^mjw z7Xo8P|Epir?x|9unS)AU41~bQz^D%=O!8Vn4duzlo*IUIGiu!~Z5w}CWm}b+BORk} z>dhbc(Y_pUt`=lW7h+i1%18>aTpOFCrt=Td*YfdYjIWZJlS_F#j5;obO^_MH-=tCx zZ}003{Ih_`_&jQw(IRQzL-sXlvmQ}qnv0<;ZAvxnVBBeKQ?>ea9!{s57%GLOgkP&D z3GK16Q3_mtmwmGNy}0-xbH$-4#GmD$!vb8)B=G`%co54M9m#B=;*#GTC-j-4_6U^> zJe{j1r~jsio*Zhw1cH!L{YNRHjKa<+^XPi+8$i@u@vxEYkJobtCF)=9B_$%v@mM8E zdoIKMea?=oVXbv6#yj(mQbBDeGydETYYgbi7kq{pm045lq2DrAqtR9E16tk-C8na2 z+LU%ZIp^8lGwIMDbLn`l0AxxNwu*HOczPCVO2nEL7-dHJm2CEFJ|r=;azEyb`^@G0 zGA+mRIii|_o){aR$zby_FQXh@_!5Qh|D=yDm>(~>x|_@uWUrX<b@C=OjKOZh7 zkejA>DvAH9fZ8@MA!zS3oz9W1fxV&<0s~);#>x(o?>5xjPm*KwWiQ3SN`AFN$Gn2^ph5>R169qTNR&s{7ruL z6`L8!b7InrZ+NpefxGi7s%kdN==zTw*natyG@txgtZKpg}M(!Xb4`hk~{BT);qhejWfx zH17QA8g1@e#q(uo<1gQ6do+$*6u(ix(asCRTP~jVS9jW{OenPTDdw1tm*(&;Z?>}+Mt=u5Nx|_x`^_jqDI;50FCx{iHxuZ?A{weIf?C`{czD9Uk zs1?YjImy`AbsX=F7tET5s4(XpEIZO})HVmfl>6-Dw2Rn>IV5!P@@ufpT;woy%4Lm@ z80s^1+t(h$LMl%(W=N#TTGEPSqwmmE=n3qXWG{^r^1V=0$Je!Cqv?nG5gx-f#VZaj z9Q2FKnqU3hN;?0TzYm6S&4&cp6$cMezt%4bKWQT0+%s7uJ(&5SibK15Q_L_t5l-4W z&-yB@(eF63iiW73wpxFvp4Hp%4dH-v*7PW9Ep$z}g<%AYbC+u$Y>?s(Z8ZrhyPKR8 zJ*-gHwtEEABOfHL8#F9_sC>lEGREM|8gzP8d22q5!EeG5^EU6@&9kivz9(GP{6+W_ z(^dJ%A3p^d_D|h2C~@^E6ZLV?=d}hhXAIvv`gHPJrI$QC!qm##eE&{M(oKhpR>x1S z#y}ywwXj7L*}tcgev$0$|DE~?ALwK(J8$Wn^)uiLw%3rn z7UGq2jW0!mN3b&-DtI^rcj(i@NUd_Xff)vgxN}&x}*e1@*Zu8+af6 zPwS|QDQ%748|uZ&*N1L7O>nhy|0>p_G(0oAJ6^qrqOz3#Q0vV>xy7B6n`P{Gueo=i zQtF42mciIMnO|yWqO7*Q!!hBTi-`-6NtWf4;}SjyAY1eJ{5jprB)JYxu723Y-a#eC zLn+_o;<-R+8gD$iP~x3~ljIc14$8r{?ezUxgp)ju*%d263e1yea4ce6M1lFl9u$g4 z#5bZPT$dm9rXxe@FVXt!x75PFioR;a+@?L{MHA^T31%leW*jUXFy?MU7SFS!5Dh4t#@|wckH51JrNl41D9em-@GSBD^wm31ki>OZ?`dMl=`O3g$`^fn_NU^^vR<$yQB|bUASIkU_*PonC4)(sOuQyU@ehV4Gs;TnNfd0B8G!e3DSc%Ue{io{5i~~+5Yo0* zQN^=qm7?sylr|FKDUcF9ojv<$Tg4)^rjrYrK@oHKYdZef#Ge8tOT)him;o_e>xSX9c&%bV(3z?bT zEiwi6IseZ(WunL8=w~&_)kpTC?SamDMJ3oHC~9Lq^)8eo=mp8Zty6aAtPfYNB$rr6 zf|40?B`+SXa13&1S<0BXU^AWB)b0|g{Iyc-`(Z4&J&{$N&yj)|mhw{Lpg1V9ceJo; z`9(8Jfpm?Ho*TyhbOPC*u`EvEtbTa++Cih;ZR{6MOf@ZxxEx8Y{6_;P z<)e9-`?DV)Tsp_XbgU>cau!+ z;$(n)64t6eHA@>^YW;$E<+7w&&m9!xQEgglm>VRe;%pN1P<6&u2!KK4ZdVaC;B!~Nrtv%DZC(g09Os1*}f4u&zDIHDJ2FmZAqyPsLr+gL4V84SH<#2BXgo; zNnXm)39k)N{(DJtz+U?J8y{ah8rDeu5~M9ap`kzYVpGnLo#U(6VxpC z-SVnM#t?Ek!%}RZx(Fd_$aD!dZ!FAm)4Z@P&>l|Vj;Zvs5JzzG<=n`#s4zz)d%1wa zg*khu$vGHJc{3M`O`U&2={WpuaoW4Lu)N_os;_xF&>rd&^U0PTn=+z{I1`2b6vq8D5hC348gFm3Wsh(H%WKZwn^bt+Jku%Xf3?;*7Z9%4?}{Mc47k-$OQ&?BzWDYRAh7n5cPY5_H{jM)1#ujqHep-UU368iO}5T!03(T5STfex@lm~;M4-{Y z`czD~$tIo^0aZsa656Cq6P#T}1755?D{aryFCTAmCrOQ@9YA&3_iUg$YY8F9>I>?i zEpM`R!dEcni8-SJktRuH@&2K(lI_Iel7IzWm=B1%U0)N@s#hxF|4KNB>0iTW=nkX9< zQ;pI{KuC=Zhu&^!_{tG96MVP31$_&__wlzphgx^1=Ry&&PtCfVwF2HS1b)Y_{#aL% zIemY8DVG0~Ea#qF@nW?F*KE$coI>e>{w^kou|jBx`M7^CPCl>QAnf!s=i;R4;LXE@ znL9J#JJn5NdQamnH~Z~B-{~1Ix_~Nn zq_1RWwEs0;Gi=$$g`2ZyvU)heq%2@I7F)OA;G(}+JRkkl;%Q6Q({}GylwF`=(4mVy zLu6f4n;M=*6+Ey=rfxc@;|x)ol+Ko!daI&pu^ZquzWZLwTLy&TzUenOBhjSUU47ZYMz3Y=tMdawB9B;>RlR6e`wJqqKK8`8v3z=Yv&#()WN z^*2RD61~3vVcE=>XzA6u01FrK;+i(8mEEX-u-yD)^P6hXYxWWge;j(!lfg$Oq@`ed zrcaXOPOAYO%61L^eTPWG^o-Xg%K`VDZ7tB0tHx;`ima$bMO+6e98a9z4_=j_a>`T!IqnM zXWg4eJ~ZnSqX4*fcc$v}#cX$M7^*2(S~pN2Eik{aP&U}0Qr0A>F*Rg*#^b7s#AoC% zqsx1fb)YKXcG zm=)&eskjbWJQ#m9aNgvj>ha&lYuJQ)KWc*4tb9BHMI_7Z2jHy!p*&Vya1??Hg;#{< z&rONJq;6gy|CreT5ojLO)aMMCw=6@qF68lZq-6_9?!=J)AgjnQa#nc0i$Z@S1}4Hwh8 zI4bp-4@M9K*L7=|l-v}|^*@-_xjeCN(y#EqaQ_zjwA%30HIy~NCz%M%lptj}F5GH& zwbx$o(%or!{ef%6hU+8`4}Mr}n3HRo*#1_?Hryvcp+`JIBj-VzvW@o|?%ae=@7E3` zNg4U_I}Kzg+*Tdi^q(4K(aV3)D2c)R=De{DYshPW>3>uwAB_K-IypGS92xm1)iWnM z!*>%QXpuP9FAHW#Q)}Ii-yE2=oVV2{pZ&3iOZPIC$|tm+)yli6T@O8zbP#CmFbT8B zrn*6vMc0BY9@U`pD{ikTjbrIo+&*{F9;|3SbOF}`KQ{gULy7z?*j}*m;Pfmub$yhL z{fwWAlRmAw3Dk*o_xp!S;%W=`lTp}1UO9xvujn>0v42=b7029NXzwr}y$f5maSUI4 zc3{Hy10D?Jpm{fD46ow3j?Q&vaqW|VA*_tK+t|Y@WRvPEjSVFxl`^F063w1nmK+LCl`9I*&kz75Q;4_?c28h@lvfvOC9jE%tDFOCnINy=VB>| z(Zk=VDSRr^L2^+nn^QQ}MTQmQJL|n4zv7;R@~*p98Dlrw=lSfsyXQ7o4>Uzp>(#|O zCyPLCCnP;l9{M*c=ArvR{dH`mmGnu>aj>GX*W@^;vA^ZjIZk)LM}$g2(qtKce0$7# zJ740l=IzDA)+4PXZ+NrDbj1&4KK@e=2VgxH7Z=Zl1-fBQfmB)iFA5}WrH%BazZ)+* z?NtYfQ||Afc5dCv*7%5c6o<+_qHma2msYIOj+s9p(HG|KZkn~yGXI=f$hYlt^@k;A zorn1LZp4coM50Rsf8Ts8Z)}+;n5B>s!9-#69xpYtGw!fz2FaT#%JA-?$&@ z0w4?=uO$j-s;tT?Bd;gKu~`-~MMMoVypoNpiwpPRc%4L4zYkqkH+Jvu)-Rqk#j|N> zVrFBX&pVTB&#wO?*IYAa_^5RHhroV)x1q&bmQnIOeUBl`t~YK z54e!Fi264pCU+NOxGbHXeGA>I@z`$>?uWiLoX$)68A(*Cg7&#JR^eD~Rc_}mpVx6S zP)~Kx1nDrLEHj^+hM$MLThA5o?!<13`6?HL!;?h}WfcdRBx{jFbvAS9d$;GOR-O#= zwClP2KRlS?H6nlWU@nNL#Xl!>&=a4`S1gvW@h^X$*IwV(TN@b@EE~N0HHmJbt*e-+ zZy08Qnp^`a+8HmP5-Nv zZayskpI1^fuEMPlq1?EI**jp9gR;eHImF%HDY|H7F1b7oXD9hd`xo#wOUpL^J>ydH zWawm`VXNQcXA`4YPZ=9maaa6|MD(iJ@1n8w!kgnSmu>xd;`T8r9c4NI=_qfMZm5k` z=?>yEgfDT@G1ujr_W)z;ki0Lg==`rX*r{1IbtCVFn+4-{p-7g6DLF2Ei&Jdl%q+3^ zaB0b182}y-=!loBU+85pMwS^OZsvptOjY-ta?18Xn$G^4WefgTNM-uqJ0r{@NsHw+zUt&KHp2}@B9lce^h+6BBV3IhIoRKLa; zU~6zK1;jsUf;q?Kvy+jdB(4F)?ki1p$J?-r_EpL{(QTj}3PKev{uz4GTNq~ax@EY3)sebhHCe{+&X+JuF7ZqPVL zYiup{?x(=cA_weUao`nTz+8z8kT5qH83;($rNAVaWjwW}@MO8u&#W+l zMufJ4eWv9(_R>HK!5B$G0#Dxk__)fY;pKmWi}vYT7(V2G6ijUIV5JjwC^+ORi~b!s zO75def6ARRyHBkT_U%6TTX?>8L$=hS6I=S>V8CiEwI$5zJK-QnQNoCbm~MIcRVEkN zFQYN)=(iw30tD=cdKk8&j|UD`Hq(=@YIZ->`A5s@19?1-yD%a97BQ8CElx~}St~3~ z!Vv{`FI@F&;Z$MzxGEBB*dfd^tU0l)s8d?02YD!Mm9COw>KRL}xELE6V=Hs){?P)) z7dwx=8*M`|PZ)bh_wReHdg(#&20`K(Jqb}9VImD59&P|W2@nr70wlgh9>y(&TyyhT zggRfb|HscC$;vwX=mt;*)i$eT^d2-q^SuPWgjM#hWWQ(-Qo|7Ii9Te$Med6rL|5%W&O9xhbJdOZL;cG=S#wA8t}IDZa;OJ)Db1RSJ<{ZaAaFo?4p3?g^wnA+m^Fb*&yLxnWjoEqH6b+ zlGAbks3ixDY$XyL81GhmVxSM z)^aP}E1FnnU>`eO$vzc32+X>%O0#P5vo2y@Dw91lB+rivH`3_NF`397YpLuTDU+B~ z*1Dx-^Yh?1EV%9WM+-MWIZdc|ivCkjI8UWZ)OZO0l-) z)#+xq|K{MORd+ZQGstLrgTU(~dbX9L3m&=b_D(5r#^ldS%avr|fNtJV7yU|rp*ieR z|9q!Fjvf$ZJDeWZ`;57%J=%)O-Jx1=c6+r5`uB1rm$ebs!X|n>6b5YHrz^8vQ`&mi zcljSq(1Kjf{v)c-*~-m)J&FTnQ}~LRK&}nnxL#qe<9H8F2;xkIL6vY$0Wp0jg7k(v z8q;HNf+9uQ)M>9-mCpb`5WK8EM|G_~@O23n8|%zjR|&=egmjtn3fb!CWH1gQXwrHc zKv{TGpLup`p}xXEazc4=eDI;xSRkvzL0p}-9h#Ejjpu(i{h~f|n!-CVS?q|qk+16F z_appj4aPE>TfgP=cBa=qX5RAPO7a%5?t|xog#>p<(*(St(|qhb`Q}B`K%|5w+jz-- zxpgP^3FmDxWeZMeq4H>zGisH`rxJe7Y4H8pDQX$1$}H2 zFLl3EDlx3{P(PioUCw)DaeAJts@!71x*tBSPOR#gF)mbAQw1$ItL9Y-`A!2t22q)?Cc!)p6#{W|l7;du#$kp=#I+co7CvhHoY=JoX6s|~BP z8wcII%vDGGyApG68h+stXy}tUGhCnAk|!a|+i`B!zLK{u2C78*>Zfy`6(`;N`T3ap zQ|h(f1Q`0)4qE25iyb`UzdcuV@MU^!?alXouyPD1|KyimP^MG+bY;!s%dIOcYL0O6 zmuhFy{IHX@QlGX<_DV<{3-l0^3p~71!)Na**0e|UdyaclswJBH8Wml0l(;<}(^FJT z(EvlGddcK9t4iI3WAAGslMcUQaVK!D&kM<5_G>l{$9&- zR5Wd6O|MKDT@}~KZvX1XPYk>t=0rFz-*hBre=4^{cNUYF&B#@+x0A2b`?sc3Es8EY zcXwNj@QxK1&Hi^V2$KrI?Gv+mY@ge*VM#I=bK1&-YOON>O^X zq*X3%%|7PWey-LKQWOk1D=*W;cp!6`i`2ZkN9nYfs(%bMI7F;TudZD4c+xabeAxqw z74P*%8IGDyvMn6fdsXI`rlOm~9{cRlC0xuE=Ip#a#m7&yUVXXS$Ul6;aFK)NChez( z{V2+}h%l^Jb=Na@QkSRe|FHJf0a5PTzdr~FN~%amD%}DiASEE8pwcZNA&R6y!w?G6 z(xP+-3`$8UF(3j0Dxh=?DIwiC-1X?*XYX^q=lt&Z-FyGp?(H6iXFjpwwccw@8ytE? zg|Qf)9m0Otbid?!J9Z~t6;5K zX?yQ(-6_@Dr02Om?&6P)9cGK%>I^uYG3mWOQq+2ujzKMsa=Wp*?_@v zD=GI~k6p_Hy?c79sLP@k#$uU$@8smxcV{mqwPnr~nAr}}zxStq5LI8Sc!Q6*kYGwk zyqr})ltAS@aw>Nc#*A6=EIhNBQ_l`TjzA0S0@csw%q zfNZliwOGQZiCInAPMHnNCbDnHt*Sfa7Ml4(z=nC^oyl2|@YNDh1@DYmr6Wd;+CTW^ zCrI=Mizn@rJ8m=F&`bFkD%p%5(R3|E=7e75`yx2Smf4nPS`)*+cX1V2Zj0!Q&)L`o zTK8uBjB%eAS(~7k-zKlAaykJv@ot{^L7(&4FqJscZ7M&lUwl8(>PC|}*0)U9si^lS_hhl1829qXrURo=OOrJnI;nh{g#qNV`(i=LGRxAQ*&Kgfb)cXa{ z+#Q1>x2SEFO~Zr=*2lDCPZTW5J>L0V>gu|}es1lY>V6usQH*?-KRU6c&MKW1hTZXN z>z%7qE!yofCA4i0Xc=6!swri^NPb! zrM+?cj9`h>OZoz=zv&U+_i{9ryZX)m^#!i|dPt+iZj9Iy+|sr)SsosH*8CYoN(gTow~R8g}46 zt2bQR@5W~-Wx6+`DXDHkS{4$_>tt*@(c2v9itfs%RNZo|J){-GxikbyJEPG77qnN#M zCDG>7na8@73%&)*^$n}B4dWj!IVWU*Yn_(j?9<8UvYzjZ@c_Ikhn>rY!{(9X91NNta=jIua=Zqw|td z*iL^`Y~3$t%XJHRLA>8lX+lCPJ#RB9jyCDsk~>HdyZB7CI1ZtF~UvfvlD~ z@u1dn!x3AwFIWl)>kd%}lr3PNfI%!d*cMqi+13-RqkjsFtY+$$uV3nlHW$O{@qfx* z{qeP(NmIm8C*=~@+X}&?*hb0bO%)f^>xT3CA$G-hZDj){2iNv>3Mmhbelu0P&IDKH z8(R}tWf8f|9Z8+=CZU9sw#}i)7b!K|7sI*i)g{JX%fov~ytK)5?i8fSb#9YlrsnpZ zLCXda(T5=Jg{O~yMu|sxp7ywmnt9Ajw5wslF7W2jd-;qZ>^_r4H+7%Mjq$d;fm8L&!!_R4~Xz|PT#;<<}U8k+lxocy7y)D4hDbM^=B${)(YPt?R@d_s@ZF)f8?e%>KrJ13}{t z7vh7(a>&6xSyrJ~BKxilv3&hhV=c1z^SM}(-QEU74EU4S@C;mx#haL{tzX9gQ`MbE zy}e=dgi*|X$+Ki_&XlWbA$MH9lweZdD{nOZS~p6%b4_8s$)aXi9cN!ksf3bdv6AbY zy?0??>&@mO+xz{ni9m?>aT;$iQi?7$`$KgH46Ld%LLAIhI|njL^W|7?26fD^i+jqO z1FnMs%sJyNKIx(RR*M;9$@0o!a?$L9=5D3>dNz#< zJRt+sV($J(2g|x*v$CXIi)QKfqOD9rFD$zAYOKd+hvB>usjN^Fl-t0`ly*5d1NY$! z#88H`wcIaNJG*BUvya_Dtq`=tE;|<<-0Nb@=*ky~^HjCnEMgVT8~?_IZ^y8Icjb#k z87^hdXOVe#IMK(g9UgmkzAL|tV5Q08W7RsHGP5PiB;&<|w%GTmYh2-|tBHCxrL8Zq zIqn+WX}XxLOAD)%5nc{o%Wc#6;Hog8&rjeur&Ve&bIR*1ckKDB@7K*{l&Qv^2xWnU z_j%%y*FzUi8pozfM=HOkajE7;Hs0 z>o#|D?zhhnQ%YkZ5AAx{Y=0U>e}G7;(0i13!bl)s#vqk~A!PSz8@zpCO2uZkNU7|T z`edF*8v7zVeW7plWIt}de}FI5SMQ4&?Ao;(nGTFpU)3r~U9Ga$a-oL*sZW zgLq`Q<(rjz@`RBB_D2X0`Cf$YK)_URP)(;*J-Y^pcHMys9T>9l`y=l<;Oa-dUs8tL z%KYc|w(!;`&o8o4k%V$!ZR(O08>VgV26D7Me_&8rfn7nP#nw-+3k5FXJt0MR+}9fce!9Y^Y$7L$~nRbD-RObS0j zIH{d=B0EoQtYbSDJ@uBpdH*?a*w{90IllQVKAU4w<;Wvbi51R|)RC0w+zc!EOt!b$ zN%+NX?U3*B1LY3a`RnkAgno{I9+=~mPDT=!(iaF*EwR!3`bp&f!5bidoS<3OPp?&9 z5i_yk|Lbp&cc(byY+oeaUAt+!sK1Q*$gc0DEm@|dSvARa;cn%C|H_BrREs-=Kw98C z!(U@X@&^=H&h4(E*sc`{i(Rn4Gu9-iq?5u!+{tENNI)eQg%+feksxNMhcRXlFI8S{W)2-?9^Yan{KNVH8 zM&{wzuA43?$%E#Wha6Y)N7e_?xyWjn(^BHZ9!y#9*EJ?bJjUCiCR-m)?!k-d8vU-L z3oyHp=2Y#0=&Z7I=6LQuoZT#U=p3WQ;R>Jjt-%g zb_+SiKOE?1;??QdtO^lZ2WjlGef%l$ocq){`>8EYR0>^NNX|2B$9PlVB?-*;RyJ@N z&2_vNG!xJ5+sm4_rv!KD%IQ@)w|GzLl+*a?Jx$Y```2`X?o%{sv7}44E%l3bQRLh| zB!7-oCT>e(pLlDldR2c<{V0uGjGtX!+bxLgnRZ>84?dLh&b@y~!@&QJZhBtP?G`+`Y|;_Q-vc}G>_gpg1jd5h9jU6@rVwsE0E$n_6C08i9Xzz%^j zw-A4{mn{0=A`jL^+`TZF~&1dAdiIpiBDd-Nw=anHAY0&c`h`PzWAs&e^uEVN= z`Oc42_jOiPlPmE3Fa{xZ`pK)*kjFfOH13-+P3pcT!+HJtaJ1vP8c5F9jD7&q0vp|8 zegti-v8(zf;*=WEI5CH*=Kj1l`}2d9>4rXSeC)CbTHf&?K{0!fgsAVrm$^PM zTaJNnP&#S(aE##M&RTGk6j{Te3v0c^w+ zd<~!0l^!IImRh5k)F%o3?#LSs&MwYJzqw#)Z(nC^XN;~SLVysp+>y4-f&d7tZ|Gbg zD6<5Zu(fO(M89VoSa8(9w@ z^LdoQ-gFNY`SIy8q=Bk%?^Xo2_=~K@ zT9cW@ao)}`|Ivy{CQhS(mYbD?ysjvZZ6kj zNO_tAf_a7?!|M(DCV$Yl2FSQRth;F-iO1-yGisyf(ypAq$tCRvF-1(np)*P+IVxN$ zPatskPQ4MZ44q)Snm5&uEZW)b@@Z>ogll)(p@7yAvWri;0xrnA(at>{nJ7YPI$XiS zXVL8OX!wG`yHhO{_!KBD`v=z1VWSQKmXjp6Jeyi_Rk+}-2q4cKd#{ykr8hDs#HR1% zH|_gEsA<;W#7UWhtl7!m!1>NJ5rV9v$7aCANq9^uo?9k}4;sDFmUkJzn+W>)c>{dj1@3IV2VQ#@mF$&MmZz#ohUS z9%fW5T`1N!%vyTWET-%1?)eY-LI~8OSIIo6Hr24vvG}zxZ!u#3s_db45x_Aq)H9}Nm-=)@6JesJzH6xr0wr|8nPn=(>y!qkq z&@vBmQVQ>`6y9^;dz`ZOen#QinA_3^l~VhC<+cX|@TKn7-bF=Tw3C*ucTqRAqAav) zaYfQypGEU3SWd$$m5=s0kNa;0>ki^|Uqu0_8b8h}Z@|XWW z^0tZDFS3#9f=ssw*uRcrLMnN4QDk{-pCp*={(#JDC^QbzBY4_C9`EB|!6Pk!)GrOE z%yPU_KN45YEgVN|;}zrCTnL#U0>^@B0>R>ac%u z$79#=-8+tvcBRXT*OSiCfPHnWTH^)7o>lIKSDO-^botuN*VLh-m0HJub-NfZUa^{6 z=C7_Kk#?@V^1DjogywCJ%iW;m>1?!!caYxDt2q;$6-vxD;No2m$(yEu?Q75MVoDT;_|T@r4lOsqC@T>)tN1G0S1pb#q`nQGQ+7m-v#8HWCkeUR^H_ zq9{0+ooP5QyUk{{+!?R*P?^zp(9tJZ<= z^e^WV^JRm8o?Asc#z#t5PNjJa_om)lbXMUk{yZaL>~$QXi0JFzeno08!hVi=?&qM{ zMEshW`d1k|-NrfRxEQ~&-Hml%QS=+*Px!DB|7qZ|fWf;@BH0#2i>x0ZrJs8gW0T)c zx&XmI02~W7As1fEH+F~yg;+euDfD7zohJicTmWEM;L*AeBf8e;-_g}i(N?IuzIPb4Hg@S3`m zA+=_Vxa_*N355X9`)OTEq%JDM!PIc6a`+#l-g!&jO>RWqp^>?!a913P5Ad*IjW9b}a=&-i1>2 z;ssu5d%QlGmZIS35EtmTru1CQh2rQ&bq+Pbp0l#B=8x<#8`^_$?X-UR*$*sfmE&4g z!WT<0SLzxS=R-LsC2vWOuo=YX1yN?}!fRu>W_u&e@zS{S8b=yX>uY258&?iCtkG^SX4BQr z_MV9}lwJ>P7+T{xAOd?`+?F#Y@QV5aeNzU}fwG0`8f}I|eESvG72VACmU!Hq`7x5% zD>F(3L#X5zJ_Zk_uB5PhP7>H1W~r{IOKtI0Y;)f?Tl$n+%Ag`Gc6{UT2Uxw(aM$IA zsh;MLvvp>bIVE#RkoX*bEz7n_Mp?BS(Uc5|tz%sc0*w%20N)qxlD^LSfRfA{fH7du zveshJLv(X{PoWZXtEbnVltOaL`#TSIK=5d*>4)j3wAS9JMalK;nUE1?x{t8D#X(VU zDc}Z1Vq{#O>HREVrP|=N*|7CG3t=WJP$jsHwL4Gpkfhu);d`t(9^Mp#G8i>daP$x< zW`0&BuL!w*npz41Mku2_mSd87v!`@F!W!1Y)BM_GGaxxHd9Fx#|E*O#AA+P)KX z9L9JSRto34WI~jT`5|9#Bsjp7z@7bl-jbpT{5m!S= z+ZNya_-IJB=+xfD?N~BSmqr7&2F(Mtx>Ge0)ZyTez){B1yb0~b>T9$rcU;Q!HZ3U~ zP}j=7$AzSi45Wtp>I$)1A5N&%<9iT{Laa0F+->I1q4%gK+C*Ase0=jO48zZkZNP^p z{!W**W%3c?@mp<&>MpTPkLhX_(?eA4xar`MRa}QF5Vp8ce2oH+Ia&Iu^XcRXkHdT4 zw&jScYtvhJnt^P>nIA!lz%EB(u10u4nzIG&rhE5|`8}v+HSh3|WCCP{B+v5A_nxWD z=IEuKG^tD}$@rH>h>u}8*fo?s7&{MVLChtI>>UQ*Gw==Xkp>D^7GLeR7{|2DX$!DL z()G;zUc6em$$v0xm)hL%WgRTu?axO&1uo$A(ciJjX&@KK!O@Jnlo@c3Gw`_12ajS+ zQERiLV#!B8Kv)pofaN?Tjl|mDrNSV(Nq<4#2U!deGRgVw9k!5}@@d|gY-JxCSW`Hy=}xcuD^a(2oNjF+=hsYhFPJZ%B8pnEyeWGh~n&;Jnt=gp{M@Usq=?_p_WVd-gdPu+O&BS08SQ#ce7cleGt217mAws1lv zTn^Ixfv>0fZs5b`YJHHrvYWRE&=9lMpxEEouW4k@XRbBMt>(;5OcFGpDi~fxcop1SuakE{@ zVcCAmiZk&x+s7}VDpNXEOwlGK=0?`4Qv3$*ibamX*+RmNYoc5qey)!}3GqCQt!7xX zjoT7<(r*qAE6``}EhPFFQ$vb$XjZE~#8A3xmQQ=kl^s&Y*qM4LnL!TQ_3oq+Y6-pr zv=C5`!8BO`f14HLeQ_pr8x>#G6;`eiK{&-CZ+=X2()wrW2h+&*~yqHlrF4{#P zM1QTv{XV3@uAmyir#)nIR;n{^)!S!Atqlu#ev~Ztc-Gwit z^gH&zd!7OJW(Oyd4(!=JaQ{hrGiN4YN#KEztDrGAuS2Bx^6Y#Cy7NItW< z+^}%<;%O5s>WZi%FjpX+f-$sFuvHRU2NY0paaLd)6#R`umsrmLI6W3Q`aeG4!b&G z(l=~Y9n}XqNbt5Ab_B*R+@8~jC7u*u*G6UR2*vI;2!$;)`QJuSowHB0wobs)0%{24Rx)$~sHt3fU`ljIEVJQ_XC4s< zfFS2$_nM*K7)gC|Nwk+%Ck9c$Af||Z?J_>ERH5 zgs3F*K(9v%QJl;ixNnGeq-`-o9H5!Lk;Mv=H3*dge0|JTL->=pV4o!!EG&l?HFE;oN)+bbFr_lQF)h)?E~YBQ99;puGi_tPYF7x32yb(b2@_5Yb#lD zbz}HYC5#aU;t(7+w7WTQM@H-Cc*3G4FdVIKLK$zfm^{jRElF7odx+*Z#qO2=8|E4% zpg#Hh^>Hgxw^{$-FRZ~Uu!!{T-t;Zfx~xyneY1cu7AT(xtW-n;WtJI0Lj)v1{NG!I zir*9R%&Pz$P*Gh}i0`m$3~d}DK(G|aTkS?d;MYmz3cA<@e-EqsozCAyL<`|%AhSaN zE-3EO3|T+``3L@ls0~c20+3tCuk?359V#)ksfXPFeTRyZe9ZEzeUe$V9`s=g4yd{y z31gI-HaW| z%tgiJR2D_3l+_ zYM-Tmax8DiDgp=39P_t9cH|_~6eW2(rLV`1D+!tIoZx3xPn(V4Dp*MsZxc3b>)gp% zHRgqS4B{zlHX*pbcJ)OtwwqZmI4US8MCsPHYRed2&i&UZ5Oe_)1<*?dfLS*<@@L2o zX~j~HfMnAEk%*Hd>G*e@@-XFUWwV~|-VvpgKFZBsLFfvgjpVDQ4qfmxoe+PF2uoxsWH`<%EyWi_n zJlcO{>y&90Mg-5i)x5gdPt~59_!cVamutGtFys}f8~k7$;<&1EKBJ@s(N&Ey(`kE$ zL8c17zC|`9F01Y*Qv*^uUnpw&-qH6>aA<#eao*o+vs&tXxA{xcu*jyT%c(mIT`2kt zwqZQ4-6jeXOeceB#t}Wwj-SL4`x;|!&Gu45iMy~1;%jrs=y-TUQW2Wb_5DCg*(USP z`k%@TA%>d1@dJqc!=~T{_4Jv^d3SYh> zd*s>N9zv|0voqeDCq4b;L1?#VsqCz$xHd?6pekPnX};oy2GrhE^<>i+9CBe#;E<8M za~KB-{fPENR*mBidS?9_nhK>JXw#Li7DRx-H!r$P4xRWh*hG0CXy#|n-r^jsb$b-5 zbXHcMM|G#(M91o2Rt|Ry-8}hFgb1rrEytfjjuK_(qs>78WJtMG(UiI{II$w{aGjQqfg%EUe-N~2N$iQ{X73YrYz$axZBJK=0IZ|(2QLl zR(R=9YSz4BmE%20p5XOz>^j|jY+SR6y}hq>ufHVaQqo1j|NhJdEz%;mt+QD zgFbPq#Z`U(I%(Fyp<2j)9j&Ls0sb>%CYZ2A$Md(+dnnQSVS1i4?Wy6Q5VcEBx8BsQ z-W!OMh6Iniy4H2O_nxNo5IihGhhNon`#iT1C`$urF+4m^GAMIDS%MvHcP>{BuH-l6 z{b^o&xnVg7FN;NbC*xu%Uk0){7Eo0~;`l>ruL2E|b^Up>A9I=dQBmfouPcAaBMVN> zU1bz2S-W;ukNnLJo#Eea`SroZJL|+;Nz|O$-`j#iH5Cy(2%|o(HC>vkNYwA3?gD4Gv54D)n8_shg zY*T3Km%4ZZQ5UD1XC)nX{S$1SW&8y;6?b-tncyw|Q16I0+OL$*;-qa2FmbmwHxdFi^HFF~#Wi5iDHNX!LKw?m@VQ2P*92BQMo?P$&GG zgcRvb+0=0qVxbGfUAV^MDMXEmOcCn)c4rieJkTa!3tCn_>O&M-2pWx>dm|P+x^c8| zkg!Bi&{*FWqMm;ybG*|#7x_HRjc#bSQ;;Bj8&?CdAQWTLOIie*3wJ_8$4}s^$mQ&0 zD3tPvaj)tNfNP(m>)x+K-n2@+#J^;OmS1gGF_tty1bbIL2)S|@KXeW&wZ*uFAD5BQ z>R(qbkPYbebm9MqLW$s|LfAE_XNenF4_^@Eb%d|j%4?g3tpqonrQ`g3jB6CECQlDS zZ>r_GRPSq75_br>{V0N};IYDrNk^SDaB3#p{b}yRR{uf%%QD!GD3Rdv6Lvym6(2e8 z!Hk;nRmkN(uUk`m4H4u`{rq~%qK*^l67^8f02m(Ze}0=u&-cQA#H$bWav)a@k2g^Q zrnPWdkZ^*Cy~? zCz#MfqHAkoD42>-=xWnCAh<7E+FXSiw4#1p1Y+$-=3}=Y@5pMpg$VqLHq9=6CDmh$ zxDB=1=?GexO3iffh%5!Wc;23a27%h_46_GpD#?cf6E&6^33%QAv56G^Xls?qksQhk zt3&EY?5xKB4&?P=tro5i(!E@A|GtY28!rzY_ecf5QIiX45ed{D2JC^hmZ{8ENNPGt z*m1dbEDnl=!RH4Y-|w)47%fib_+h;7)@>iV^6epfIMm0J0L*m!;rdlXfd3#$1FR;n z`ugo14IO2|G~>&9_oSrjlZ9m>C{0C@fXM;12|_B3!x#?)ai`##+G5fV5kZ~{8T!`R z{p=OK>wjr^bM5u)b8`K`O1>_|R@Y6K_Pma{e#ecQ9~A^By{^X8W;jx!WJ-K%rSW>N znnb4Z89uCRz+T6~klXod78JFW0E8ih%m0X`XoA6CgV%GnwXMEtKq}tW@ zZ~p^rtq0lRa`Th!REx!kZsZSCq0QPGu&7EX+aALoFW6%<={g2ub4gt zHkoRM4N(!UT@*aUX64PB@4W1Apr&%(Vy1sTTHjq zXZ-I~#QD@LdcCeWG6V(EYJS$zwKERX2Ugl~l7*YrmB5llL8)?ek{Uzy$g}B0#%`Sj zN*b=0w<}_9IeDd>+uFZ}K!?lzKnm#l(IE<;9-} zg^Qqva%*$Jb)pej7vW9?vQ|pOAd$QM>!n8jf90++`^ytLhjrRWMB0`E(bhJVojZPC zT-?kYSowwc>j99OdU_{Sk(?ka3sF&ZAVV|8nyu3(Si3&eNc6}GM7HTO5|3PZrR2uoD)su?M(Ct>=l6@&FAdRKx6!Q@-f155 z5lx3k2m-*{?Up zMDYBRzu{X_3azRm&}+bk@)&8*0--CYK=)>P?@sE82<{H!b*XCwLQw=!P$Xc9<$BEc z2eMT$l#+^3GDPjE>MB8eJ=q zv=3u5pC#qgy*d1wlbpJ*6m=eG6>_$t{Eq>Coxg-;(XRYJ_oK*09i*UPM5TLqhjj$C zUB~b}L&V*^8}sCWzYu~nGb#c z6|MgUgO3SJDtr8Y1?Q3fNdSz8(EYwAu2GBhJ0R`-EOT1@-ez76{^#c$s5b(Y8RIC< z@A^R&c6w9X zCxv_~BXO@V0?1Fw%{vY5m`ZxGVP#fC$pTV=imke)%$hKwHv%i6(7XbuQ-4SM)oW=G znL(MZ#hFUI$$}sE>IcRUEF-%l3PWb)nL(7XlV*kL+~TKW`TI&=Up#jP3c5D3BTpv9 zOG6k?`h!^$@<&IXj(2>-SjvQJGz<)!>7qm%hgmV_9WFISGqUkKE}zjr5>;fOPnzrt zm#pxzfy_>#?Z~Ss^?q_)mPOBaM8yo|+h-MDrk=U0;aMP;+R^v*r7N|!;F;b(FoVHn zZ+1dIi%KI+O%@T^d4i{QPN0WY&*VoFb%d8x#5$A`GNN63b)G;880R`isrha^OAq*M z-6(n||FaGeoWif-;VM=To*>;l8*-*`W%O?&4vZe>%%B^`iCE z4^~jf?X4;KEPj1fJcOjI?^li(49pd_gR1gb3*q1RY?MhC#g{74hk<IBCtp~X!_>y+--0Q1UUKwVUeSmp2&9#1J z=k2i5Sn`9Y`3Vrx31vLT+V^Tv8R3u$<=|e%C7gcwJnJ8nIAQS8QtOolm~f{t{?^Ph z6?ql&xg7UfF3~Q~;?!`yR6JP&5Dyh-qhIV8jzXC9emLk=O>H@TC0gwaz-3T3sMG+W z|M8w=y=hv4ndcu;;4`e*%E+Bb{|aAu23JOSZTOWkl0z|bZ-2Yvx~ANmM+R}+lw_5A z_r3UX*%nBmzDnFH1mMxPRm`Tmx1Tr(MWUu1uPO3bnK;^O;oJ8@u@?C@7uJ;XWHVOD zVlyT&N`O?ts}BP4c2^cvxt&=)3)Krlln$oRb|#2qkBiN9mwUN8ragp4TS;lfI<*pkQDTUKobknpCfhyJy{2hF{+r3-{RCm z&S}sxdL&2fu8_^Lc3y#c(0JrU0U@OC0i%ymI&a^Jw0ItE$j@2TX9j%!Nw^PG352~& zigwbSbHTh#1RSR5w3Co_tu;mK$+wF>O0Lhdu6B0&`TgahCa5MeE`$Rp*jh0x;9uZH zWf(GR=LtcC4xOveD+>H5%BaTyWNd0)hQfTEzY{U3jm4u&9FvO~y)sX|CF9&)U!=O4 z*&wh*mcV3lVFGtqj9X;SN)CO%TI=LWl4UF-$qRAtH~eA?82_RIE`yWHlVyl0g-B*8 zYG|fCnh*HgcwREu^H1oyIr)OGyZEo1h^`zP?3_cc1ci#}atG?DpP+G=FV{?lzgyvThcikp?Bz(^ z#WIlJUU~tXLW+`l3^>I(g7RMq)lmhv(+P12zWxV`X8|iVP1Zj6gP-EdnLDXcIrVOs z-m%r8K@hB2mAVJx7r^Dg)x_lQPW*vyS6x&D47%~{oWx(h z;gB!uIRLkR{QDn&n0;7@Xn}X+=Qic|CoFrB>IR~WE%#*o^peiiEaIhnwyaHMjJT3d zhOBQ<=w#QRH1q}^x>%dnP*3im-H=oM?2=UEO8J%QpvF5n`>ySCDybBRnQ>iHSeNwm zK>*n6j!P|ZVPB^r{Vvp8-i$Y7L6oq+Xsl+<)w(;C*)2y1JN$lGY9x?@%21{d*m}m2 z*gGb+C;uB7D>msmt0i@grnZ9r>tI1>&zLS$1AHuA|3Bu===yn#q*aG_TnZ7 zf#EpA4gHrb*tXOS|DJrm24mEkcZ!*32ZMO3!*R!bOZprOHg*2TLpQoits;B>tS|PG02mUmf2sDSjUOlQJ-ZL2u8uF zd3K4jHY3ItBz};Aup%BlgPnOJEt0VWa`dgjkW^%Mu?dowuOp4!o>^ zaVWxFAwdCYS|)!SEPhiyw^MxD<}TqlvDIJ>&ROpGXO!F8m@T?4og)PFr<@HLAU}9m zTE?eDH0}eH)nW-#)O%f?NTe#Qx-4uOfWk zt0NIcg?k`kE;}gwLU>lJGX(~C>-8JeN3jRsD6TC>FJ0TQ>0K!UMks2g`U-N{quu(M zE6A&sk~SluMIF|?9PBqf9<=<`Zn^*{q=0(;v!s`7%^E)~ARTu?f8*KZ-aSKdLv}Rr z4Y(+%GWF?)J%Q|QM(`?>_kn_d9O(#j$gbQ2K`Bw_LAupl&=NW!;lZC`S{FVLyO?3U z7Q^#Pdw=LzObDAxpP6(p_^CVEz5cRTsnt)62CC6xTy5B00o-(0K?g`Qfh{&bXM>-~ zYYj+s^kOPh_r3g<{YC7d42*4Gg<2py3#d^Z_iVC6Z8L@lTb#z)$k%kGSLVP6$dJzZ=XVt@)Xqe9Ezb6JnupJZoYfC1!n561;yKOX!|+``GR+L% z>QM2rC2<#c_LG>0Iot!+ZzMbsau|$>Eix;<;E?qCCb^Xt-dSjLgkIi6kkJd8giChwG9VJ2lhh`Ik~}mXlT|o6{1?czCFTDJxzduxEI-Y}@RYxM+uXP$ zu2_8k@!1*+q-Ub5pvo7TLy4;O35t-|tI;?a%S9sB>BNwSxvsso7mtod4MY*cDM+KG z1C7}A;A}*sI~PmY(b;o~O6yI-c~H83@cwYR;X9P96RyGd2~gW!af+W*wKBfeog*Q8 zEOpIa83vs@Tb+|$PKc7*!*~F~#do(@D#;5ll+CXFF8Ij%;;q-?d0nP5GWXJSQjQBq zs#K;;tKF-SqIvH1N^mc2h3`1z8c%wp(3K&v10qH_1#t`_>zr8*7woGv5 zz}84?QZV&T*sA2Akjjp#=X0Q z9ZVZ=YEn2mK);4=}Wfx77E#-1rNbYwv5M^~auyakD+kjkuk^0awKb zb!zjAYb0@PNVNW$GUxGy8u$Gy5Uy75(7E4_fxe8C|6|%ZTI_Kc5h$Pgr)djl7wznX z6Od<(!uczL)_#q`MI}Z%SJJNaI{)#13{L<}hDfp3)Pp%`b?(@P#+F4#Uwv#+n$&Y) zE`#@cMgtu=2@-_&SB{=fgF+>uzFynh7`^{MwKgpz6iP}n`Rbr1Vic-IS|DfanDLgf zEwX{?@ex^UHC_M_7}8AJ(pzRzUFie9Mc>(e{5@MN1YA&z9n;oH6+qojI~fwkAJ+#O zo5K)+39po6S}oap`(5W&!kTa`dX~j8%VweFm_C>IF;Jf%a_NBN+i;W{0D?KSb7GGi zYuO6tLN=JUvx4s_f7STqzeKFHMt_M|X?<``@fwAVhd_Gie(ACB{}i&mNZSBexyjm` zO3<)$H+Rmqf5$J(%2xgE7?Fys_^FmX9}xX%?y7b{VG7NdWo)uf^b#y2gu*ZqL#Zv+ z{w8z%%MRxXT8@TmjI8 z{9h_qAIBlwr=pyac5XN8M^cBPhqphN?8nfSYghA&uF|aZFJZ45r6nP~DG7UYG_4i)$glPGIf*N5J`vhUi_k{f?IG6B$u z*NNXP1TFP~HR@QQ*eN_@zQ>K*SmUFR#6k@*zPWB{4Jk1Jy6X#md&+(OgLp@)NOr5q z`0P4b?m#s+Lc`!k?QqJx9|#=*5xv?o9Qoe^RR>zq|A#;|sUc0eEy!A$3LiCKx_uPH zbVs0D!w>il92%t02x_=j*PmRd89$Q6GE%~q47Z8dwJ{9As%cvV$tEBgoWbINT51_n zA3bbzQzIlBS6J~9H-TYARVr=JlaJ0@jE0VPsATSf9+NED?e#JB)j&DJN(qH0Tqz7; z-FtX=I5(R^x4$H@d3m38DVy^^<&2Yt!v=lUV$lizCirlziR3(X66jtbgr-OsyS)8q z<;=CSb2Y}=hM1JU1g*lstD9>i@k3e@(CT#Y|BI<6IQ+>}CCh}-rFrY0m!OWEWgS|o zo~K5R9`vX1C_U>@CQC;gA%y@axN>IuA9VCFjweCr09bo-b_t9dxCr3hFv-cL*4Xyw z>UUb`Z9rxXSkf{Azk#~QW!y$>NH(}x;9^Lf2__%h+^EJ!17vzKDTF8yMKP4v)v15h zwnFX(1t#LeAze5h&<&q;)fVo^u=>tuM6&VnM`QW5i%jK3TLYK;n^3v#P7uVi2qp_f zA2~^*X8m>BcZHAs+Cu2t%fVT=6hARfCvHY3>HZ*Xxg6&w!k;ag4msdRxNO|qrQ2=F zVIodXn`@(9kZxs~0&*WX^u0Q_1&KgAtQC8sYW_7yYw~CFxvE{!jnFUJ6#PgHdRbCi zG&<02pQKMvG}iyhb=Z%*uRyd0Fyd!$f514`7W#;hZii?BA3%dq#!tDnzjjtU#I+5c zI8^G4nPq@F>Pk;Uu~Ze#S|m43H-!e4>*|6$Qk4N;YWZe&A>W54np5oqbjmzin7CrdYvqR*phjl>CDzLSwNG^bcaPkl3|F*z)-LsEDOrX7rFT{_@H6Glm z9~0!D)Fe@6jNrs^{B#QC9WFkZ3%!HC8T)#Nj*X$z)IabDi71$7i?D$6jO7 zrX}^gaD>sMS;mAN|C6CA_5D{2Rj_h1ke7?<(($`ad{~=ECfVoUHtX|wA?{divOqm+ zVG^o73hr0@b_#ONdFr~9U}V+qiWHl=B@*+{B#_d z=mdZhDU3EB>6H9y{K2xeRMiS}v*cTjfPNMk+9UVXh;}XVBRDXmN~!Dt>N@R#>?jer zllDnd-vMj?i*`2Mf!bF5C5R(bY;E=*>ZE-13snLU?lWkwoMXnL(BHgzzjOI%490kV zwh@HSpJpusw{TfAe%drwpEG?{GbP+|PUjv!r6$MitQ1zsij%F|y2vDs#>m`JU;p4- zibO3Tb~X-YvY=MV3Iz-#zJ`%)kE%~x_wschaQX-1VEeEhliHe74TZs8nu$^!!SYWjwp*bM%p?+iqUAHIfenm{eBnWPEl} zoD6+?80jtv6Oy|B5!+_KOjhRc8X2)LY~fZn@f_2*C9{$LN)ZL(S2O9iRvI-P|l9k|>k~P0GXa3H|u(pES7646SPzUJ} zSXf$Lht4bLZ~Q|&tFu2pdU3`p4&l%Oc zY}bv|ZlqrS3!aYNe?}mbkiR|waoy4unu~z5*ru?k`(FgD$9Pbxt)HJ!ICuYaIA`%t zE;O|AkCpVG8tov}>8Y}u`cdmWHf+?|=}iDL*@Q*Hl@A>_rS6qoS%c+2gRh2zK8rdK zvogP3a9w%Vp*}^d{m-kQM7L&rPI`lJ{!f6KUK8o87JGsu{YW1WOsczp8sNq~1=R43 zZ19)R^fBq=6H7236gW&h*bk<7f;OT*6sUVo8wBJ(-Wouq73mlt(*XRI73Q7JLBPbj z!A$Lv|HtdnssF^M3=g>0DkH$_3Y`2U%yS7q%f(O z%qcnZ55Bq#5nEBYU2W=-=N%3)ODXJ!cfDf7RY*du`3rvhNQ0^X-XRkKX8Ya@Udk3D z#T;+yd8c~dr&*1B89~~Wpx_O8DhCWK_{>K~%@j>JT$ zmHef1C9G0<%G3gIh4uXT!+3`%NDJT=LYT6To0UTJ5`Z1>YewGnXsGOXf$+K4tQjON zw(63X0U?0i`&7JA!fw*C;h;_B00G`aSub5mffO+)4s#Q2K-Ha!C^L32$;Q_oa(jO~ zA>K)GH=u=1b1dNan`JSWOz1Xt(*KlN?AA}A7-yo6CfB~zOFrhCWLBYvePDLj7EG;b zZh>qs0@;5_ZBML_y>ZnL&m{R4#kd@J3#$Z0PFfz7 zUu2w#lDTBeRbuU0ShTj}Q5892A7FTML*~%}8+VLp3tt|xO&)SCCx&QGI=aSiV-xf< z70cUVR|B;rIrA<_mQUqU9{VhM`NO?U_f;)a$(#u*oe(Z^e;ibzOGwEVwuRrDn+V|y zU@xJh5q0pyp|l4yLeR)B+&+LbmhGK;;D4>r(6)XhF(CzoQ*V9^BzxE8_7lVkJjgi8U9U>Yg;>jx0fV>ytdZqy0*8huk&E@I zCJ}fEONQU983vIclB_~4c!jTc|8FR^@;-uMDdvgdgUGrfK&0+TE2-jzf}xpfGGg{y zCu}{#0-&e8>X2}<$l6-d_k7k1^lBc-+|zwBcrcU*gaGF7pjUAQ@Hz6kofB?Kj5I4# z9{R0dr3hhBk%!p{&>;MQR7nb^74ays9TK~txypKScqjBl3M8*z97aFn;6#3JjbFpE z<4nSFF1LxbrOj1<&LjU>0gHlw?OznImdV0LnJcFfQWTmNh~S3*kD&vG|8D5O?KehG zkZKgC2hlx#M7*Gu+!osck|#%mwDKFq9WHR8{?!KqXBd=GSLPustP5PMihv&6C^9_i z-&)y61z}J&XO!EMg8nUeXZvvWc!$zdP&dB)@f8^ck$baN4g5S*cdd#-!TBxjM%3Zq z&0M~ENnRU4xOAca9^n@6%WSw_fQo)r<*DBT5L~!A4Q*HRgjeW3*0hc~1(+TZT}O&VL|-yGm4BKrfz5RlGwdR|fz zk`;ZPXi^oy4ud8OK@<#63{GBUwfy$fkLiv0NQY8Z>|&&#Nsd$03*ub$pQ7&GD)T~O z82Ye|{j6?fCQ2AX;99ZvnwHCL(iMg^jX+oe)$Pu;2Qo;1m+|)F+pn$EC-o1YJOFaj z#$1)`*#&kLuhCDU+A-U#`m*MC8m|7@yxG40#oKwubG^U+-$+s!C3_YklHv#`lWS*@-gBCbJ^4_srgV|E?#kb3W&MKIi-Wer~_N&aESQdyVJwdOohl zb$=8HpVk5eU4unU`{_M8xT2S^4OntgIHjn!ewS9ALYEO)w%3Ar?vJZ6@adBRmGQD_ zg>&s#zIkRQg5ZIv{&=H@?Qh8c^`Bj{ujm_L{K(+4H<%~U5Px*Sl{H6b+af)bPLLok z`EFJU{|LjKEyK1*I5Gno;pqej*kF;^K_k5Nhw4ODGiMX}p2U7{f(F2LOYN5^Oih?f zcQe`xZqIj3nZSwJc*e&hS7Dq3C&Eg$DN?8ZFgq}M6(+X6(Fm$=B;nCHA~nfO4YiLr zAi0*PSu5x?dxFblyY0ju9FBx~3|V9Y^j6i_yQL0%hY&m>Dbu)(5MD4!tmFuP=?3SF zx951n73lLKdJj^up;l4W_ts6dR=~?T-@SShHV;sS*^A}8jx}ybKFTSwQ5XmRfJ^eQ z!a#0F#0i*TXXG6eee~&z64{o*Dv7)NsW+wLG)-L+65x_ff|HooBWAiY)&;yWS+)_Y zCn|K7u^!YLo-#%x6R<$!PX=-D-blNK1N$sOqiB$*YDOcr2fR3(Zs)8zG3#D28|okf zYwO$Sa_H8IgKBl<3LNJSu7tfppa2Xo7#%-MlF}J;cF!0bdy$ua*r=xr8I0K1`RouH zcO3dJ4HhfE5DKQw0mR7z*;cj)V2tpYI}lIewqIB7bLsNdLx<-b{=pmOJ+f~m>R?=> zQ^;N(9Mg_8?_xF1cPDzg8LSWhApq0T5~g_t(!i>9APK^ z=y2qBF2Ql_A6$aWcQN=dhye5dL0cy5*?my$W=g$5JuxtxUZDnPlkm-8ninfFAd`p( zu(#hXvvo`k9jtKH2s_A4XjF1JlCuY=?42W7^X;p?AR7CT@iwicJY+8NCW+WmifXLn zqNN|>3*vp50Jh8^UOa-g3hvumH!y@PD-CMWtG=;!cc+>Eoa1sTqs;N& zaRx=cV6>gG{BE>m5GVRqH?72cZ!sMBZZ;MDVx|ot_-Up+X{SdH!pSbH;7qBG^iurr=8n+06(1pn^xQVW6<4%ZHj!gqenjzp(-p^EA(K#n)6DH)#*fsI5HlL z-d%Wt7m!R$!DkOI+aqErJi6BDKHg@8 zb$W-1+hPn%+$)-mcJHyd&-)@P?XB-tS_1F0tvDoQLMCUR1Bhi|)#flC2~E0;#Zd!& zw+5cZMv6Jtv+!bla#8krnZE6*=~Q=|B|EW2yL;noeYB5TM1=JKuS%WGq%%2em!gOZ zC6qB3Gc3FOWTT-lPx(7%g6yS$m;?viY=sQCXlv!IC$;GJ@qjp=oj=I}j}G8-kh;Dk zO^)%m9Ne}z)_)_TMhfAqJ0!gm6O)1R4<0$f;c+Py8d8jR8XYh*^?2B!Oc>S~&{@tG zbS7=c20|&4Z#TgWBc{n6!2o8MDtMqbX=!qLwS}8apV*2PCcOJ$AN{!X3vPGxP*6>d zFHYE%LwK!LR|S}tn_#O2pL|Hy34;-DT$eE^8&mAU;dL08Zzzd{y9)5z;4Y@v3U6qy zOS5e1@9|V?wAvrDwSm|ClK$P}H-b`J`4-diiV`x#;&#V`z3a9f1~4<=ebCG??u4@Q zRo%#AwU8WS>xL!Ib*R++FmsZ%pGW zs)Xs%eABRGu)>raVuq1mKqoSNa);G?Wb*CNE_Ip%HhGEUFkJ%k2kh3aJaS`gg60l2 zx0bO)a`AwEYZ7n+*wI~eTgQ429mPOn8GOE=iGnXvJv>K?^>3w8oW@G&Yby+}>Ls5H zQ5>`_AAuVyqRrOT)8TgV-n$9&bglHY`3bD^tu%wrTM88%NYG7zp$;J2=!mQxLkuGr zepB|qbjXV(KLO2*EVh+wYi^jQLJRr*?CcN6Kf-l|Wlg#`29x2*=Hl|wQIl$o+aDYV z;P8$fC9o!7VyN*8sd@Oa-4VU5-Ivirw!|&e$(~bYh=%{;ZRJ@b|iAT;w2wUell0xF_~vfP!`eE;)eu zL7|eY$!~P(l0Nb^fdhelfL>gE{NqopSLZ^8(28Au(DWU)ANsDE5Oc{sD!gLYX}K@!Hbbxp$Mo3up3XQF%WQmR8&B6!0T9n)aL-Zx&^Is+rv@rtKZzR;iokDmW1+Th|c}=$);>- zTzn>g2iv^ZyTE(kdj^-y%4|`3IpW{L8$UnQ4e|uUi0}71xN( zUwH_DYiCIpXzeFpQVmRe@$&jLHNfMAW=--00q^(Ad;pNPjKg$1q7*%MW18U%MR`j= zWz4tzCB4n#v$hfYSSAa1@wSSeaP`Vz$zC?~)LE^f6XY|pi+GIINRUxsM5_p+C|}~K z)OSm()^Bcbgz{k`Oul~K-it9DY_sdoj(5n@?xpe7v7x<1P55G1XL7F?1#?zZ%_y+w z_d}J{8>R-GM)S*MP>EE3O^{_Jqy~&k96#<0q^Wa+fqeAJP8<%!c?looD~(`1;)OA2 zbS{Z@h6RpyA{k*f09S;Y)H&Ob0=_Ib&DpDcO@&T1~op zOJMmxPlqTx-Su0;A2QQ?S3PogUbzRp9_==M2DdePVvP?31&UX9{b8;aPA4E`U>1@X z>f2+PgF)1flY<1zuQJ+3Zb~rGQWks=^>$ISw$ggs`FubtxWeH?`-b~0JC|6NJ*&+U zu8^(i*`{KL(g#Zy?mTlFp~C6-^!0YK|KSh~p=$tjr`J0K;w4znnYMA9u$%1zsLcfu z9mKt<;8)Cazw(RpJX_&CyL0f3skjVW-O2rXh%uA9UU!9qXRk)L!>XV<4|VZK<0eGT?B)VT+XS)icC5FmPktdjt9#5M|$Uh2Dt0N|1XFkZj~ZxiVd8rd|v zP@-LBzr4M`{N)04AD_#AH0g6nD1uq{Sub1|?Jh;8$|TbORvyxCj@hRXZT<|a4yN9p z?l}vx*H82FoRu6l&C@aaSgW@|8+iFkG~lu%&ee^G?A**+d9e8p&>?uL31$>ndg0(y z{S7a9m}u}{#NCIm;;-D9G({Fzn)5J(YAzDB>svK6KJ$$(sedL)DIu$M?}yqu4buqP z01jS-E<}w`vB+ErPCWHI8I(J z!0rRDtYt+5cx5M7%W8eWE35h4D=S&Im0GA4V(Tgh7E+FG^QPpjrMpoJJc%P$F3Ejz zw61XJmuk$7re-@ntQ59cLdCOzceYScWRgQZU&-gWhCuunI{4n_q6Gm_VUkwl2cjTT z2YgI$7UHF+U31I<66gn#LFUy!cwhk~`6!4gXy(0)EbZU}4Z6CGAVeqF3q8bnP2S#74jfP!Bh~*2=4Sg5}LC6CB%Mk;5z;IkUR`15jY?qhXI;wDy^h)G*e{8^MUNLCSAE z_Qj(JzF?6cCjT-qW{+>W4W~~3%e_5qwG11TYStNKr&z50aAU_^=lwZxU|k<;(;M$k3~7K$T|mZaExNm z@+n?lnl0{LidnYsU&l$Nld$c~)s7mwG9o_{br`RstPN~j zr9&e4yYsQpUnxpj9|uJwS;#+{J6^f&Ej>sP>%PRxNc7O-FHNs)OlkM~fc5dKBSR`$R%2YEbzVA?u3~jTvqKrS|6HBDd2ts5Yg~7k z?${FpuZM@-5?iFe(4v#SBDLh}J0?_&n#e##K(aY1SwY{OXf3+1MON6P)e`?2B%MDL@CWkAQO1w1e@ z__Pan)dL6u`a&{w)_IZpbGvAQKl^2?mWJW3Lgx)C>A;Da9m?!f9S(Lfx(zF*%!1ao z61T8NZH+o-m|Is|4**jJEFLF3u|JQe3ze*iG~HuaBNitsfgAFuU+O20ARrRt+31w4 zYsbk5tmf)ng#U^JO8^^}Z2e>5@NLC;`d|g17}1Wb9^$Thc)&<2zVvdWKg@0LT(xPY z(oXKWJo_Jn*^8)?{ujcm5p|3fogy@){#BPv$pE{9jz{D}7*Qw#{%HbhIHo4&>*lml zgyat__~Atzmeof&I4Yw-_N43=TwqWXZQ^0yY_t|IZrxjE*)0Y7k<4C<{Y#sNF?6cm zwMaq>-iL0B2C7JUejcfS*k%wS9fkW!|)B%FhQ(scV^g{b~hm;0dzs@=fK5AiS$ zZFLk@x!bmAZ3SqcP;9t{^xam=o;>W|*|S%h$gRD|LEwYig8|dddq+BiEEERzikaAX zABUd}LL4|tTtI%WNr!vHA(l?3EI2X)$(B2gG$+aIUeU$gSW zB+Kv=(dGF=Bn2xUb=W8w#Mo2Ze-dN=aKjozt;t+=0I`<~r01pH zUJK^y-|?e5LX8L=orB;3c3&s7X=@4 zGWjru^rE_GT^Mb;J8NN3?5qHn3>yF7s6=E)u+@!jL-PfAm<;v{sQiQp-#LaW8cPNq zJlCu2HILgu{SK&V+H0rPRE-&b<;AjpppzNT~v}yReykQwO^gNpXvbd8{fe zQ-MAa1M)GNQS9P3Z`{&7xT)}k%Xe!}y+oqLT_LgA*l*_9qh#c;e=1RD!SpNCK`_&T zgjC1d_G+YT*7IP*vpWTZZs^s@_zY=hS<$g?*o>z`u$nZP>OojV;O`@b>?Xis{Hu$3 zPVK@5aKVYI2fsT=vx>po9vNRnnDQ4D2Sk48u^Z7V{-j3M6+qx)#eq&q1D8pj?3;zu zmQxkHg_5OTDgKgZ0Hn9*(m>xQ`C4Iv-eL#S#u=E9sqgClPLQ>Z`m-RL^iz;ESAE+w zMx3a}o{dDwuoQbjq;f*q*i1FfVtE=Mpf7Ypwfu}p%iC#P{R=ZTyJ&A7TLn7d`tg$3 z<`~NF3j&E9j#Ph3GMG}RU{Drn@BmT$<{YE&un)03I?8$rukyc%S|B?LFx@%D&I(`}1_ z*gVhu)Mm;Hh%KkkS1r}ZTTSe?QUC6|k|=b;OC?|=9wq>R(_s~D=r$Jab@Qt@oEs6z z7?IkJOxPYm=5_Oe&d1;cH7%T?h8C@;m^>FWI*{F&*YHc>hmh|k*x*7jbnt`@7T$`z z*X^G9c{uOL>Stuk(co{5G%@=H0*?%xnxPFF4GJu1B3K01ZooPvld_Bs+TZc9_kZAH zZ}TXD8Ukm)*_Y!qNnUpxoATIzF^UiuFZppxCZ>^p>dlRe+q(YnDZt$3wJ|x(*(M!z zmNw6BAfsrGyk=GHhc9cq2j~ocI|g+wYv~V7cY_%-1TaVi?Yi3s#qai3k1vgH_S>d-I}nSBBXo zQ5YKmM~BH4u@;0!p5IKJP*?-KS*-i>3!d%RuOh5Ai?bCjJN($^pED&q=*}$6ecTk~ zUHFKtQU|o9iqL3-Wn_QoWe&LtM|Rpk?RLvhV2)t9QIiy`0iG*yWQd`gH;K$`1JA;K zkPyt$`rwX0h;c={#YMM@6@t`sK-}Pp>;Np4E-GpA<;kyHO{;bAEVCh7{-8yL^cut4}W(k zr_}&7{J*7>B_}b^3N?J-@@Irs5_xVZKIkR&edZzruy6Yig*MS-L@9LKyvt8oTL6e7U;XF-7Acw zT-(!AGDZI_LhLWo$&?PxbkLMbKaKQAxwg>}4?5GI71_sM!zXo?AYafepXpWxbj47~ z2kQ`^_4i_2o!q#3;`~bx0QoP=Sj&;uSvi&Y3O}aW`ZL5JDEAN`WDjR;xq|1w=EVq< zDi4it36B{$?CH@PFxqk2cKWJX4a|#|ZTpjjbBd5nyGIDV5`Vk(}05yuBR~ z@k{HQ(P+S4`^_*#H!sCWf)hVqmt;>(FBqAE>33ZK+A4pA(>V|wZkWy73DvK&!!CwF zFzi~LWN1Qz?>iYX*LiS3D&4w2@n((<&*J50xE0Sj46`CAB4CWDIK)cU-dVUc3Wk1umCg2nISlhkqp);Jy9}IoVftSpcqg zMDqQ9h&BaJii)M+r?7c!eg9K*MV7Q|&4Ots37lA^BvKH*idAxuL6&;X&Bk6F?KPMF zxf)xcjnr7opK5F#_JE@WF`R(t{|9>P%ZC4o9t+((SB=ik(4{<9y;=!9As&sH>1p-# zl30T@@RbXoYkf$+)9}0BwnRN+`c#ws`(x_o=cMF)C?lDVA<8y9L&@5!9K{?aieC>2 zs=b?S9T-g}`xFi5CU1~qMF2i+xzqkN4P!8?^W{M1K) zx4&DPf<`3nP4-m>-k8746pTwycEqG192>%k4VxgHL5xWqsXf13dG8%@po)MFMfO}* zBSCG8feaz(A>au;0tMDBWh{?VjRblQ2ss!0i-VOcIqe)sx{vs)?iKw)HMn!MRxLlx z|58}krDcmRAkLww9Mkc&OHa!b$B7f~0TmUAmuH)#*OdN)@Af*N`oMP^W8gTm$kAi; z;C0eo7-s+=-xmS#9+p<)vtXMf>FuM%w2cd?xaM0@JB?P~ z=;gD5$#jbI7kQ%wRcO6l67CUnX+4!5vDhB(18Y@fDTM(((nwN#Y4`%B$y!>?^YyS){q4;E_trTBPz}*tz=VBBsa6 z1ZW`;&WV|K0W3I)TT``~z0lw+S2Qv5=te4BvMLHrX}pHqOE^}ejaj1h|W7S@Y!h5{G$M1&}u+5W_c9hb~n zgD3DV#4KEa5VmU8w?H>MX))KBKoV;`e~<+HH{O8)rqa`Ek44aO2rng0cO?zn3c&+W0pbS{`=eiByyswbg^u%s1z$X#CS>nL2UOn#c5yjWsO?pEIMCTpSM zg@j=#2)2`<3!05uIV9hyb7!ntg4LKDyj+kXYF9KOPmhs6r#O7P&*_;ji&@Z$osdYl z)QWHVoG!;zg*kdc$rjwmt*zx-mI_^p8;_am1Rg6aTzsGgMd^tFDw(MSYZ=D*gE+Eb z2c@VF10M2UO|(^i)L0K9D=hErb&lV%0owZO*9?&bRuR*d@hD}^@*niq$69|u7eGW= zS5d)_S9g53xR}{oPmk6H9zhfXVfxb%PUY-N+4$tYVREf`AKnUluT$hZ_hR3JS+ACq zDu{W)!~h_L{>QWB*tQ)XT;?ne?TD|ZDM6hWd(^I-ys6khvTuqfvG4|?&1xbvIN2xxQ79GZ)ed%DmOxd7&wh?PYB?5YkN7iG% z$$b5EZ9?Gs!a#Ke7(q*r{0hY>%xYxlZJ%1zUQxBZ7FvtKb+HTVAwH{2o{OjI21>Q5 zvxcDveKa~a%5VU{H~2syKs<6YDFSNA9ryr@5sO-|-8#AlVE8qjiMW0Zkiqgjk#cY_(Ba_wNX2Dl;Kmo8>oqJK0&8$y7P4vqy(7v$ZpXj4VgLWCuE!5x z0KnC0DcJtdo}P!3ViK(c z77!>AfV-bGI&1?A1UjsJQvU#WazS|V&kPoN!+={;mub*islP!Y%e=@dyZ4_x0{?KI zKx}P!up_p9!GBycnf&pPTM9N+U<3$^9|D?!VU!U@{qh$HKlXhCvYj{zN#E zBefUCT|nAd(HqapRIh&S%c9VK50+2l!!v1HbDP}Z2^R?EDZj> za=@?jO{Oc(EQNw?iJr+@Zi0 z&%pep%Fo}0xJO_6L!j>sb6mw8a;wf_&Fv~^(M9-ZmFrm~Yj9u%+v%};iGauhg~fTV z>&9e=Q}{s*fxMo=nGi&_?kV);;&7Z`7dfVwQ6mT{r&BK0DZhU!wU+%NwSKXN zM%0cKWg0`LBK0Z4kE{uGY{|aOGk`Iyqo%A&#`O_IEcKZ}053M(UJ$%Ofw5se;$yUG z6?>L8qK}^?Efcr(tiFKNMipIJE@n*8?0a-(qE0M7%A{cvy~Lxu{skP5_Trv`QdB{? zKrKN@T%}Orp!{A~xe?eFP4sGOjhDl!k5+JN2j5GxgAA-eE8n>VXNG=q3z|rNrf`93 zzC)Ik?fOQR{Td8?arjJSkQN9Fw{#}(Wv!;=7Xv!g6+8!`zn18*%s(Mj=EHdPGni`- zr*?LX1N^S8&W8YP@bqwHS^X&{Ii>WT3ek;aW^4?|dA#f(@wMpM^vHK@?%RFkmYZv* z6B}QX#zWE^*`GKDv@l%$mmC8#hU~wIw^~1?3C0qX#Bo_=jR3)mLG5PhT|Sd(Uza!i z4Rv5C4bTx62(Uqb=US~*1a5uiE=JD`V{?e+H=b4`3T-UtaP6UfR|PSKfvVH%w(DpV z5~>|plTi#Oh^+Aj>Ec9HDUU1o#;jTveUvM*i^jUTfKvvD3o5|R>ntr-KT-u$x%%&P za8=Q?1Ii2gSBmT`0}%>?+L7x_ct3lJ*}#ntZP{7?qZnB|%BLk?o=8u;YDuIcQ!&{;I&ZnV6}AVTyq)~Py98;2`*qy45gtcHc;Z@ zaIm#lOv9exGD!RsR#Rf#yL(`81=_?7m5wd1DJ7TGkk7R<(L%&4uyLG+cE{!_1EU9j zV{=uSBs|w5wS}@k??P%CP7h->c*FmY%0>G#l}kArRDWdf0}wh6{BQM4Geqc zpNZDG=&A|^to(@D3?4BUm`5&AXptzM*t;?*cO96EcAD_f)!P4}I%iG~hUyY?%%FJiy7 z&Wnq%8AFA@$yWiM(x&oF!$&;l<$v3tv%YT4wpr~cvSr~p!If$TYh-40iJ8v^*87q5Sjif{t|A*{u4`tSFw zOAjPdb1tz^JmFY$cn1b6VH?p0huI~viSO^qzqPoo{v(SkcMjPtK`wz^gR5*K#6vwS z(0KB1u&@}#s}+i{ewD)L3cPv{vw>~Fpor3gz(W8$U&iOBfldzwb&AyvY-Wlh>n?SY za;x3hO6psOq5kKcU!Ms#xDP?VH8B{@-fj(QNdsqS9pa8lfxFl%-5*{B%IKw*NQDXc zG#G;-x@j9>nArB(w)fV?-C4V*VTxA`H|REC!aI}qqyp&LOh-+V-x!w9HB%UPH>yD* z*Rz>+K_(wxCPGQ7b(`*NVUtBy5%3;0~G%m`GH*7Js`} zOBf{a&TgaII#qr7%}zQlKuJrV8YGhY`&v!<{tvWN@?B?ZCTOV!pTu!6fF7w+adP$6 zbQ=xv_Uq?w;Q79>NwTM*rvo@o^qI}}Iqm7?|2BndIvXESxHc-9>4pZ~e&%^~#p{f; zMFv3GixNeFJai_>L{DVAo(owg{wkj945^TkCzXc6<|m<@aTpPAF{7Cg2{t)Ss|j%4 zm8=lU*hVC>3`qWn+Y~Byg7;GC-%OpZpN9OXd#kZ0d_^kAY$EZ3gxqGYozSxH4DPG?#Xli4`7fr*ege<)DT-~#JV;;i+t;`@;Rzyy=gt+Ou?D>YLp zTGsSN^`~iD~N?_Qt6v{jh2t7 z`vqAwRM?~Gw0&dg(4HlSeCeG+?7Niug^S;ev4`VjhK0-I+~{&R6;#+0SM!Mrs+kqLo<-Qaxk&+=599D z!aAI#cQFRh6IbjU;RVROAMuII&h6j(TGfB`wSN7)<7ZDbUIv|if{vO9w@!i$xEv8(cuzn#+$OtAR3-}6ULtHmOq*8YK~b+kfue`RBY z;dcuzzc$ne8-xPCd6d@iBUR7kORZApJi_#(Kmf4uuQ?^Lg<%#N*}87%ONxC$ zB0Y@c7EY7pfU7O2{|E-8+n7ST4B{#-o>H25Z)(&z^k_Br*{7L7mHh%h@pANLe4>@8 zP#Fr;WNt0+`^e@=E~||WW1xu40?pf*I7DgVSQeL^KE3XkT0-OgV1xXyRS0%7z%v~m z5>2KKREY`em~V93_mzSnx`I1799>pGU*FhX0aqxhH4t>ZA`uaV`SGK<^GY`XS6G-uI;Ndi+^r5kAp&vKmroP>5A#9SDu6 za)e? zLB&BLTL^X#VAF^J1AtU0$Qgb@@s6`q^!a0Pe%RWO?-qQ0NkvA81R*@bvukgq#5b{f zP&*wv_7sBczPzTl!TX(qkoAbI#n~pE`harKiUa!Kum&e^uI@XXn3HS>1p6yi07OezwOESwyZkYJCkbOwl*SfslLPD~Hk5%U|jiK~_Ua2G24=M1u8f;Q7_9vZsQ}nVjbi zI6a0s1;wu}I;)SPNtlyNy^RvUe6wRlZqQXWU4F8ww-%@?8LR30@NRtaOYMw=4}%_G zP!30$g;b9-3pn$OSq7D39RmpfBJ+q5QPr?a6J$sg4~)XJ0u*co!@?-@8Njia2Snjl zfgXBQ4Ms5#Kp+h|ej8Tc7|IYt>?1v;6?Cj4*5TO9x0)+9)L_>xUK3I=)Pk%^K zsiU6dPS;Yxq_MnkgOZPwnEY!a-DocQl*6wC$}ChKx&UJF0^Kz^ zQ?i8E^2ASbZL*(*P2!NsirFAAJ`cPi7Hk|Fs4kK`qgvoac0}-UKMC*R?HhT0uA5tp zkA##RB#;6DL(sshR2)h~KJ*>O<3%kFxw-e;9^rG1%tT(e&pb7ob*VyL+F_aS4;>)5 za!U=-?_eqNQ+?E=I>Nz|Ll4crkI{(r!8L(LNj{gOiKXh1g#tR^hynf<;S0tMgEAPV zI9KT_0mD+^e2G_Wofg0<5AL+p^#vXn^VEb+Q%JT*I@o~V9$jyHd+EjeU!`#^kslqJ zih#0kCyWd6VZ}de!4-SI`DOWrJ_d?IP97TYZnv^>osN1_L#xvfGz;&qGiFb}7HHOQ z{4Bt7!MJyp~mMLLV4*3urOUh}IJ{@mE3V0jI;esAZ8kJ`Aa{$58Iwn2ojY zKM`6Vlw7O+&Xw&+V0_ZKi;<;34?Hkv75@`U_9mG!9DTpDWYZ{ruw*;DQ3fci*ZJc% zQmlHuhkod*n#BaEI(uFhp_x(Gr8w77(-@RMU@=-gz0IgV<$JAgwpDx8<6;OWEqH5J zg}!@h`T6MI;}dN{BMZ%nMv-V+Il>BigwF$RKTdjqfV9Fy+qTmUhSBNCG5`}w=UF_j zJzLWr^Ob=X4r}+{vk7W_fmuk10>Cyid{c7DiG0i26X3FkUzL6M8K}j^A5;k2ODMjT z*mG5C1BHHLv& zC#2o!&0PRN4q72Qdaii~g}ASBS37w104UuRifMF@~|X zqC?z?GIA4-NnY}BNRDw=uDe~&WsE-(nDWpituB}Y7D!OnM($^?1Ty$5g`9&5>m@9@TR<;2J8dZLJQ<^P+j zHAQ5{)mq##jX(!k)!?h;qk;Dcrft2!S4pGIfJdq=x@r$D;30Ai8&Yw?=++M|9wCA- zT>3B4tKuJ}S4~r|{!X&keWaC}ecpMJqMuSU^0FDM>=CBY_bI)J@c*|~{qat8oW&aK7Yl!6M!|AGR0oiNio zgf&4tt?0k%Xr0mZ*L9p}t2)usp$dEsGzxCuknTX>dgzZiT!w;dLP-6Ux)7wWDZT4! z)n=&okMeQjg_93eh7&}1`}(w zn^l|mz5D`~-Oc98&V$5l2f*?1%_-K?3ls9lhL4IGGNF|ncI@(q-rtC?vno9RH3}#? z9yZ#(eegH##(q~)Wyg76qd8Cb}Yc7FYn%*FQ~C|YJw@y=)>u6J~zBpoSa(CO&!v!bl-TxfU1#58zl=+$G+WHo@O?4|kk zDL4hjY}SS9`x+0jbvH`~BT6Nc2kKlsHv*h8+jzQgI6PHxA1|Pc+=i6)zF{0PTut_q!-x#zMxcp6M|MQtiQ|9W&yvc%#w z-*cn5hw;twYLGWsr4BCK{m@;icEs#;GLK{gCYl9i|Lu1A6-GlidLmW8`6Epv6O9p|CYt|-!ipw`&=G4MR=R`jFA1I-j26Pw?m()QP`M# ziESpU-ndY|dz#u9av6O}nQpasTRATuN;bGWNKaLz`zFecSLn!JSXi(1_O7??JoSWn zTpOafwsxYq3Z;iB1cATu^XR+Pmofcml@ud+JRGuKo=#i zySi7vWh?3@N%pUNt;D2`FvF`nEe!X2O7KeokYsIvB&+Ztn;d>P0y(Ns2(G_g)4DPR zhb#bcS+%I7taX$rZi~bGB}XUoz=UG ynX0fL3as>R+l;`3^J(Oto7q8yR3kF`sA6h{b%tRHgq>;BL)Yuvlk+180tR`S{HnU5*ilvSL?>!JQ92z>?lBg_j(_lA$$8OSnBaH335(;5+mNG?Gdqg=GfH!nCG*Z!|oVOzEOu`F~Nn$?ohC(mdOcF1$d}%;AGdc z?5Rm+VktX&5CdLb2xzhpx%LDs*p|lZ+wz9?;RZMsF=XwQD+#_ zW!Wkrc7vfG7`EMDSg(YL@ZN#t+MU6FApW6@ZvX|ri_ElrpvNd3pp2lm>PF=dg4DWl z^XuNHUZ5cST?CfQ6yOb!ws!8{|vW9UMbb%_vfy>_Tl$P%l?maG*Jnj4JJduyv7mlV0uz0SN zem3GzsXNU(Wu_bIzA#+vtSW?sVR=iCGvr3hyHwf7Qce0QBgW%I)e=~Ot0ULxPjx>$ z;63cm$As_WZDH5l?M+70(L2{DD-nyu?KAFPXLHxuD5LPc%Nup4bEl$3??}Cw!)>Bf zPMqXk%Wqse7H=RMc7xpCzUtrC7r>&C}< zj|*o6L+eUza6S^aZbUa)t~h+CiP_5hl5rfz))|M8Jh=>qJ%Z+bT9HTi-p*d7le#!_ zUQ<@yuywA*-65QVsmWRBO@W(b=c1Kv)8$P0>v2`9+P5633g6Y^-qP}?4-J0qqW8(9 zJgi7zN$^Xi)U`k=iVK_>3mFok6q@F}t%jkSRIW;$a0$*BY~}l%C-drdpzyKxmONGH z)T$+D<8!}rNIX(~W?0>&!B;)f|ASzklJ0Adem(b3=cZcZ6WMa!^mDmX-z;Bue_z;6|YJ-)kz|3nn->j;M3=hOX#qBOcOEqk%oTeF927flN*O%t&qJI703x(x9)Z;)!N zcf=hNrWXmzTRLh%bJA@-?f`t%Ij!?lz|Bb$m%J=3W!GZ*sJF{8Guy7Uq;Gr|_6xBS z*czD@o>zpv9M3pdc>>_CUdJH1xGtUUmrJf>``fbC z5o2=a=vD^qI|POA%r%uO4iAp?8%PY9Ne}GBU_379x-Pa15823QsLdq5ze4+krh9P% zr5M-x;AZxUS!E}~Q_O|Mcp|6i`5arIw%SId@ zQ^1wW?WI~u+UpvSrrP<|T2sY!_I+}~XWKL>4Ql7GtGO+es|1>FX~r+`^xBoJtLN$9 zWDgcO$#Yc88`HqMs{R64jr*@oPdzYSCq4QUTUdVBz{>9WyAiO@HixyXxl7j47WSBb93@5xf0JCzg5J7Uf$xcYcM(|P%v zk4~043Rai8GwOXZ6opuCg~z~$H^Et3PObNd{!3I@#hn?sF>%5zdXsg;}0 zU6*^}5nIdPoT?W~GhNihSmllTmRHWZ&SoDo0h{*)@@#wlSHIgI)w+K>FuXS|n;~S* zEle;`p@Yq>-8yUGq}x?{o5hQK987Y$SaTOkW8E>FB5Ld6-KsW1hp&N?D9(sK3Ua4Z z?ImH9)CRe5Tswps`-z&idBfc4Z__*)>+*1Tj!&TQG!5=VjeJ|C*}c>Erf!G5#Gm9<(&F1X z2Uq;j)yN}EZ|}bJofj;Rr}}IjkBy%6sinn%v2wP|5B7(wJ~@4w>zN#PyET35u_q6n zHkfB~d?Q7!=F9BM+$Zn={$HP9U7qNbd-e=+ExFv0HZS5dbh-*9mhfB-8*MF*#-F`$ zvib=AN%+@^$V^H{w6|CTy!VDI!79m}D3`o{xT+!^+nVq;7Z zc2%ZYC$*Ztq8@%}|Jb!Q#P0!RmbR;2k95=#ZQrgnr3l;!Ysu%0fx9InM-P9%{&A^x~BVHCRHcWhMx$7*P09QH8%P&S?xo>HC(vF`Tio|dgjZZ-*QE5RU@ z>81iZ^-tRbQ)}$7!cx@+p6VkBdS>avZ~}(M@0VU*S{cmGP4Au@uY}s8KG4iHM3B7e z4$TbydM^!m5bfb;5&&2|Q+p_I;VdUMm2XA)^H&`zCv0lOCPVvLTMQff4?LdKHyq^) zFbyTP*DZeV^gH>!$fKw>OS;!vIQ0@g%=qha|`57-!qC8`EVv0NC3 zYh@?ww$zSZFu>HQvXyVN4&!HoP2~Mpzi9Mr?N2FIjHaxxzB}JDU`n-?;2jfimf)i} zx_G96Y@1v#JW|F}f*0#KS40wj{JYVZkgL3CiCx;Wy5!9f?OHM6Ip=1n+b{tDqs7U?2xc*bj@7_BL$&&`H`J1#d2k2eQ z`REtk>8r9(FG6;UOD$Vf6+Tv4|_F?dFi}q zKQy@^l2O?sFJBtAI{&bTaJVkmW1k`X3w#_dF$Q4utmhiaKlqlHB1xdEP+0w%>LXZ> z3pe_YTboJXXM4yR=N~z!;^U!VpAliO0I40@PCmSQaJC2T9zWbx&0f*usRobT`}-db zMt|f#{rG)crMTI?lcD<4omj#Z0U!MYpBN=y&Am6DeVem}gVhO^Ojx`8X%FkH?+;Jn z$4My7yiPQ@!Mf<#XS>*t7#Y@-MAm01=qJ&cGqs_;Z`T_ zwSfx$DVx;Sq}4B*p9)U9H5|Ki-eDU{Rbbug4ey?0YLa;5+(53}g$2Tg6mD@_m3)nVuj~)N*#O?)`wX-RucZ8&*$huSuq@}$UJ2AKbt2$n z3PPKW<@y@DL*m`9+avA5pYf8wy3H(D{nlo7|GSs>dlR-ZNrfD50uO65Q@#L0r)nLa zs5M`~ErNuIyiL!=-dlEzN z>0tZ2wy-D6$X95Y5Y;F#oG-?E1wRk^c~Z&3)6e*}cc+Zk&7YNM|8dQqZ3$fQUy5zE z)btAyxOA4ziwstQayV&y}Dqn&^YC&tfL_VS_q~In2 zE=3`>j9gvJ@#T{6j^e0+Z^svXtrHgzfS1_g^UiVd%ut%LXZ1QPojp!I}m>Cwde z7}Zj>T)SWZugY)dgOy%ypN6XV)0xxo{43e}!yr{7stT0Waa}0g;-u$)gNfUbj6{6lQP?&08r-X0L70BudwKlpgce)Io-{=V&OF~f1m6Vw~t|}Tg z^T7g>&pN%?zBDNe&peIeJ5~)P&10)ZB|x%v%`lh@9(8TXfbMI!l-@bYEMI z^X{ZQKG$$(VX_!eJRQD7)Bh;d4uy*ZWR{i6!l;Zp?66a2F2X(B!h?-7iP(-1Z8_f;vv3p_zk zxxKPZ_ey^w#fCU?)n^ijo*Lunf#SrEExyBMK%p{{Xl zVeHCyej_j6A-Gg}Xs2GvWS5e4?x&S1QVHn>K@dR@2?^yfDd}}D`Bo+4{CN3T?Ixd*`9Mz6>tiJqZx}dIrrnFHSX*6d zMO_}G5H34X-pmytlG~xWxqgz>y_YeEK0x4c`H_*~j#@E1E-{MkN zoxFFUnTx#&L|~RVt6Tvz?PO) zDngH1x$sQBPQI%yA1N=^u$KJ#A@KJjPQl+kPcnb&^WldJH z_RWn8-J9wgW`%}olgxf=i6?{mlcGZB*Szk1v|kh@gV_;oU5YTT?( zeSU6M60d|w)nicQAn^tE@9Nos@B%3#Udjx8^T7xo8w)Abfqx@_D*b(pN zPHRWdG$!G|Y0YqM6oai$TgBaE<#Ir`Z{!;W>E;TVl=O0vJ&##!4KXkjR=&flwl7Qp zw;eUDv!Iy^eSGxkj+>6gtqa{Q8pf}U`>I#5-0T)2oUcm^qoctd{_u7|?dmj9vox*< zbgLTANI`@vlaAu06mbG&Jpr{P;h}EGybhJ@P2(wt4;)Lt=0e%{j(anxTbELLQ+yjA_7gHwk@vU3m^m+%ao#KmgT(uG0NT z?A5L(phD`c8dmjZ&<$-aoj8y-D((Z3rB^4AyQ41@q{H2_51-35XjwI`dZw#E-UtOp zv}iFlP0UdK2VL(-jX?T`HxF(=eDimceJ;y=alSEO2MeRLr@lQoeU10k^*o9Du9pZG zPu)D>VQ*s`0hK*Go69(HNJ0V69Zt15hJu4q;UYx(qNe(@1{=w$f13AK4R&(L8hdz3 zZevgFBUTMi&Db(+6*7`=Ou1`RCU2kNQ~q6o9Y*^_f}KtHA0$}l(+EUC=^0m&VJ9OA zfM@x3N*$R9)R<>PET6{+jV2NexAUf_j%Tc4zerPRe1^}OntT&ZO~^qxI0-!18`mLO zmV%HAPi4GmzgGRcoogpt(3X_$K3l5NyDCOtmW=(MrC0x3jVGTnh|LQpZ)4={^_}SrO-vu^T8Q95+1nHzA2m~)JC3inZ_&+T&JO3zZqkxS*q`v;r!@VFJ*f}L7%eq5@#m{DeDi?KThNj&?lAzShilbywy78i#nD$$)CwisR zxUc#N4WwDFi%Uo0$}Eu=Re)tR`}h=78d6uPE=Qa}(q@vH7EYE_l~9Q5XIq-9{A&-A z=4Y|rdt=pV8Q{6|GP4uD04)}JKC0j5sp2*kZU`@pHBAa=c&L1NaHFr<4jvXR9DwR4 z>7USlxW04Z9YJ)hW0w#7v|7uGthsQrq(#F9Ugii2BFRV_AA7(xzv{bI!SG zX`J&btUPiV3eh)^7J_z&dXv;w5hejC^nT3-2aDLWl9h3Ng2{1(;jNh~^1&jn^X>=k&yypaiY|PV2P<55sBb~QsCUyf~((cht1bf{7|I90@F^g>dLJ} z6KRxQ6A#^ITk#R^e2v;pWt$twSo6I!+JR1$o(4A(uAlH%;VP$7Nm8Dx$`# zy0+niV(Y`KS9e2eW7$YpOYThDgI32pY8%K(z1o}O2`LC2pX(!{XQZIELhuJM7~_5F z)a_(~2V>s26*m$rjG#iU2jNE3lw9SN6Ha-bQ))e9!w^A;aPgtOSoPiaTRw=YcL0S* zFbGc=7AiQ%%Nuq98R*UE2>QY%XL8?rCn2%gN!*Xp?pSEAKfiC7SsJN17+BD`Vn!)t zXV>4dB&UE18F?0og`o}$3!={Mr@hM>m}pQ{#c(E=Pc4p9RfM+anl&xBkT@gd+GYA! zK>|%|;@c0cMr8_W7CcnvtkJmnY}rr9J?*kIp7p0f#F|LZ&kf(WrA?*VsZKDnZi5`q z$Os+=k;2y_SsNscyHY^?OM3eX2g>CtCjYA|u%mA(%S$#++mnEBdUNB4hrtLBIuvc= z8;qb&Kt+e>z4HNlW#Aa&%c8SY$(h%}v_+a7(z*n3SNsBPYfGEBX*Tg^?@Z8A7@LGH z4zBDEUGW@tcoG=VEg(u8B#?Xe6VefR4DBg7;&=r|MI6m@L``!(0knH+6S$x&h-{oM zT))%pSW9C)%P`(4g$6qHOqb-%{noW}NCA{jg9jyT_Mtn)`XO4oNhtEInFP@l0-iK; z#-yKu7t5hD|H|g^RXjx=D5a3j#>J&A7KLwR-q0pW%8_@8m>$;ghZG!IV(4+sTs3e! z(HcGtLAReyzXN9jqUS01S$xVXhe{D1I&P_`uNv&+tNL$`T-O%*`mBv>67-uKgEGc< z!(<+Pc>S*qMk?IiY*zTbaftXDMS$k8vqb@-gExI(74hRY4#cBtWgL-wef%IT=&kK- zMrz=`8Y-F99Z3G{4(ga>L%33B6(a{fmhH;vp#AAw#sPDBvrw8N&Wl-&n#_v%SYAs9 zuU*|^Rd4b5YioIQd_o)B?{Iw|7ZY$DtJU_)pdYkCj#D6ab_s0q5h*x}cNhw|rF~9U zFNDRv__$cCkq3M)%g($wIVPQ+@E3S;F<~*p`Se+c5_lb z=DQ?g46uovqqJ zPy>~e92E)@QTBe)jA-nHJM{;tlRTxST%$Pf+I@hs6ZGU{?HV+r&%*<-vAm$4N-xGq z2J%jP<|QAv>BApW6OJmVGYDZ*H25v=pWLt9J_(X_`~C)5^0w!hku}Q!Qc875(h;41 zxbo8Jp&K`hE(s(-A!(${J^4E8dY5DXq69;Or*=9s>Uz$w{->=GGJ#&VgNjYD9Gx?i zRSQY4oN~WR*IMj9wCS^6>B%0lLES%|o7i1;j~dd_)MR3U*Nv<*^`dT|X7{~wmQrb< z(1k&#k_T1%i(b&RaFX-Zaz{tAG&l(vW)t2WVM_RlR@!N^X9)SMyiE+5k_yQ%_IxI_ zE!-&aSRn84GT*s(R??qJL4ZKBiJ;De#=?c*bi6Rdm20DK?=2MPu|L{_U71|Au~l;) zlod`!;>t*YOwz{M>ZY|`jZ)}*`rRG5rAectO-2SssS;tr`|_m06GLKauXUP=M0X40t4xSO}8UPpdF9Iyb03vg}4}TD$oYw zVyy7hhYI)BB$)=QkNb#-SGZ0p&Ly1yHNpH#IW~NoQ>JD{kUOxAtc7dfVLQF7lhb<| zvM{n8la`*U3v)0Lvla^{@SjdjT#-|9I?K$)+x-v3)d+>Rm7c$ftA=id*xCE1l&(bK zzH`q<|BS)ww%>IsDV~VGrU=X?2D8#CZFUvfR4ANaN4>2J5L3a7obdf`>S_bCp+|7U zVy!vItFSH`ME+~+*&m)rH0yORm@$)-@9wQL!)vRuwP&-hpZWL^?VdPG1%_k~@BMDs z&etbr@XgASj_n-1@j!B&_Z* zlUHYRS;+-TsJ`~=Zp_?#QsLYV0ocANi$#5E`x&*J9fYnBS0;b`OY8HY^V%e0`25Ot z$&#_X!T8N!eIjX*(I)%<0M%vFw=C`jZ}DkqMS~AARIGqD!DG@+rnVQ0SBD zT|Q&0ZcUwjB703CY(dseb-DppnhRTL)%<(2!@Ajh=gbWl$jRuDrLk5eUmdNTqvVIi z*hWj* z7|15bzqdYCz3A}G5`r~*IQk=5qV#a9x=E7JrCz6FoGf{)&C|H<>Q`Lsq>^a}dH=Dt z8lbZ5TlNXfqYXDr4ohrt29)&lm_b#xwM<>kgNSetQ=scm$4cj-WHIE>q057WB*@32 zMW1u9t3V%n#b+*=bxgx~x6~a;OHM_dzmB!+aoSJc{c26T(dp)6jlnjHRPs}UR5|;F zy9%u;jl`^ioeaIZjy&|iRN2eL^w3ngBTCNo;dxYCZs5!56r;i^7}DTbZCU99(K6*r zk2{v<>M2v|PUmbaF-Jzd%@=~y8MZvb0y$EtAD&5U#i2+_%UG~9t%OxKB&2iqQ{^Uc znW#l1(<+R**QqntEQ0yhCx&&7f6C*!nV|hCPsLuX77`Wd$*X7hb_i?Zje4mOBU!c{ z@PCt(<^;?cbh)5!qB^b6b(LdKvWn_|#qbP|_J5I9nbm(vt2oPhj9-hMz`-rFe_wNb zUdDfF0bi!Xi>Y1bp-9)M)LO{WXAP~^ssLJez=Ga4+K04fcMG?4dbEk2El`1CM;6_1 zYx;8&Dj^{HfT5!T(#$WtP6E)pvMs%COYE9rlr;eItVB(?WqSG-l2g++tDsA)@KXA# zGg`m(5L1)dQnl6P;p|T$ZHgdud<-$1_|P_#>`!Xp4q4Vo{P&Qtj#*{PLNk{+o!?67 zP&L7N?v^&44)xTy5+=+sW`7y3s8k{u3feyU^b}mqIn_TJu8t_+c-$j1WTfyPtOtnY zO@{-mwwFQnYWH)ALC^aR=Msq5pM+Z+FZCDG+B>cELV)^Ua#?a$T)7>z&s3CvGK2a| z&vqOwpEY28zAu68-BX*yg|03lszP=yG2_5Q4SO#C=69a3k^X2V7IE9)5$nusiON4z z)z7lF;jHogW{g|U5_XM74~|?0k_XXEXx8y}Y^n@S zhATmtk@rED`Tj06W=3uM0#R?^1pj)g_W1jF4irsAhl9bzCl~J*kG1ci7bpguoKd|=STvg{3u&MEZzMr`JcN!?^3smS~T|O=4 z7k1Jbzc%XM$HQa!WDHf$ST7m>P1C~N_ETFoORf9;fKM0~QSn+Vl0BN4AR*IkXJ_Y@ z+eizg0i<@=8;;;p`#p9>T4gI^?}`On;1#x*oy2d2k#fs0C9#-HYHx0XgY!`3S>!#r zPrU#>6&n9dROSB{QB~9MKZ>f?Vt;Vj*TR}Ntn)DY8Hg;GT4 zx1Y~cIU}>s#;dV@h|{hUHVtbx4Fu04IUMXkhK}03-V6oKn7^iq58m*!(dNg07gHBxowlh! zOx3?I0hSV=riRvzXGjK9J+@O$|I8FX%_1rWb1EmRH={-ur31|CZAE54CP1WA&2Adx zy*-Vtu{Y<>rR#*5FIw(&alWjRIlA$Ilm9JL(q;dM?tSsQmalf`X2!)Yl-7?+J%h~) zki+=H9RhaDn}0~Dh-!+NFgzheQ@l%tqi7)bi_AK16FC;47ytB8d3a*+RMf9(DuFBx z{L-I9*>NS^t*KLusu|B>?;$$t8h4e}Y2Gcj@SmU9K+IEGUty2tg=y5Cdsg-Q_I6Ot z@(r_OQE5;mkD_g9j=!+oiKOlCGoX#m^-!&NvNk}QBa4Rx@A^(ABBgyuYnko$@w^qnoq}?uQSYc;F7)^N#@Jp)os^s z2aozBm*y4mTJs@kbc=&Ao6}S^Q(FFQ0bL?o)$vBB2)2D)1&nf4@iw8tZ-O!qBFUDo zYt!qSfg$feh%@+l0T`mEO15Yx3UnMK&2Vphcuupf{plVgAxMVk?dXcFKe^q7k3^%* ziEIhSHygIyu^G+Tn_&iM^a+a1gcwO?LyFUS<%7b1;_{X66Y|hWgo~4xw z8-y#oQrQN;xOAy!QX8+x!Q#GaeE+RvIJ7PYQ$6wTMC-W!;s{VO1sU(nGrnhlR09wk z;qFu~>$kVwWk=AU)`fNu&|c7>9W+S~*I{(8sjmgmX6&)W?_M&uZK7qUM(&QSIoaViP+KoI{gThoHy|!iLtFRFuuKrZu?$W(}1nJ}Qq^BYn z6vA>r%qw0RV%QI?x|0iZ5QxY(5_9PwW^L(w5ef?eW(!(KDNxiyWpvi{&PnLunLIDT zhSEs<3uuNJ=dy_QLWDw%kXGY2LTo#yoX{|c5F2S!ps~i#;$(>`FCs}gXcKbcSKHu; z&wy?R%`uxhg-q}rde2=u0;E;{QkU3?SUjN9jNsFu(DB|33Es|MtFj7=iof#!Oo#a=sl({GxJ=%A@B|l-KE4?PKNKQD>2R#-VY=WFmk1W$R1teH{>izZ4UM z=`(jkgwkSy?uonxASFWu(+G+Ql=Jvdw`g2oe|6676p$G=Kw?Q2IM-%<_{JJopgIG! z#Bf*-D354zX=K<3cE9-mha0?3UB*Y?Zq^MlFasNNLxC`j2+EwMLZf#C7)V)&0m#tV zFt}}tts(e%238*y?=s}tA&X*XNx@mR4V-1W_mj+qk4w0WBlCkupu|Az$y#Oa{zar;*IULYeh%uj#<)*i>ofkR z`)L)-2U1`QLjr$oyPq*BC|d~DrF9=)GLsIp?x(!&269T+GSilsT>-*7eMt>9{7Bo$Au9 z^*15eLEHATqHhO?=f-q2QCE5+NOX`Qjn$1Gs4i(73a%)* zzYts{KW~%!i4=iIkmBs0tL_@FiuC20%g-$eT?;|9pQ6eu>_;((>Pju?pnqZq`55w3 zkl`3(;km!jTaY%z#ybj<5Y7Q?RdG08zkZa+rDOY^000WZvPjq>!mUtkj;~0sNl(jk zbqp}#p?SiCBPAk}v{>96H9Au1-CR-6s8FhsOW)*j83czb|2NiTdp!{q8Fuxv(X!*v^fcgn4r7o z0i?R$v58{Snupsd*;WRi#|+WMle)FiZbejUtL<|P;0VAW#rUdute@k<7kE)eYX!igm7BM6(9wH#EZ+yfSQ!;aO!=w zSyst_16fLvG+WmDb!3p$sm2c%L=C}6TZBU+C(5Qt?;Q?8gg~4F))n4KI5ti;gD?(k zqrXtM2k|*LKwf$z-OM5dRYxnzqh%xC1Zui`XJV0)89j#`@v=~ZHX%G?;qF`L8y(Ul57D?SKimO8o^v;WGvcn$NBZyxCTcO& zRWWGvt+;8;nbkiOXr}T+Hna zeQ{d(*wN$aPFL_me)KhToxRjnIV^;ujA2P)nF#ovloH8p0nWs!>JCYS;69AC6hR&tt|t zC^@F(h*8PjV|xhuKAzChvLb-5$<3;SaP{K7z$SkCWJNU9Pzy~PiRB_%HJvw(s)Tkk zQOQwecXsTJ+O{PCHGd&cEf406tJbMWv(m?3j;x0)u)%#e@<@*aU#8U%u5TA%7LLP4 zo1NR$cY6HZ-Ep)Yydv4R&%jMW(pjQRa8&?6xp24do@7AR8{)dH8fcI(MCd{16y7al zuP+i$LBav3jljbt$vcB9ijiL&k3&F{xE|3z@ca^oZPJP`aJrYFRRLuOB9q%z{itsTc~n# z%5$N$%IuPcjy5Xlh6#cyLlfgy4CJ|g6JEwK1+WW{sa_ZM7kz|@u(ZXOwwn#Yn(EubHg@SrEpI$I;k#r3_m=03KZiCnzvl9zL<;jF$$6K(anKO(I~T5 zv%rLWsluJhasX!&-PDfkH|u(j zT8d20#~_t^R>lu-Ijn_Oqi{707|I?oPc^ECp5%srE;9nUY*0oD6D5ewsFW$;mBM38Tpv6 zI0|i-8lkIkggB^rPgj$p;h7!B*8Z*tqx&hX>~1K6R@qSY|;w8vzaAf1z7>{*`X6 z%LRe}SS9bBhmAL_(UO=5=RNFTVKOuAs`EPuhTgUX2qmvGS?mWh>pC^Jw0X2%<=E{u zQ0ysqHfl>F-A=MTAM0d*B#~?g=GyTb#xPvVOT4kNCdDmD5AW`Z-!^7xpAC-C-D4sz zvSod|;sbpxiPI$~$e9HnY8lV0RpRIf;i5^7Iwyaa1mOgL04*{y9Mc^OgL)87)ZRFd z0vyRGJ`eu^_P1q&x+`asjgMNbKPSzC^!Wi0FqEa z6W-yRGauTRQy-c7%5k3oNvmAUIX5DwMUTtx)&RG-!no)5eUD;&JtdBv%>KX_3;H&@ zyJ?&ff-F|vmT)0Nv36VT<)HLxa!4ZovHbcw+!|8#Vj7U_Osk1(xVS43MJBWglq;TK zJ*mrXx`uskDb=OV6Jx4?8a;w#N(8Btxj=#;il1MJCds5Tw>c4r4HA&_DBbW%RVOd&zGkA%HlAQGM6a(N@!eOC@Me z@|k&W625?cFl-pkXF+h-BfW^FNwZWxk}!i$HH&!gtNCn~BrmA)us%I+X~3>f{PGjC z+`?p2t>{wAXtwrb)p0UdDr95=IA#gpUZLVrtVcup!XE-r5Ca4c$o^9~0);9@y#Ai>hSi2Zy_57pR?Q!dk?L`@@RYfrAt#iL}$9) zm|4MScD$cIys5}5X&QoC3-?=5<#m5P_mBsm(89U2%XTkG?gQJoqFw&|^o{UB0Y+#l z-DElA_?G)N_{{1&Ebr(YGn|WS+7=l~UsW18BS310&v>N}^C{6uh_Us~3WHO{LhV%69l}wJDM| zA3++Q^86FFILifoYdCT1+o|%Qdoba)wXRNu!zZf7o*l~64t+gXg|Kh0-in^=zxj12 zX(yFcP@Bs@9AJ#yb;I6?8Lqq4&_7$58+r1LiayUVDbi;5a_+%28L81+3+qZV7G1>P zMcT;dCSI7$_$PR4$H!23`@{8ZkW4;ID!W|QEsg)MdfKjwgT6zmZOX<7g6>ANVNKST zzE)q+#Pih^#gS1&ZiZrlG>!(^7xM;t59!&g)f!Gh-}-9=Yk{eCTrC4jUgHQNI6s$z zBtFv1$w06ha=)jBA0sxISRxyiWX{u;H=WEGDQtK!J|7zpj;a;RjjP0vj7k~%lNQ_c zC9Ezpc_lM4ZqEd(gSn_fIuB7-%cd6rkeVZvFkz!R zSLD0R3QTA`oKso)W{T2<9Koj2R*CH$wD&-{Ch2Lu=pXs)fwJCHg4`D8%I<{}$fpRY zfEkq2dqVKgviz$iQ)wIeGT}&H6rR4bVJ)0WD<3D!G!5nNpy6b_|C)Cq{yJ;YJ`a!3E6sFWjukG+DooMM;Tm;`0kHl zm&qThPvQcyyxXSY#=U%imIzfS(slhQ`e57I|3KP+Lk4L9#x#>z&q3HJ8?ZUbI}>2$ z$8`Y}bA=lJIp@~BgGY-*CbMOtXW;+6*{H|wbZopzH**Qt48RT^3C>#50KKJg=K;2m z5_Bmbx}BPKiJA4vJeL*jdUV_>`@m}1BiLS3FK>^6T%n@=$(q-giN(Gdu1mo%fa8!& ze?_H>Zw@kf6jq8KO0xT}{z8(ykhv%KZ<1^bgtjO7&-8^&ku%0V78{})*ru}QXD=vV z!FWhA4P7tz!m$?Xr`j#~g3d+tm zNFVO?m+ceJ#7(JJ^fxWkauBE!2F_|)@YVHEy2xp-i`Uc*H^u*0%>FIVXP>MHvaP4A zOnq9p+!IL4X8-Y0&c`m^qqcf4#hTXdi8%ENarGENz(Z=d+){vR3`b^(>#xt1PB*ap zQ{eTd*5vam@QQC=T>wxF{Sd=TQYVitBJ>-u!ZQWl)A!Pf?6CxLuwi}>{;p^i0SRZqB4cU1yLbnqejL`WB{ba z0-fHJ{3lF5{kv9+qd z{2)2j3@%Pd?cDRCgyU9@DGo%{_F732_edmfriq7*p^?C@ndZ}31CKKrGO!Z`;*6T4Z5F8frcyi$=&Kl@hTG=y&9CUt)Rz-n1x6 zd_K{uYeAh-DTE9Go7~%F8tHWrZeXc8B35ycXMtJnU#Gm_WW)Mq{7 z&L#A))c=EUb-MP5y;039`E&`qk4GN4oMYKh-y`&(ii99>{2+bn)6Iq-Fg!3vM{t&U zK62>@KVd9lV6l=@E6DBi{%DYGuey#jEk|+`x*X5gPu5)|o^FpgqHtg&XL14U!t>iz z))y+ZC8N?s&unlRu%Eo>9+{(?GkF<%?ydVPK#p!fB7)5N zzdv&uroxXxbGyIT+HZ^N=<9NjU7%;>?NQ-|z?&clO7Va=18{LL2mw<%1<0WK?3>{b zkh5WNF-n-*&9 z8NWE!%)b+BDGx3)pMsL3TFCMw3@KtS(NJxe%y^723YPD6UE(HB{$V|Eby9}gVv~;& zCM1d_6}hqk6Qp567&1$r*)nx!)ujgi>!-UCSaEgt(9xhl)^si0AHIH)yH<>5(z|R) zX0qe!Qz?EP&@w%D0VNAA0s=sPIXd&h)TrPRjj)M?>2T4qY( zv?MN_RW6edV^JbEufyrCx)-WoBi0U&6WHFT(L6LTHt{4N+#irNKyVJHnp(;JTCR24 zePmZj7ld@-i6OK-D9JUvu;2n&IHLKydpQk9%KPJ2kx1MhSOPTGrJM4%Mqg(kFhr+O z?)_j=5Da!dwg-9_Kqd-FXP_HJYr)vJ&>NL^L+R6JwolAH0XYWhVHnj;T+c((3`tRf zkOLs>?fl0eRKPX^j7W~qNBT-s;CiG~YlX(aPBZZUylD)=J#U8k2xmSlqqbn~TbxgZ zj%iU1s$w)W%h89f8=wy;Q|}W(Vn@6eJnANRah|aAq0J)T-@ehV!M=kAINakT`Kf^qubP#83t2xf&DgU*0< zywmBV%PI0O^SfBD*9rX)*zQ_oy)exTbd5MfiTdq51+6P9Wioi?apeF4_i_hyXPVeI{>E$O_f)05D(qB>& zPA~RGJA?&?!W4v;=ZJ8ExEWE8sO1v6akqW%2>mc`0$;r^W$R>0JIqdp<^*`|jEcW2h_eORJl> z*iTGkK)nwskvX(np(V8?IpmytEt8*4EwRoFaw~-CwL5#zQonO;od202f*lQCI}b?{ z0t`ELu@v^%W=Jr5J-RL&)1Ks-N(M}=38>rfYb`C5^+2(J{{uP#&?TF-ESre&1!1a?M)8n>?Iu0~aV-EESggv{^xNmUnYKFs~cAdot%>?q9&# zoX_m+vrkfzHGle4!1b>hVu_>6Ub8<@%<0wcWO%LMn>Bx^`jE#A^i2b@v4BcJMrjZm zk@>i~BLn}$zySXXUiJbYEwF%!O)XSsGz3G0|J}bJfC}qkA3u&z1q4i>YruYhsG{o# z8enQ(K-ik|sl#CikK3VrEl0J%fT`Pwk}Sj(rm80HU(Lbg=))R`~#@g{OUFwHu`*HxOa6|y3I3I zbU50%zqmPKVQf6lOsC$0X9h4aqHVpOxSe3|513j`WFZ$e5WA88 zKdcLm!3}aPFTaIH2dhv27d7`MO?xcDUH`TEg-3mo0-Ks^m0s`M0&}fKeAiMH9gd}a zem*IObI%%+>4#YX7eXult69N?PYHeVG1z6F63m)U{i5Rr{m^k?LVb|n#0F8&FM=%A z*^V3h%6CrObq_IJ-wZW^rl17oM8uK*hSTyZM><%58`G;OGjf=^hm7WiUWuc=P#5ej zpJ)*T!CLLc5laCbSBUHWtPV)-NU2@^-D}>R1QI;XAphsA*Jl^XS%k0A5b9=SKu?8z zyqk=}QN}vHdlh|tufhNsI=u4#kzIkL>S414IC-M$cWIJ6)L~!_dQQimhp{(?`TbY6 zR+py!2V1+^THAx&R{@|iG*s#pdyN(MaUrsKf_+N6X)Y$3{_?g2yJ!-(bJJ1}{Rpd4 zsK^QPhbR`k^?{qIby0Bhqk@md#kT;}!zU)q{BJ(+(qESUARGr-hr zx3I^RZC9AVXLX-l5##J9!_I1biOiM77!EV5?6}o02QPf}XvzX9Ke% z{ulleQM=iI_MeE_)W_@F0N5ZRfb;-GvPU>{k)e;GRNJNtf zw;4+E)_27o)L#0b#6BYr9T7m_PQl)=1-k#ytpFBb(!br#&HBP*v)-f+^uV`eB=@|X zMs31gKMQl}jSy>?bXUmZI)MTOm*$}ei~-)%7HLC$le`^v8krd6K)K53QXl<&R6eLl z7EYhxE7^Xk5E|XjXAL0j65YRow0ar;5Tu1;qJcP}XH^Mj#nNe9 zqD^m{h|_si#9F{f>-94d7Llyy+A90xp$BRsJFMV_^c^{X`NM*3bmKPa!RS_ z@R*Om={fjav+bh$soCzx6qT@i!Q2cE{^&5Gd?jRn_uMR>ASVqwSZxcZ90Q+;y+=-! z?c;Tne`ikMi9!xXoj~spF$jX-9?}^R3biXhQ691P>R;EwyK>0cDCK%j@tp(= z-*D^m-HTcO(Uw4L{jY2ZiVPKg*b+C zlz6;7pPvNCza^*B$$Uu1x$cyB}jj#Ej&LrD4>1P!h@^nu{4x-7s*#9&I zOrJoQ*FKR>D5?A#j{P73{rd6PCm$oD(8gMjZ~}anL~-@ZtbaO`Y78^pLDZxQE-yY) zU{WPC%>|49%_3?Or0t5Yh_N4j{xFo(01o?4_~f)ykpS=wBTQ z5;}fBwOMq~7-4o*U94Wu>ix97u4u2!DaZue=qwCI>XHNWA zw)V;?wiO)}l=x-$A8M^ehU3BwDaCfD#TT;ex-&iK^#_a|sLci;7*!@=vkjle${*Dt zkPR@m3#|3O2uxS;GFR>LCXEJO)1O3F0X)QsK3pu9>H(p{f-p##8!WcnELU7=TR^&xakA;#h~$SbKuGt z(luT?J%4oy))wuNA*mH*iOQUZ>yq@s0wW>L4|{^H**DeWHnarECodJQssWtNd$t)g zO$L~SnEkj!h|EiavC!i=VG7|nbE(l}Fw%#sv_5vuNX%i2fV5q;)QrS@r9GluxM)-N&J1XWR(A81B5eNnf!+Q$`te^m zTJ;?k&j}BbO#Cypk^$kaO!ymRB!bxvEgj)-M-}lq)!peE;-O-S|3#9u{<9=24LisF z9lN|^VD)xtbZ}APRF6^NgouyLY9R_>+8Xfl;Cu%#Hc7^Yw0gV3_gZri#lPZc2mXqq zy_?i>Ugu0#emQFUM7^*HbEH7(%>Lu~Z-AeFEm@>P27Hle9oYAXI17jv0>6UK$m0V> z?x6)xfMBqPe0D(=7zMz zl|=fO5F9$F&|Mfyx3h#+_pisf0 zPwIhA)QM2|W*sBF4B>$oPOF`@h%FF=aRl21_yXJ=si1nVhRMbN8J}N_6e3GfzXy-Q zy9K6$xAUzs97%;H%TIL+(JwnE*Q0O5Ka9YTe#wmGH2UC-Tpg>*6{7WLbR7fxTHgfRFWh^lFgLwNUX&8 z;RlGl?q~k54h3O<=}^$W@IYpOQatOr=iOQ@Vb@Fd>7Ymh+dmt9(HE?_>XWW-nx=1; ze+SG0tO{x0sZBuVZ$nz4eS9i(WmYFAVW?#ZnQQKDkNSc;rDc^Lb*DNjBb5W7%jygo zFuV5`mSl-{NhM+3sAD)|_f3|5TLkf$;wXuH@?k#)j9?=pJP=v6=qdv@F)f}m<9WFK zD?|7xOgF&$DG89Lc`sq?LPWCWryDAqps|q`kZj$k{VQRW{(rNJT_4nLHUy^O|CLYd zzbmW3o=yhf=p~%iBJPJ0%=e3~6b@3|{hq*2itHbr$Ao^MYBPig!O#_SazOY+C}40B zW(|mPT0416!Ns2XGK-dXV^+E=-6JK{48ckJ4XSLmtOpy5@Z|gM7&LC}&}9mU z&_jAgP}ncOsV63Igv-F7rUcLE%aGl`0zwxLd=;#ABmS11l~>DZholWi)Wy+M6t_SU zK+lL<$_&+LBPf=6V5Z^XBoBTvFey;OGYd1;W8gW4j50M-qy43c0nfk-UVKJDK`5ER zE8)34K6pp>xCLzt5SfB$;^24@m)dWLzBxxB_0ze)@fYWUmIB8gLhA{+C%^j^U}wyv zHK|RW(Ik)(xo1omaJZm?fDy5&1o_pa%0lig0ihbfePNJtB8$ou3F{D|*$AB4v2SZ1*ggp&o7k=uiD+p`~9i6Ad zFF=HUOuqog?T$77al6TJh%QOrbVCaTn3sdFEDU;xmyc8dgn>Ac1%}*BJ+7Q4oXvV5 zL&*YZy8+kX!265tbnW)YHQ#4q4OwPqj)$H;iafd)TE;a))I)@P4%jw>mfW^Km7$ST8<=+Zl|tb{%r z!apNp(hxbp%U6h?KPsUB?5>bOd4cOxgSG%$k_G9yLSAyM#5(M`$7l1uwJ>-Zg1GM$ zed9xH3v%zHRSh+^gM!M8p@V_C41e|&HFG`b6{wluIT)uh35yDg$n&c*Kj?V=U(9e%1^-TThEu?2eecNyIiYyG>vlSArQG9hC6MHbR^kzyeJI z)1n(0@eO_i2qZNhN`3lrH!o{(;&y8-c71{uzud)esN}coXDjk7N;dQZXZ5>XQn4&t zXsI@Eb3@Qv2BqMOI$WqyLF*Cm_Y( zr+IGk=WMyeDD90pXS6pvhwQ9HMMhM5=6C)srBsnayAj?r7!B(cvVMbPBrq=d-%Mh4 zZQ00+c9>4=9iDNgOQ5|r4lh&e+pACcxHQ)l$kCuRMun8hkOEAlPcycM2ZI2X2dP+R zB0EeAL#u5Z$nvePBVsiN+F~GYZw*xLOK2E!r#ZW2Z%uh7J#ekg=mC26VNFboDBFMZ zF8DWg_5`AjPmkq%ngB1DaTp6Q5YKd+5dhd;UYeEqR;bE{z?~X^-M}IGq{taFu*>Zn z={*8i0F**=3@0PqZntqDIZ>=fuq@2l!)O$V$aGQzj0sy}z;qN;#gXiAk)L4xu^vNO znTE-BAZG)JkLKg?iDD5eqk>MKwH_&bpm*(gog1hLYNJl@zC!SOvC!}wJY;`iXPG>- z4)n1nSlZv;RssayNV|PDs1m* z?VS1Kz8(K)LWnW=95nE|M04N#zI;4Fvq$7nJ^00N5iv^zWlNeZy)M{h3Fg&i(pt{5 zt!RYmb1OJ~t|M^To4z5_oB+mvVbmsXO??-q++HQ~i>h4oG<1ZE!FDp;FE?vt&9d%M zYRBJnXG{T;hL56GAF?lADXaAe*WPGwPV1pi?_Rxd$j*xVnVn_66FH&Ct$_@3+pNF3 zKWejz1?bLSNv>xGJjA0?lC=z9%}|uvh7!8_ zID`{7Gvw(NzISeL>52hERHzwfmi{ItT&u=$Z!ixA%YQEu?8O6nA;>dY`(mxp)kNk z2R+xH^vIDM#ygCA(8L5NAO*r8+=+mIA_E6_a2GV2m8-3!E{SKHNUCd;1!3C5Wiyy> zT($5gDRQF-il+vM8SFh0QE+t{4eS$Ezj)XvUbODxO*^muPxvgp6Q?4sg#nF9Svq51 zDBE{_b=9R#{ZHg-VqqU!9iC*h%ZV(s(ZQ`t6#u)80kyH}a;Rt6nlsYW{fF}Fmu+&3 z4fzPB9TEHyv0@m?e5%B;nBmz*gp1@)z!fU$= z>^mn7!$FNOvyK*(Tx;E6+2FeqY$7oLy)wj)K0~?KF=_bKJwWmuG)H&R4Co}YL_cf^ zEab?-TrP-mKDk>>cWE7fQpoumDVAvOhZLK%g-neA7XrTpr-lR=MActe5BAKyb+4os z_qbxtbI?7ZvN!@&E~FVr?r49)XRS1K|BTO8zW*zH)*d-MWP5lK)peU!ZzB)9j@XK? zbjRGu{QkH(znmq_u6s+E!su-~SV4p42kvh$I|Ob->?$K?0B`q$)LfkKOlI_xXImyc z)-^W+YFEVeMeFFM)?fKRYaDWuj+OK*w&PAwSyG>~yw5Ikz5jrAl*1HyBC2cbe51Sw zLkmhxOQqAIxQ{Wvh06`|xmeu^o=0iF)G=)F@Y)Y;7cTmr+_G+;fDT-}7A z_%FVYAhuRduEW^@R1r(~PV=v{j*LFFv{;8?Aebu74p9~`(JxOdeuLaA(`rtCXL2vAp4 zz?05ZGQbSr7`kx~0SH%ZOl@oR_7F0B1x8WfvadT5b23}Y={ z!DI-^p9%QM5wuG7Vdn6Z&DMkVgV&e{u`q?S&(&taZ0m!Y36K;n!|AilX>_OE?|?i? z7!SeRHUh=Sol{p`>%8RgOiU1rC_)~56`ijv*U| ztVf)7<_aolgHOZ)6{5A@0{|ciqB7CX{<^BbEFFUsXYex8yF)He zb7*^@;ia6n2(!>^=Th3?y|36zIV~&RzF~Vh4pXOESf1O_)nvEJ1D@FY_YYmc(W^J7Igl=mrI4E)XiWWpBG^4 zudpLN0`R1PkFw#1-)s+_qlEYJrVT|_01)j^O90B}1J%OpZR=Ml>DDsn3P{vp*MPK$ zG58;fvq(S!?&HKY`@N8NqKwb3+W`yvy8!F>^*8r}6M?PHe=JLdxO@1Kxb-rM6~ zTPvAlb?XE2=O1d(^kUzS?a2T9NOBeEkM9f~!J~WxR|-JRV0{0Qzy)~K!90}I_BmoF z>!H#Y(x<&%Rk696=YsFOT2CsKSV=)c800%RI`&MLPw=l@5b!~fOJyXa{zJIU1}-tH zlhXPJQtP0)u0#_<-sbg{MYf#$?mP3#!IB!u)9%zEB!}%WX&8Tkei$wml>TDVmiZFt2VF*5_K6oAXb4g-xTT@Uq$`^?$qJLCH@~43~<{DWM}`hgxi>>YCb* z{s`Sxb2j);9(P1X13(EmDy~E+GLvy;tO$~)H26oB;ZPWAg{Md?$&Le-P81@NVLs4i zF2Y;*!7>$)O7v{f;W|ygi^lZRL zU*cTq58XBjwM{?C`!w-Tx|O0ynE&DbqPH0e+D295vf*VQNx_(~7Vb$v8ukFr*SVj3 zy0oD$>Ib|m-uedOcOce!oi#ikW{V;J2gViz^Wd~lPUNgYjCNUilJ!Cm%X*MWXTKe~ zyoxMcrtiq*8lmU>Tqp2Dtz}@=Y5CO+p(bq4PjYt-3|ZmJBZCX{|GOE&{)-;>jRtgc zFl5YFx_*84ETW@;*dk@8zNfawMV`H>j;u^)!E)_mt^d2btSD~~C9C?HMQQ_;F5*yO ziGcvMtyW=(Q+;qR?*sjsj#YH_>OEmlgAoG=-In_>oFT!ka2oR8g8A~p>8V$)kgNTb z0fGRsE{6mW4D!HqrS$6$a3oZNFGIoWVz`ya2yWMb9vOHYlY%zDpvbd^y6yw-Y#^pH z+|&a7k?{mKgH*i`Bwe1PESV*9v9h=X83lCOZh*0yISgS7HFV1U2a1*%s^b=2Roxn7#r_Wq8YXA zLX4y*WXC`*tmDuX3!U@+4w{xt$0n?59 zaKQ+A2?2d^h8l?j21p+=JW<BPGq39)8s~ z4n3)HwxKM4X_^pSjQZ0RVK@{5zxmaoqk#YgIuzS(B{)VypQc77uok5YSqTHz#yJ4? zLF0hCw0xT?+x}Jrp0nqMUu2M1Jakbg;K%*dL}At7hl#>%cdw9r#b7M#S}?55DIZUq za>vWwocC{!@0Vu{ zf24Eo*5ulz)%d}k*jIyB&-=oM9Nq=yFG>%FxcH9AzExMB{~c9ZA(0On^94MN@R&(e zAMP-F0PC5v)a>63DnpbtDod6kWU{nb#!}X(tO+eh8cRjV zE)m(Y6=@r?g-Xg$nMldfp@?K@p`yiB*-n(4=ep5EPt)`~&-`AmU;lc&PUoEO`F`*F zzCPFWzQ8Bt&7FK!rMX2v^O&%)`;(y5#SV9M^D%9vR_JB<7JW3TZaqD{;Z^cn+LTk z0AavZg9}?%mVPq>l@Uuh;KKy3#SS%y*u&=NN86emMuf5z`|3;f<pE*& z_c!NB`2~^b;Z%Qyab=YB+VUya1||4RSpU6gYj)|%><6q>gW^(8{4Pk&BRCL3M8LzE zsmUb<@__iAzvu(Y<(0sW0jgEOD^FALZIw2831P^C1D+8$d~nKvlJW8}mdE3;+L$7! z%-`|XQfW2m`ahgM^TQqToQ zJKg>WYrtBV?!9jJ1?-} z&v_5+Zcnh3R8jclYUh=~j{03>fMsgn(5xUpO<>n5?&_g)O2@|Lyp$AI1@%Ee80JRF*h~{rExOJy z$;Wywd^T#47|E|ZDQcX8feQ+Z!uw@b+A)eLHO^{#BzHYlfEn9Jf8c$9{M~Bk#(<<} zFvc-DrGBT=?GEJzwqI?|@-_E@*0IJ^B^0%vHGT@%TOkU<<Q>WufnD+))(k!4CgyP_2db)4fl@G6+pbrQq4=^=J)Q{Z?iB2>$wGK-%%X zFF0po>|Q+BUB;(-ZfToAhj#2RpN=?n@MF6U7#<1lK0X`HH{w_lQ~x{Xv)5o#RA5)q z#)#yi(0ODWphH>i-*ZGMKbc{ZW}533*a#g4O1(xg!MIa&LFx1&=2@=qnP;0{FibYj z8ZJq$pa{GB0L&`CtWhlBAFB0web*Wq7Bt`jpW#FO(IF%{{uwN}KM|`g2DYt^k3L z&TSw6GY&#w!r)FWuRaHnaz5uzA%}ezU=N6GZO}&@k%6DfHC~%nUB|Z&i?3U0Lcy2U ziSHMDl?mtdWOB9+NV3{0W#~EL5e~J9Wq~gbM+L*%{SgG=;!H=vDYX$Er;4w28D%&l z5c>K(?&==qmi)t`N_R-aDcWhty*{qrrWYB0kQV6?f=`(fI>d$)f`#eIzpIESOf174@pgG0-e?NyEZ6$RMh?V8keQ~TFy z>Qp~FW$L&&nf?J=?tf;V&6H!!jL?s}hbH9zntCuZ!Szf9R@acJ-k5bEX^8_==!K|< ztn{4bI6;t5|5GL}CfXl!Ly@*4+9&$C?wMX}=D`rCQ&4x?d#BLtw@}qxE0I!Hd@|Kp{CeD z+#-G@c+MGm3P=v4ne+M8gB^^m&&H+Oy!c%TMx0y?jaM~xEx-5V#`Q~kc(Wg6Qe;)b zW_aDT)C;}|nDCf`wj)$s=#YMzqRD8n%3tAVpLb!#33C{y;s~CHK$B?dZ-(@T-fa3` ztGKIKE$x(~b@|sTP^I?EK>krW?A|w!o09aqXj?(Ff}FO%_i(f=q94BU&?=YwdULgp zTBRe5e*~RiejJuu@S9ie3B9)X9mN?sCMW>6yb~Cjc0|$Fjxg{jS5hcLg#zAidR%mD znO{dJ(PSE~T$4(b%gj1f&Fb#5~V(M~GKWjeb2)^-v4X_o{2$J3@? zy1ra1teT)XMR&7Lr=L#E6I{^NxHJFZK)XGo?JyF(LbC0KWQ*^$NHVZVZ%q|kQQ$Z( zvUw`S_@+7yMbvAVBOLTwsNOMORTYIvQGF3FY zLlhhE3CshzhmamMqZ0C}&e?8O8<>_-bHCY4?1X2~R8c)%p5T6Ld1l%F|0?^kL)q8d zfpAXj1%S#{-!_>}8#b9vE0@xGfY50dfmZM^0>Fb1t*-Cz4%C{EA4cNlB2nf+Um1X3v_Mv>wPrmKdg3wa>wgltY)Wi#q-q=9 ze+0>yUw93VQ&E^`@qOnQnZ}4Hgux`98~?CnWmnNX4mN*+JAk!XeX*WaF-`nW&H?VO zwSrUpV5cHyHqGrY4Qs<4jgf}$Q?V;5`3<5af^<0LKF5;`GoYBwxd;v4Ky$}6UG?V2q1s*L1Z*jPxBI)UK1 zv=!S=jq>RTcEXUM6koWp|NZ!*MR<-8?jWxAMqPcM=o;aL;?;AR(tKa@Br@D8mp+Bg z%755ddxf9uJ1~o?c?(4J!PYuA{w81f)PyfS+xg~tU9f}_G_BgkCZIc!Aumtk=5b1f{X-3eGQUc;__s37-UCoyP@aDCUC#`$*`xhmR1qQL-q@Na8>8$c?h^nx zcf7TiRAK06$wsYv5 zVdd#e*jC<6AlFhQ4sj`{lAty;aN5_ zzTE_-(=F(HJ3^ml-*9m#_rbVLx~pw1zf^&7Ja05gtu$$x75dC6NaMx&{BaOK#-Xs> zc}5VtF}s=RnteT~Nvg^n4*#cU?jsFY1cB&(cfBT)NTmUXnux{%1Vxh*oz|orj-H7oS9G_k&qt0X*5X zhz7?~uQ}1vzQ*8rnX1#GAa^Sn8+Jif+gnSLRQ$w;d_B`YRp*W}8mH#X|MaXIn(T?%M#K$Ht1Q9qV zM{5rdb$^()kS6D#^LI|yr_1@0-yzV%>cbi{?3?|oK)GzY5H)oJ&a-rA|ZLe?}4R@_~TiLpM{+zjWj)~(l8KXceY zZdTDyF$h3?d*~2qm&iD*|Sq9 zTTxjp;i>56WF)}8+OT&T*0H}p)C&6qT7Lsk+wSc^=7IwyMABKN+l@|1iPnLlFZcpc z#~;KONKeKWbZY(uzQ8I@`<!E6ByNEQjMF*wOnZyh!?(a;GY=R@TKB?Lj!H_G zIwVj96*D`y6*fp6WyDZf=%Kl1$bPR+icF<1~H|}yrp6@oim1R zVrl?jq;VT@0^vxwwO`too1!&M!MkgE<2H2J&o>WKp4;_l2*<30OOEIamvEF2$-T}4 z#?J_ibA@&CJcnXNw7;MW&VFf_lrd$wPzF#wZ4gW_w&=w7)svIocyw7 zHLR;%vWjd*{cA%_y-4BIK;(i^;*)RAY?!R8uYO3w5&koW!ZNjYCU@4pR5`tlc0s7F zZJGZ?qmwn#r6 zN7EXBY5Tr+>vC23uZ35F>NToi3T|pW(q}DL^r#^UZ#Y@(#mvRtGJiZ$1WX)OesN_H z|5~h&@w{ws8pZ%(z$+FYTT9Ep9+9Dj`pPVbQ!aKl|5<}m>>=ARl0UY)*JjyP&(5l> zN5vf?RLldzd+TB0f%oom$YXi<>$}7{G=?uQH__hc8GgcdL0~1B6Tj_=u6L(CbXj1t>(n;2wN^;c3#c{j~;b!x((;UBHhZX-Am9AZc}hr1g=> z_{6g4Q#>adsR6@f;T*jz{n)o`K}n|AG~GQwdd{NAp4s&4ZM`?;i@abVTre0n=jfH3 z#1D+IJM+T!*Jkf2)uDqH3Y}Ei_@8T_Wdu}#!R%cVWQ>D>zw9Sl$dZ3pNXkR zuqshfQDCh|uaHT#L8$4o*G(aP9rLsezA3%B_?Axu(5Cx}N9Yd?2F?n-9jI-wq9&SdtH`Tjl@k{fdtcHLXEiH`imxjP#%;B?P9_#{-n4h4B*#!AcDMd^R2{ z+>~7g8aq66#JNsD|TL(^N@E~ za?339BHNGa6F}~IC2#4wl(%qb0e>6e|LSo$Hw51hi8`8CVk8i|gNUzh3T~Fym2r4| zqXaDB`z2t7pVTptz$wX0PZr8(w+3f10PmF?Wgp7{a2bT*ON*HC7&p8vG z;Ah<3gZlY9CzftnUp59XaQL*28M+02@0XlJVs>OV%iG7&BFeE3WZ!`<>gckFdiPDF zKW2sCp*dJA?=~#1>ot_wIO@;zMC=Jz0mJtlMblP!hA)Z4h&LcnDQ2E>w5pjycZy{Uhj@RFdpF&f^3rOePjg(~Mj zrgV0zc1bVSTXLvZ_3RV*Qxv-8ju%bXP*W6YebUg9?!N#3F0wXKyGe|6p6?%FoRs~R zJC$x(?Q!4g#=vftDI}&HXq4DIJZi9P4%;vSk1@BhXS6k2(9wj<9$nHTB^}Zl(zCmM zOB7+n_QN;J6bakxiw)CcC%_8^IlT1`Ze{P3~_r(2**-Z64D}?*r!X%t={A5KumJ>vO>m|>b7fc zD+n*p4&0cSFnqH&;8gSJ1x^uSv`EH|f%XF@7&EDKtEy|Svjlpinc`?=S}pIdM*7B< zU!h(hpE~)fWZtDys+AAo<4y*kTqU$3(|PTN3bLGBGS>IemEGuskQ*R&q?yl8MkOvF z%2K{Y$plzXXtnIS7gxm#SB3t0dnxeBKv8@5;}y z)3W_;b3l;5M1yPrcf|0yS06Go=Ce7p^C&)#6Hw;!Y_>~EFT50)aGi%me9scjPXV_= zfBIi#*Gb;jTgP*!Tdo;r68!m>g?!&I$qxBWNoM+^O={{AJv#i;(bUtppl0R&FJ}s# Ad;kCd From 9875f113a3d22b625c55d8d00cc60cedafd2248e Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Tue, 13 Jan 2026 16:05:21 +1300 Subject: [PATCH 15/23] Make name unix safe. And reo. --- ...tting_your_first_job.md => Ako_Submitting_Your_First_Job.md} | 1 + docs/Getting_Started/Accessing_the_HPCs/VSCode.md | 2 +- docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md | 2 +- docs/Getting_Started/Tutorial:_Submitting_your_first_job.md | 1 + docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) rename docs/Batch_Computing/{Tutorial:_Submitting_your_first_job.md => Ako_Submitting_Your_First_Job.md} (99%) create mode 120000 docs/Getting_Started/Tutorial:_Submitting_your_first_job.md diff --git a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md b/docs/Batch_Computing/Ako_Submitting_Your_First_Job.md similarity index 99% rename from docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md rename to docs/Batch_Computing/Ako_Submitting_Your_First_Job.md index 23065fb69..fc502a670 100644 --- a/docs/Batch_Computing/Tutorial:_Submitting_your_first_job.md +++ b/docs/Batch_Computing/Ako_Submitting_Your_First_Job.md @@ -5,6 +5,7 @@ tags: - scheduler - tutorial description: Tutorial on how to submit your first Slurm job +title: Ako:_Submitting Your_First_Job status: tutorial --- diff --git a/docs/Getting_Started/Accessing_the_HPCs/VSCode.md b/docs/Getting_Started/Accessing_the_HPCs/VSCode.md index 420fb37d3..878f9844f 100644 --- a/docs/Getting_Started/Accessing_the_HPCs/VSCode.md +++ b/docs/Getting_Started/Accessing_the_HPCs/VSCode.md @@ -83,7 +83,7 @@ Clicking on these will open a connection to that machine, you will then be promp You may find that VSCode is not utilising your preferred versions of software (e.g. when debugging or linting your Python code). -As the NeSI cluster utilises [Environment Modules](../../Batch_Computing/Tutorial:_Submitting_your_first_job.md#environment-modules), changing the executable used is not just a matter of changing the path in VSCode configuration, as the libraries required will not be loaded. +As the NeSI cluster utilises [Environment Modules](../../Batch_Computing/Ako_Submitting_Your_First_Job.md#environment-modules), changing the executable used is not just a matter of changing the path in VSCode configuration, as the libraries required will not be loaded. The only way to make sure that VSCode has access to a suitable environment, is to load the required modules in your `~/.bashrc` diff --git a/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md b/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md index 0d8e320e8..70c4e1fe0 100644 --- a/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md +++ b/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md @@ -8,7 +8,7 @@ description: Quick list of the most commonly used Slurm commands, flags, and env --- If you are unsure about using our job scheduler Slurm, more details can -be found on [Batch Computing Guide](../../Batch_Computing/Batch_Computing_Guide.md) and we have a self-paced tutorial on [Submitting your first job](../../Batch_Computing/Tutorial:_Submitting_your_first_job.md). +be found on [Batch Computing Guide](../../Batch_Computing/Batch_Computing_Guide.md) and we have a self-paced tutorial on [Submitting your first job](../../Batch_Computing/Ako_Submitting_Your_First_Job.md). ## Slurm Commands diff --git a/docs/Getting_Started/Tutorial:_Submitting_your_first_job.md b/docs/Getting_Started/Tutorial:_Submitting_your_first_job.md new file mode 120000 index 000000000..88158a676 --- /dev/null +++ b/docs/Getting_Started/Tutorial:_Submitting_your_first_job.md @@ -0,0 +1 @@ +../Batch_Computing/Tutorial:_Submitting_your_first_job.md \ No newline at end of file diff --git a/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md b/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md index 15150c536..c1005f1b3 100644 --- a/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md +++ b/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md @@ -8,7 +8,7 @@ Jupyter allows you to create notebooks that contain live code, equations, visualisations and explanatory text. There are many uses for Jupyter, including data cleaning, analytics and visualisation, machine learning, numerical simulation, managing -[Slurm job submissions](../../../../Batch_Computing/Tutorial:_Submitting_your_first_job.md) +[Slurm job submissions](../../../../Batch_Computing/Ako_Submitting_Your_First_Job.md) and workflows and much more. ## Accessing Jupyter on NeSI From 2c0e37a1684627da9261194058ab24e196a52cb4 Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Wed, 14 Jan 2026 12:49:07 +1300 Subject: [PATCH 16/23] Add environemnt and modules --- docs/Software/Ako_Environment_And_Modules.md | 464 +++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 docs/Software/Ako_Environment_And_Modules.md diff --git a/docs/Software/Ako_Environment_And_Modules.md b/docs/Software/Ako_Environment_And_Modules.md new file mode 100644 index 000000000..aa6f20038 --- /dev/null +++ b/docs/Software/Ako_Environment_And_Modules.md @@ -0,0 +1,464 @@ +--- +created_at: 2026-01-13 +title: "Ako: Environment & Modules" +description: How do we load and unload software packages? +tags: + - software +status: tutorial +time: 20 +objectives: + - "Load and use a software package." + - "Explain how the shell environment changes when the module mechanism loads or unloads packages." +keypoints: +- "Load software with `module load softwareName`." +- "Unload software with `module unload`" +- "The module system handles software versioning and package conflicts for you + automatically." +--- + +On a high-performance computing system, it is seldom the case that the software +we want to use is available when we log in. It is installed, but we will need +to "load" it before it can run. + +Before we start using individual software packages, however, we should +understand the reasoning behind this approach. The three biggest factors are: + +- software incompatibilities +- versioning +- dependencies + +Software incompatibility is a major headache for programmers. Sometimes the +presence (or absence) of a software package will break others that depend on +it. Two of the most famous examples are Python 2 and 3 and C compiler versions. +Python 3 famously provides a `python` command that conflicts with that provided +by Python 2. Software compiled against a newer version of the C libraries and +then used when they are not present will result in a nasty `'GLIBCXX_3.4.20' +not found` error, for instance. + + + +Software versioning is another common issue. A team might depend on a certain +package version for their research project - if the software version was to +change (for instance, if a package was updated), it might affect their results. +Having access to multiple software versions allows a set of researchers to +prevent software versioning issues from affecting their results. + +Dependencies are where a particular software package (or even a particular +version) depends on having access to another software package (or even a +particular version of another software package). For example, the VASP +materials science software may depend on having a particular version of the +FFTW (Fastest Fourier Transform in the West) software library available for it +to work. + +## Environment + +Before understanding environment modules we first need to understand what is meant by _environment_. + +The environment is defined by it's _environment variables_. + +_Environment Variables_ are writable named-variables. + +We can assign a variable named "FOO" with the value "bar" using the syntax. + +```sh +FOO="bar" +``` + +Convention is to name fixed variables in all caps. + +Our new variable can be referenced using `$FOO`, you could also use `${FOO}`, +enclosing a variable in curly brackets is good practice as it avoids possible ambiguity. + +```sh +$FOO +``` + +```out +-bash: bar: command not found +``` + +We got an error here because the variable is evaluated _in the terminal_ then executed. +If we just want to print the variable we can use the command, + +```sh +echo $FOO +``` + +```out +bar +``` + +We can get a full list of environment variables using the command, + +```sh +env +``` + +```out +[removed some lines for clarity] +EBROOTTCL=/opt/nesi/CS400_centos7_bdw/Tcl/8.6.10-GCCcore-9.2.0 +CPUARCH_STRING=bdw +TERM=xterm-256color +SHELL=/bin/bash +EBROOTGCCCORE=/opt/nesi/CS400_centos7_bdw/GCCcore/9.2.0 +EBDEVELFREETYPE=/opt/nesi/CS400_centos7_bdw/freetype/2.10.1-GCCcore-9.2.0/easybuild/freetype-2.10.1-GCCcore-9.2.0-easybuild-devel +HISTSIZE=10000 +XALT_EXECUTABLE_TRACKING=yes +MODULEPATH_ROOT=/usr/share/modulefiles +LMOD_SYSTEM_DEFAULT_MODULES=NeSI +SSH_CLIENT=192.168.94.65 45946 22 +EBDEVELMETIS=/opt/nesi/CS400_centos7_bdw/METIS/5.1.0-GCCcore-9.2.0/easybuild/METIS-5.1.0-GCCcore-9.2.0-easybuild-devel +LMOD_PACKAGE_PATH=/opt/nesi/share/etc/lmod +``` + +These variables control many aspects of how your terminal, and any software launched from your terminal works. + +## Environment Modules + +Environment modules are the solution to these problems. A _module_ is a +self-contained description of a software package -- it contains the +settings required to run a software package and, usually, encodes required +dependencies on other software packages. + +There are a number of environment module implementations commonly +used on HPC systems: the two most common are _TCL modules_ and _Lmod_. Both of +these use similar syntax and the concepts are the same so learning to use one +will allow you to use whichever is installed on the system you are using. In +both implementations the `module` command is used to interact with environment +modules. An additional sub-command is usually added to the command to specify +what you want to do. For a list of sub-commands you can use `module -h` or +`module help`. As for all commands, you can access the full help on the _man_ +pages with `man module`. + +### Purging Modules + +Depending on how you are accessing the HPC the modules you have loaded by default will be different. So before we start listing our modules we will first use the `module purge` command to clear all but the minimum default modules so that we are all starting with the same modules. + +```sh +module purge +``` + +```out +The following modules were not unloaded: + (Use "module --force purge" to unload all): + + 1) NeSI/zen3 +``` + +Note that `module purge` is informative. It lets us know that all but a minimal default +set of packages have been unloaded (and how to actually unload these if we +truly so desired). + +We are able to unload individual modules, unfortunately within the NeSI system it does not always unload it's dependencies, therefore we recommend `module purge` to bring you back to a state where only those modules needed to perform your normal work on the cluster. + +`module purge` is a useful tool for ensuring repeatable research by guaranteeing that the environment that you build your software stack from is always the same. This is important since some modules have the potential to silently effect your results if they are loaded (or not loaded). + +### Listing Available Modules + +To see available software modules, use `module avail`: + +```sh +module avail +``` + +```out +-------------------------------------------------------------------------- /opt/nesi/lmod/zen3 -------------------------------------------------------------------------- + Amber/24.0-foss-2023a-AmberTools-25.0-CUDA-12.5.0 HTSlib/1.22-GCC-12.3.0 (D) pixi/0.61.0 + AUGUSTUS/3.5.0-gimkl-2022a-patch1 IGV/2.19.4 PLUMED/2.10.0-foss-2023a (D) + AUGUSTUS/3.5.0-gimkl-2022a (D) IGV/2.19.7 (D) pod5/0.3.28-foss-2023a (D) + Basilisk/20250612-gompi-2023a (D) json-fortran/9.0.2-GCC-12.3.0 prokka/1.14.5-GCC-11.3.0 + BayPass/3.0-GCC-12.3.0 (D) JupyterLab/2025.5.0-foss-2023a-4.4.2 (D) prokka/1.14.6-apptainer (D) + BCFtools/1.22-GCC-12.3.0 (D) Kraken2/2.1.6-GCC-12.3.0 (D) pstoedit/4.02-GCCcore-12.3.0 (D) + BCL-Convert/4.2.4 LAMMPS/22Jul2025-foss-2023a-kokkos-CUDA-12.2.2 pybind11/2.9.2-GCCcore-12.3.0 + BiG-SCAPE/1.1.9-gimkl-2022a-Python-3.11.3 LAMMPS/22Jul2025-foss-2023a-kokkos Python-Geo/3.11.6-foss-2023a (D) + +[removed most of the output here for clarity] + +Use "module spider" to find all possible modules and extensions. +Use "module keyword key1 key2 ..." to search for all possible modules matching any of the "keys". +``` + +### Listing Currently Loaded Modules + +You can use the `module list` command to see which modules you currently have +loaded in your environment. On {{ site.remote.name }} you will have a few default modules loaded when you login. + +```sh +module list +``` + +```out +Currently Loaded Modules: + + 1) NeSI/zen3 + +``` + +## Loading and Unloading Software + +You can load software using the `module load` command. In this example we will be using the programming language _R_. + +Initially, R is not loaded. We can test this by using the `which` +command. `which` looks for programs the same way that Bash does, so we can use +it to tell us where a particular piece of software is stored. + +```sh +which R +``` + +```out +/usr/bin/which: no R in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/cwal219/bin:/home/cwal219/.local/bin:/opt/nesi/bin) +``` + +The important bit here being: + +```out +/usr/bin/which: no R in (...) +``` + +Now lets try loading the R environment module, and try again. + +```sh +module load R +which R +``` + +```out +/opt/nesi/zen3/R/4.3.2-foss-2023a/bin/R +``` + +!!! note "Tab Completion" + + The module command also supports tab completion. You may find this the easiest way to find the right software. + +So, what just happened? + +To understand the output, first we need to understand the nature of the `$PATH` +environment variable. `$PATH` is a special environment variable that controls +where a UNIX system looks for software. Specifically `$PATH` is a list of +directories (separated by `:`) that the OS searches through for a command +before giving up and telling us it can't find it. As with all environment +variables we can print it out using `echo`. + +```sh +echo $PATH +``` + +```out +/opt/nesi/zen3/R/4.3.2-foss-2023a/bin:/opt/nesi/CS400_centos7_bdw/LibTIFF/4.4.0-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/nodejs/18.18.2-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/libgit2/1.6.4-GCC-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/Java/20.0.2:/opt/nesi/CS400_centos7_bdw/Java/20.0.2/bin:/opt/nesi/CS400_centos7_bdw/cURL/8.3.0-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/OpenSSL/1.1/bin:/opt/nesi/CS400_centos7_bdw/SQLite/3.42.0-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/libxml2/2.11.4-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/ncurses/6.4-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/PCRE2/10.42-GCCcore-12.3.0/bin:/opt/nesi/zen3/XZ/5.4.2-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/bzip2/1.0.8-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/FFTW/3.3.10-GCC-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/FlexiBLAS/3.3.1-GCC-12.3.0/bin:/opt/nesi/zen3/OpenMPI/4.1.5-GCC-12.3.0/bin:/opt/nesi/zen3/UCC/1.3.0-GCCcore-12.3.0/bin:/opt/nesi/zen3/UCX/1.18.1-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/numactl/2.0.16-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/binutils/2.40-GCCcore-12.3.0/bin:/opt/nesi/CS400_centos7_bdw/GCCcore/12.3.0/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/cwal219/bin:/opt/nesi/vdt:/home/cwal219/.local/bin:/opt/nesi/bin +``` + +We can improve the readability of this command slightly by replacing the colon delimiters (`:`) with newline (`\n`) characters. + +```sh +echo $PATH | tr ":" "\n" +``` + +??? info "Wait, what did I just run??" + mention pipe and stuff. point to intro bash. + +```out +/opt/nesi/zen3/R/4.3.2-foss-2023a/bin +/opt/nesi/CS400_centos7_bdw/LibTIFF/4.4.0-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/nodejs/18.18.2-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/libgit2/1.6.4-GCC-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/Java/20.0.2 +/opt/nesi/CS400_centos7_bdw/Java/20.0.2/bin +/opt/nesi/CS400_centos7_bdw/cURL/8.3.0-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/OpenSSL/1.1/bin +/opt/nesi/CS400_centos7_bdw/SQLite/3.42.0-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/libxml2/2.11.4-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/ncurses/6.4-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/PCRE2/10.42-GCCcore-12.3.0/bin +/opt/nesi/zen3/XZ/5.4.2-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/bzip2/1.0.8-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/FFTW/3.3.10-GCC-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/FlexiBLAS/3.3.1-GCC-12.3.0/bin +/opt/nesi/zen3/OpenMPI/4.1.5-GCC-12.3.0/bin +/opt/nesi/zen3/UCC/1.3.0-GCCcore-12.3.0/bin +/opt/nesi/zen3/UCX/1.18.1-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/numactl/2.0.16-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/binutils/2.40-GCCcore-12.3.0/bin +/opt/nesi/CS400_centos7_bdw/GCCcore/12.3.0/bin +/usr/local/bin +/usr/bin +/usr/local/sbin +/usr/sbin +/home/cwal219/bin +/home/cwal219/.local/bin +``` + +You'll notice a similarity to the output of the `which` command. However, in this case, +there are a lot more directories at the beginning. When we +ran the `module load` command, it added many directories to the beginning of our +`$PATH`. + +Looking at the first line: `/opt/nesi/CS400_centos7_bdw/R/4.2.1-gimkl-2022a/bin` + +Let's examine what's there: + +```sh +ls /opt/nesi/zen3/R/4.3.2-foss-2023a/bin +``` + +```out +R Rscript +``` + +`module load` "loads" not only the specified software, but it also loads software dependencies. That is, the software that the application you load requires to run. + +To demonstrate, let's use `module list`. + +```sh +module list +``` + +```out +Currently Loaded Modules: + 1) NeSI/zen3 (S) 8) UCC/1.3.0-GCCcore-12.3.0 15) ScaLAPACK/2.2.0-gompi-2023a-fb 22) libxml2/2.11.4-GCCcore-12.3.0 29) libgit2/1.6.4-GCC-12.3.0 + 2) GCCcore/12.3.0 9) OpenMPI/4.1.5-GCC-12.3.0 16) foss/2023a 23) SQLite/3.42.0-GCCcore-12.3.0 30) nodejs/18.18.2-GCCcore-12.3.0 + 3) zlib/1.2.13-GCCcore-12.3.0 10) OpenBLAS/0.3.23-GCC-12.3.0 17) bzip2/1.0.8-GCCcore-12.3.0 24) OpenSSL/1.1 31) LibTIFF/4.4.0-GCCcore-12.3.0 + 4) binutils/2.40-GCCcore-12.3.0 11) FlexiBLAS/3.3.1-GCC-12.3.0 18) XZ/5.4.2-GCCcore-12.3.0 25) cURL/8.3.0-GCCcore-12.3.0 32) R/4.3.2-foss-2023a + 5) GCC/12.3.0 12) FFTW/3.3.10-GCC-12.3.0 19) PCRE2/10.42-GCCcore-12.3.0 26) NLopt/2.7.1-GCC-12.3.0 + 6) numactl/2.0.16-GCCcore-12.3.0 13) gompi/2023a 20) ncurses/6.4-GCCcore-12.3.0 27) GMP/6.2.1-GCCcore-12.3.0 + 7) UCX/1.18.1-GCCcore-12.3.0 14) FFTW.MPI/3.3.10-gompi-2023a 21) libreadline/8.2-GCCcore-12.3.0 28) Java/20.0.2 +``` + +Notice that our initial list of modules has increased by 30. When we loaded R, it also loaded all of it's dependencies along with all the dependencies of those modules. + +Before moving onto the next session lets use `module purge` again to return to the minimal environment. + +```sh +module purge +``` + +```out +The following modules were not unloaded: + (Use "module --force purge" to unload all): + + 1) NeSI/zen3 +``` + +!!! warning "Thinking" + Just because you see a command, you don't have to run it. + Removing `NeSI/zen3` will break your environment. You _do not_ want to run `module --force purge` + +## Software Versioning + +So far, we've learned how to load and unload software packages. However, we have not yet addressed the issue of software versioning. At +some point or other, you will run into issues where only one particular version +of some software will be suitable. Perhaps a key bugfix only happened in a +certain version, or version _X_ broke compatibility with a file format you use. +In either of these example cases, it helps to be very specific about what +software is loaded. + +Let's examine the output of `module avail` more closely. + +```sh +module avail +``` + +```out +-----------------/opt/nesi/CS400_centos7_bdw/modules/all ------------------ + Flye/2.9-gimkl-2020a-Python-3.8.2 (D) PyQt/5.10.1-gimkl-2018b-Python-3.7.3 + fmlrc/1.0.0-GCC-9.2.0 PyQt/5.12.1-gimkl-2018b-Python-2.7.16 + fmt/7.1.3-GCCcore-9.2.0 PyQt/5.12.1-gimkl-2020a-Python-3.8.2 (D) + fmt/8.0.1 (D) pyspoa/0.0.8-gimkl-2018b-Python-3.8.1 + fontconfig/2.12.1-gimkl-2017a Python-Geo/2.7.14-gimkl-2017a + fontconfig/2.13.1-GCCcore-7.4.0 Python-Geo/2.7.16-gimkl-2018b + fontconfig/2.13.1-GCCcore-9.2.0 (D) Python-Geo/3.6.3-gimkl-2017a + forge/19.0 Python-Geo/3.7.3-gimkl-2018b + forge/20.0.2 (D) Python-Geo/3.8.2-gimkl-2020a + FoX/4.1.2-intel-2018b Python-Geo/3.9.5-gimkl-2020a (D) + FragGeneScan/1.31-gimkl-2018b Python-GPU/3.6.3-gimkl-2017a + FreeBayes/1.1.0-gimkl-2017a Python/2.7.14-gimkl-2017a + FreeBayes/1.3.1-GCC-7.4.0 Python/2.7.16-gimkl-2018b + FreeBayes/1.3.2-GCC-9.2.0 (D) Python/2.7.16-intel-2018b + freetype/2.7.1-gimkl-2017a Python/2.7.18-gimkl-2020a + freetype/2.9.1-GCCcore-7.4.0 Python/3.6.3-gimkl-2017a + freetype/2.10.1-GCCcore-9.2.0 (D) Python/3.7.3-gimkl-2018b + FreeXL/1.0.2-gimkl-2017a Python/3.8.1-gimkl-2018b + FreeXL/1.0.5-GCCcore-7.4.0 (D) Python/3.8.2-gimkl-2020a (D) + FreeXL/1.0.5-GCCcore-9.2.0 Python/3.9.5-gimkl-2020a + FriBidi/1.0.10-GCCcore-9.2.0 qcat/1.1.0-gimkl-2020a-Python-3.8.2 + +[removed most of the output here for clarity] + +----------------------------------- /cm/local/modulefiles ----------------------------------- + cluster-tools/8.0 freeipmi/1.5.5 module-git openmpi/mlnx/gcc/64/2.1.2a1 + cmd gcc/6.3.0 module-info shared + cuda-dcgm/1.3.3.1 ipmitool/1.8.18 null + dot lua/5.3.4 openldap + + Where: + D: Default Module + +Use "module spider" to find all possible modules. +Use "module keyword key1 key2 ..." to search for all possible modules matching any of the +"keys". +``` + +Let's take a closer look at the `Python` modules. There are many applications +that are run using python and may fail to run if the wrong version is loaded. +In this case, there are many different versions: `Python/3.6.3-gimkl-2017a`, +`Python/3.7.3-gimkl-2018b` through to the newest versions. + +How do we load each copy and which copy is the default? + +In this case, `Python/3.8.2-gimkl-2020a` has a `(D)` next to it. This indicates that it is the +default — if we type `module load Python`, as we did above, this is the copy that will be +loaded. + +```sh +module load Python +python3 --version +``` + +```out +Python 3.11.6 +``` + +So how do we load the non-default copy of a software package? In this case, the +only change we need to make is be more specific about the module we are +loading. There are many other Python versions. To load a +non-default module, the only change we need to make to our `module load` +command is to add the version number after the `/`. + +```sh +module load Python/3.9.5-gimkl-2020a +``` + +```out +The following have been reloaded with a version change: + 1) Python 3.11.6-foss-2023a => Python/3.9.5-gimkl-2020a +``` + +Notice how the module command has swapped out versions of the Python module. +And now we test which version we are using: + +```sh +python3 --version +``` + +```out +Python 3.9.5 +``` + +We are now left with only those module required to do our work for this project. + +```sh +module list +``` + +```out +Currently Loaded Modules: + 1) NeSI/zen3 (S) 10) gimkl/2020a 19) libreadline/8.0-GCCcore-9.2.0 28) tbb/2019_U9-GCCcore-9.2.0 + 2) GCCcore/9.2.0 11) bzip2/1.0.8-GCCcore-9.2.0 20) libxml2/2.9.10-GCCcore-9.2.0 29) SuiteSparse/5.6.0-gimkl-2020a-METIS-5.1.0 + 3) zlib/1.2.11-GCCcore-9.2.0 12) XZ/5.2.4-GCCcore-9.2.0 21) libxslt/1.1.34-GCCcore-9.2.0 30) Tcl/8.6.10-GCCcore-9.2.0 + 4) binutils/2.32-GCCcore-9.2.0 13) libpng/1.6.37-GCCcore-9.2.0 22) LegacySystemLibs/.crypto7 (H) 31) Tk/8.6.10-GCCcore-9.2.0 + 5) GCC/9.2.0 14) freetype/2.10.1-GCCcore-9.2.0 23) cURL/7.64.0-GCCcore-9.2.0 32) LLVM/10.0.1-GCCcore-9.2.0 + 6) libpmi/1 15) Szip/2.1.1-GCCcore-9.2.0 24) PCRE/8.43-GCCcore-9.2.0 33) OpenSSL/1.1.1k-GCCcore-9.2.0 + 7) impi/2019.6.166-GCC-9.2.0 16) HDF5/1.10.5-gimpi-2020a 25) netCDF/4.7.3-gimpi-2020a 34) Python/3.9.5-gimkl-2020a + 8) gimpi/2020a 17) libjpeg-turbo/2.0.2-GCCcore-9.2.0 26) SQLite/3.31.1-GCCcore-9.2.0 + 9) imkl/2020.0.166-gimpi-2020a 18) ncurses/6.1-GCCcore-9.2.0 27) METIS/5.1.0-GCCcore-9.2.0 +``` From ce7c571b8138c21b362df9022fa6aa70b0e06a70 Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Wed, 14 Jan 2026 15:13:51 +1300 Subject: [PATCH 17/23] remove broken symlnk --- docs/Getting_Started/Tutorial:_Submitting_your_first_job.md | 1 - 1 file changed, 1 deletion(-) delete mode 120000 docs/Getting_Started/Tutorial:_Submitting_your_first_job.md diff --git a/docs/Getting_Started/Tutorial:_Submitting_your_first_job.md b/docs/Getting_Started/Tutorial:_Submitting_your_first_job.md deleted file mode 120000 index 88158a676..000000000 --- a/docs/Getting_Started/Tutorial:_Submitting_your_first_job.md +++ /dev/null @@ -1 +0,0 @@ -../Batch_Computing/Tutorial:_Submitting_your_first_job.md \ No newline at end of file From bf81379b9332d133d265b19a6b8e5735180c478a Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Wed, 14 Jan 2026 15:14:04 +1300 Subject: [PATCH 18/23] update to admonitions --- .../Ako_Submitting_Your_First_Job.md | 32 +++++++------------ docs/Software/Ako_Environment_And_Modules.md | 28 ++++++++++------ 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/docs/Batch_Computing/Ako_Submitting_Your_First_Job.md b/docs/Batch_Computing/Ako_Submitting_Your_First_Job.md index c6f19aef3..22da06fe2 100644 --- a/docs/Batch_Computing/Ako_Submitting_Your_First_Job.md +++ b/docs/Batch_Computing/Ako_Submitting_Your_First_Job.md @@ -8,26 +8,16 @@ description: Tutorial on how to submit your first Slurm job title: Ako:_Submitting Your_First_Job status: tutorial --- +!!! time "10 Minutes" !!! prerequisite "" This tutorial assumes basic familiarity with bash and the terminal. The first three lessons of the [Software Carpentry Unix Shell lessons](https://swcarpentry.github.io/shell-novice/) covers the information needed. -## Overview - -The exercises in this tutorial should take approximately 10 minutes to complete. - -### Questions - -- What is a scheduler and why does a cluster need one? -- How do I launch a program to run on a compute node in the cluster? -- How do I capture the output of a program that is run on a node in the cluster? - -### Objectives - -- Run a simple script through the scheduler -- Use the batch system command line tools to monitor the execution of your job -- Inspect the output and error files of your jobs +!!! objectives + - Run a simple script through the scheduler + - Use the batch system command line tools to monitor the execution of your job + - Inspect the output and error files of your jobs ## What is a job scheduler? @@ -324,8 +314,10 @@ This can be suppressed using the flag `-X`. echo ${SLURM_SUBMIT_DIR} ``` -## Key points - -- The scheduler handles how compute resources are shared between users -- A job is just a shell script -- Request *slightly* more resources than you need +!!! keypoints + - The scheduler handles how compute resources are shared between users + - A job is just a shell script + - Request *slightly* more resources than you need + +!!! postrequisite + - Link to next page diff --git a/docs/Software/Ako_Environment_And_Modules.md b/docs/Software/Ako_Environment_And_Modules.md index aa6f20038..7441079fa 100644 --- a/docs/Software/Ako_Environment_And_Modules.md +++ b/docs/Software/Ako_Environment_And_Modules.md @@ -5,16 +5,17 @@ description: How do we load and unload software packages? tags: - software status: tutorial -time: 20 -objectives: +--- + + +!!! time "Time: 20 Minutes" + +!!! prerequisites + - Page Link + +!!! objectives - "Load and use a software package." - "Explain how the shell environment changes when the module mechanism loads or unloads packages." -keypoints: -- "Load software with `module load softwareName`." -- "Unload software with `module unload`" -- "The module system handles software versioning and package conflicts for you - automatically." ---- On a high-performance computing system, it is seldom the case that the software we want to use is available when we log in. It is installed, but we will need @@ -181,7 +182,7 @@ Use "module keyword key1 key2 ..." to search for all possible modules matching a ### Listing Currently Loaded Modules You can use the `module list` command to see which modules you currently have -loaded in your environment. On {{ site.remote.name }} you will have a few default modules loaded when you login. +loaded in your environment. On Mahuika you will have a few default modules loaded when you login. ```sh module list @@ -462,3 +463,12 @@ Currently Loaded Modules: 8) gimpi/2020a 17) libjpeg-turbo/2.0.2-GCCcore-9.2.0 26) SQLite/3.31.1-GCCcore-9.2.0 9) imkl/2020.0.166-gimpi-2020a 18) ncurses/6.1-GCCcore-9.2.0 27) METIS/5.1.0-GCCcore-9.2.0 ``` + +!!! keypoints + - "Load software with `module load softwareName`." + - "Unload software with `module unload`" + - "The module system handles software versioning and package conflicts for you + automatically." + +!!! postrequisite + - Link to next page From 39eb949e993edf2de8dfd44230fe9ad80bb9f205 Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Wed, 14 Jan 2026 15:14:21 +1300 Subject: [PATCH 19/23] moved templats into partials --- overrides/main.html | 11 ++++++----- overrides/partials/status_deprecated_header.html | 4 ++++ overrides/partials/status_tutorial_header.html | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 overrides/partials/status_deprecated_header.html create mode 100644 overrides/partials/status_tutorial_header.html diff --git a/overrides/main.html b/overrides/main.html index cc65e211a..b5b25618a 100644 --- a/overrides/main.html +++ b/overrides/main.html @@ -31,11 +31,12 @@ {% endif %} {% endblock %} {% block content %} -{% if page.meta and page.meta.status and page.meta.status == "deprecated" %} -
-

Page Deprecated

-

Information you find on this page may be out of date and no longer accurate.

-
+{% if page.meta and page.meta.status %} + {% if page.meta.status == "deprecated" %} + {% include "partials/status_deprecated_header.html" %} + {% elif page.meta.status == "tutorial" %} + {% include "partials/status_tutorial_header.html" %} + {% endif %} {% endif %} {{ super() }} diff --git a/overrides/partials/status_deprecated_header.html b/overrides/partials/status_deprecated_header.html new file mode 100644 index 000000000..4a088e6ab --- /dev/null +++ b/overrides/partials/status_deprecated_header.html @@ -0,0 +1,4 @@ +
+

Page Deprecated

+

Information you find on this page may be out of date and no longer accurate.

+
diff --git a/overrides/partials/status_tutorial_header.html b/overrides/partials/status_tutorial_header.html new file mode 100644 index 000000000..5451d0371 --- /dev/null +++ b/overrides/partials/status_tutorial_header.html @@ -0,0 +1 @@ +

Tutorial

From 3d41f05db522818d4c0ba328d3d7983383b3f057 Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Wed, 14 Jan 2026 15:14:30 +1300 Subject: [PATCH 20/23] consolidate CSS --- .../assets/stylesheets/custom_admonations.css | 748 ------------------ docs/assets/stylesheets/footer.css | 31 - docs/assets/stylesheets/theme.css | 109 +++ mkdocs.yml | 2 - 4 files changed, 109 insertions(+), 781 deletions(-) delete mode 100644 docs/assets/stylesheets/custom_admonations.css delete mode 100644 docs/assets/stylesheets/footer.css diff --git a/docs/assets/stylesheets/custom_admonations.css b/docs/assets/stylesheets/custom_admonations.css deleted file mode 100644 index c17db867e..000000000 --- a/docs/assets/stylesheets/custom_admonations.css +++ /dev/null @@ -1,748 +0,0 @@ -:root { - --md-admonition-icon--prerequisite: url('data:image/svg+xml;charset=utf-8,') - } - - .md-typeset .admonition.prerequisite, - .md-typeset details.prerequisite { - border-color: rgb(170, 170, 60); - } - .md-typeset .prerequisite > .admonition-title, - .md-typeset .prerequisite > summary { - background-color: rgba(170, 170, 60, 0.1); - } - .md-typeset .prerequisite > .admonition-title::before, - .md-typeset .prerequisite > summary::before { - background-color: rgb(170, 170, 60); - -webkit-mask-image: var(--md-admonition-icon--prerequisite); - mask-image: var(--md-admonition-icon--prerequisite); - } - - .md-typeset .admonition.deprecated, - .md-typeset details.deprecated { - border-color: #ff1744; - } - .md-typeset .deprecated > .admonition-title, - .md-typeset .deprecated > summary { - background-color: #ff17441a; - } - .md-typeset .deprecated > .admonition-title::before, - .md-typeset .deprecated > summary::before { - background-color: #ff1744; - -webkit-mask-image: var(--md-status--deprecated); - mask-image: var(--md-status--deprecated); - } - :root { - --md-admonition-icon--pied-piper: url('data:image/svg+xml;charset=utf-8,') - } - .md-typeset .admonition.pied-piper, - .md-typeset details.pied-piper { - border-color: rgb(43, 155, 70); - } - .md-typeset .pied-piper > .admonition-title, - .md-typeset .pied-piper > summary { - background-color: rgba(43, 155, 70, 0.1); - } - .md-typeset .pied-piper > .admonition-title::before, - .md-typeset .pied-piper > summary::before { - background-color: rgb(43, 155, 70); - -webkit-mask-image: var(--md-admonition-icon--pied-piper); - mask-image: var(--md-admonition-icon--pied-piper); - } - - -:root { - --md-admonition-icon--desktop-download-24: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.desktop-download-24, -.md-typeset details.desktop-download-24 { - border-color: rgb(70,130,180); -} -.md-typeset .desktop-download-24 > .admonition-title, -.md-typeset .desktop-download-24 > summary { - background-color: rgba(70,130,180, 0.1); -} -.md-typeset .desktop-download-24 > .admonition-title::before, -.md-typeset .desktop-download-24 > summary::before { - background-color: rgb(70,130,180); - -webkit-mask-image: var(--md-admonition-icon--desktop-download-24); - mask-image: var(--md-admonition-icon--desktop-download-24); -} - -:root { - --md-admonition-icon--magnifying-glass: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.magnifying-glass, -.md-typeset details.magnifying-glass { - border-color: rgb(255,255,0); -} -.md-typeset .magnifying-glass > .admonition-title, -.md-typeset .magnifying-glass > summary { - background-color: rgba(255,255,0, 0.2); -} -.md-typeset .magnifying-glass > .admonition-title::before, -.md-typeset .magnifying-glass > summary::before { - background-color: rgb(25,25,112); - -webkit-mask-image: var(--md-admonition-icon--magnifying-glass); - mask-image: var(--md-admonition-icon--magnifying-glass); -} - -:root { - --md-admonition-icon--microscope: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.microscope, -.md-typeset details.microscope { - border-color: rgb(128,0,0); -} -.md-typeset .microscope > .admonition-title, -.md-typeset .microscope > summary { - background-color: rgba(128,0,0,0.1); -} -.md-typeset .microscope > .admonition-title::before, -.md-typeset .microscope > summary::before { - background-color: rgb(128,0,0); - -webkit-mask-image: var(--md-admonition-icon--microscope); - mask-image: var(--md-admonition-icon--microscope); -} - - -:root { - --md-admonition-icon--vial-virus: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.vial-virus, -.md-typeset details.vial-virus { - border-color: rgb(0,0,0); -} -.md-typeset .vial-virus > .admonition-title, -.md-typeset .vial-virus > summary { - background-color: rgba(0,0,0,0.1); -} -.md-typeset .vial-virus > .admonition-title::before, -.md-typeset .vial-virus > summary::before { - background-color: rgb(0,0,0); - -webkit-mask-image: var(--md-admonition-icon--vial-virus); - mask-image: var(--md-admonition-icon--vial-virus); -} - -:root { - --md-admonition-icon--database: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.database, -.md-typeset details.database { - border-color: rgb(255,215,0,0.1); -} -.md-typeset .database > .admonition-title, -.md-typeset .database > summary { - background-color: rgba(255,215,0); -} -.md-typeset .database > .admonition-title::before, -.md-typeset .database > summary::before { - background-color: rgb(112,128,144); - -webkit-mask-image: var(--md-admonition-icon--database); - mask-image: var(--md-admonition-icon--database); -} - -:root { - --md-admonition-icon--folder-open: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.folder-open, -.md-typeset details.folder-open { - border-color: rgb(0,100,0,0.1); -} -.md-typeset .folder-open > .admonition-title, -.md-typeset .folder-open > summary { - background-color: rgba(0,100,0,0.1); -} -.md-typeset .folder-open > .admonition-title::before, -.md-typeset .folder-open > summary::before { - background-color: rgb(112,128,144); - -webkit-mask-image: var(--md-admonition-icon--folder-open); - mask-image: var(--md-admonition-icon--folder-open); -} - - -:root { - --md-admonition-icon--backward: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.backward, -.md-typeset details.backward { - border-color: rgb(216,191,216); -} -.md-typeset .backward > .admonition-title, -.md-typeset .backward > summary { - background-color: rgba(216,191,216); -} -.md-typeset .backward > .admonition-title::before, -.md-typeset .backward > summary::before { - background-color: rgb(112,128,144); - -webkit-mask-image: var(--md-admonition-icon--backward); - mask-image: var(--md-admonition-icon--backward); -} - - -:root { - --md-admonition-icon--jupyter: url('data:image/svg+xml;charset=utf-8,Jupyter') -} -.md-typeset .admonition.jupyter, -.md-typeset details.jupyter { - border-color: rgb(47,79,79); -} -.md-typeset .jupyter > .admonition-title, -.md-typeset .jupyter > summary { - background-color: rgba(47,79,79,0.1); -} -.md-typeset .jupyter > .admonition-title::before, -.md-typeset .jupyter > summary::before { - background-color: rgb(255,140,0); - -webkit-mask-image: var(--md-admonition-icon--jupyter); - mask-image: var(--md-admonition-icon--jupyter); -} - - -:root { - --md-admonition-icon--terminal: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.terminal, -.md-typeset details.terminal { - border-color: rgb(105,105,105); -} -.md-typeset .terminal > .admonition-title, -.md-typeset .terminal > summary { - color:rgb(105,105,105); - background-color: rgba(105,105,105); -} -.md-typeset .terminal > .admonition-title::before, -.md-typeset .terminal > summary::before { - background-color: rgb(124,252,0); - -webkit-mask-image: var(--md-admonition-icon--terminal); - mask-image: var(--md-admonition-icon--terminal); -} - -:root { - --md-admonition-icon--r-project: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.r-project, -.md-typeset details.r-project { - border-color: rgb(135,206,235); -} -.md-typeset .r-project > .admonition-title, -.md-typeset .r-project > summary { - color:rgb(135,206,235); - background-color: rgba(135,206,235); -} -.md-typeset .r-project > .admonition-title::before, -.md-typeset .r-project > summary::before { - background-color: rgb(25,25,112); - -webkit-mask-image: var(--md-admonition-icon--r-project); - mask-image: var(--md-admonition-icon--r-project); -} - -:root { - --md-admonition-icon--calendar-days: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.calendar-days, -.md-typeset details.calendar-days { - border-color: rgb(135,206,235); -} -.md-typeset .calendar-days > .admonition-title, -.md-typeset .calendar-days > summary { - color:rgb(25,25,112); - background-color: rgba(135,206,235); -} -.md-typeset .calendar-days > .admonition-title::before, -.md-typeset .calendar-days > summary::before { - background-color: rgb(25,25,11225,25,112); - -webkit-mask-image: var(--md-admonition-icon--calendar-days); - mask-image: var(--md-admonition-icon--calendar-days); -} - -:root { - --md-admonition-icon--bell: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.bell, -.md-typeset details.bell { - border-color: rgb(255,215,0,0.1); -} -.md-typeset .bell > .admonition-title, -.md-typeset .bell > summary { - color:rgb(25,25,112); - background-color: rgba(255,215,0); -} -.md-typeset .bell > .admonition-title::before, -.md-typeset .bell > summary::before { - background-color: rgb(112,128,144); - -webkit-mask-image: var(--md-admonition-icon--bell); - mask-image: var(--md-admonition-icon--bell); -} - -:root { - --md-admonition-icon--comment-dots: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.comment-dots, -.md-typeset details.comment-dots { - border-color: rgb(47,79,79); -} -.md-typeset .comment-dots > .admonition-title, -.md-typeset .comment-dots > summary { - background-color: rgba(47,79,79,0.1); -} -.md-typeset .comment-dots > .admonition-title::before, -.md-typeset .comment-dots > summary::before { - background-color: rgb(255,140,0); - -webkit-mask-image: var(--md-admonition-icon--comment-dots); - mask-image: var(--md-admonition-icon--comment-dots); -} - -:root { - --md-admonition-icon--check-to-slot: url('data:image/svg+xml;charset=utf-8,') - } - .md-typeset .admonition.check-to-slot, - .md-typeset details.check-to-slot { - border-color: rgb(30, 182, 182); - } - .md-typeset .check-to-slot > .admonition-title, - .md-typeset .check-to-slot > summary { - background-color: rgba(114, 228, 152, 0.1); - } - .md-typeset .check-to-slot > .admonition-title::before, - .md-typeset .check-to-slot > summary::before { - background-color: rgb(12, 165, 114); - -webkit-mask-image: var(--md-admonition-icon--check-to-slot); - mask-image: var(--md-admonition-icon--check-to-slot); - } - - -:root { - --md-admonition-icon--square-xmark: url('data:image/svg+xml;charset=utf-8,') - } - .md-typeset .admonition.square-xmark, - .md-typeset details.square-xmark { - border-color: rgb(219, 166, 95); - } - .md-typeset .square-xmark > .admonition-title, - .md-typeset .square-xmark > summary { - background-color: rgba(221, 112, 62, 0.1); - } - .md-typeset .square-xmark > .admonition-title::before, - .md-typeset .square-xmark > summary::before { - background-color: rgb(207, 31, 18); - -webkit-mask-image: var(--md-admonition-icon--square-xmark); - mask-image: var(--md-admonition-icon--square-xmark); - } - - -:root { - --md-admonition-icon--rectangle-list: url('data:image/svg+xml;charset=utf-8,') - } - .md-typeset .admonition.rectangle-list, - .md-typeset details.rectangle-list { - border-color: rgb(168, 216, 153); - } - .md-typeset .rectangle-list > .admonition-title, - .md-typeset .rectangle-list > summary { - background-color: rgba(30, 145, 87, 0.315); - } - .md-typeset .rectangle-list > .admonition-title::before, - .md-typeset .rectangle-list > summary::before { - background-color: rgb(8, 92, 53); - -webkit-mask-image: var(--md-admonition-icon--rectangle-list); - mask-image: var(--md-admonition-icon--rectangle-list); - } - -:root { - --md-admonition-icon--screwdriver-wrench: url('data:image/svg+xml;charset=utf-8,') - } - .md-typeset .admonition.screwdriver-wrench, - .md-typeset details.screwdriver-wrench { - border-color: rgb(140, 141, 141); - } - .md-typeset .screwdriver-wrench > .admonition-title, - .md-typeset .screwdriver-wrench > summary { - background-color: rgba(248, 201, 48, 0.575); - } - .md-typeset .screwdriver-wrench > .admonition-title::before, - .md-typeset .screwdriver-wrench > summary::before { - background-color: rgb(16, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--screwdriver-wrench); - mask-image: var(--md-admonition-icon--screwdriver-wrench); - } - -:root { - --md-admonition-icon--linux: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.linux, - .md-typeset details.linux { - border-color: rgb(207, 127, 36); - } - .md-typeset .linux > .admonition-title, - .md-typeset .linux > summary { - background-color: rgba(235, 204, 66, 0.151); - } - .md-typeset .linux > .admonition-title::before, - .md-typeset .linux > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--linux); - mask-image: var(--md-admonition-icon--linux); - } - -:root { - --md-admonition-icon--code-compare: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.code-compare, - .md-typeset details.code-compare { - border-color: rgb(207, 127, 36); - } - .md-typeset .code-compare > .admonition-title, - .md-typeset .code-compare > summary { - background-color: rgba(235, 204, 66, 0.151); - } - .md-typeset .code-compare > .admonition-title::before, - .md-typeset .code-compare > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--code-compare); - mask-image: var(--md-admonition-icon--code-compare); - } - -:root { - --md-admonition-icon--heading: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.heading, - .md-typeset details.heading { - border-color: rgb(207, 127, 36); - } - .md-typeset .heading > .admonition-title, - .md-typeset .heading > summary { - background-color: rgba(236, 221, 84, 0.815); - } - .md-typeset .heading > .admonition-title::before, - .md-typeset .heading > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--heading); - mask-image: var(--md-admonition-icon--heading); - } - -:root { - --md-admonition-icon--space-awesome: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.space-awesome, - .md-typeset details.space-awesome { - border-color: rgb(207, 127, 36); - } - .md-typeset .space-awesome > .admonition-title, - .md-typeset .space-awesome > summary { - background-color: rgba(235, 204, 66, 0.151); - } - .md-typeset .space-awesome > .admonition-title::before, - .md-typeset .space-awesome > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--space-awesome); - mask-image: var(--md-admonition-icon--space-awesome); - } - -:root { - --md-admonition-icon--stethoscope: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.stethoscope, - .md-typeset details.stethoscope { - border-color: rgb(226, 74, 213); - } - .md-typeset .stethoscope > .admonition-title, - .md-typeset .stethoscope > summary { - background-color: rgba(77, 24, 61, 0.151); - } - .md-typeset .stethoscope > .admonition-title::before, - .md-typeset .stethoscope > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--stethoscope); - mask-image: var(--md-admonition-icon--stethoscope); - } - -:root { - --md-admonition-icon--key: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.key, - .md-typeset details.key { - border-color: rgb(235, 184, 90); - } - .md-typeset .key > .admonition-title, - .md-typeset .key > summary { - background-color: rgba(252, 207, 9, 0.151); - } - .md-typeset .key > .admonition-title::before, - .md-typeset .key > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--key); - mask-image: var(--md-admonition-icon--key); - } - -:root { - --md-admonition-icon--users-line: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.users-line, - .md-typeset details.users-line { - border-color: rgb(110, 226, 247); - } - .md-typeset .users-line > .admonition-title, - .md-typeset .users-line > summary { - background-color: rgba(94, 128, 219, 0.418); - } - .md-typeset .users-line > .admonition-title::before, - .md-typeset .users-line > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--users-line); - mask-image: var(--md-admonition-icon--users-line); - } - -:root { - --md-admonition-icon--file-code: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.file-code, - .md-typeset details.file-code { - border-color: rgb(235, 184, 90); - } - .md-typeset .file-code > .admonition-title, - .md-typeset .file-code > summary { - background-color: rgba(252, 207, 9, 0.151); - } - .md-typeset .file-code > .admonition-title::before, - .md-typeset .file-code > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--file-code); - mask-image: var(--md-admonition-icon--file-code); - } - -:root { - --md-admonition-icon--hand-holding-dollar: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.hand-holding-dollar, - .md-typeset details.hand-holding-dollar { - border-color: rgb(148, 233, 152); - } - .md-typeset .hand-holding-dollar > .admonition-title, - .md-typeset .hand-holding-dollar > summary { - background-color: rgba(26, 243, 6, 0.459); - } - .md-typeset .hand-holding-dollar > .admonition-title::before, - .md-typeset .hand-holding-dollar > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--hand-holding-dollar); - mask-image: var(--md-admonition-icon--hand-holding-dollar); - } - -:root { - --md-admonition-icon--circle-question: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.circle-question, - .md-typeset details.circle-question { - border-color: rgb(163, 84, 9); - } - .md-typeset .circle-question > .admonition-title, - .md-typeset .circle-question > summary { - background-color: rgba(241, 113, 27, 0.459); - } - .md-typeset .circle-question > .admonition-title::before, - .md-typeset .circle-question > summary::before { - background-color: rgb(202, 101, 43); - -webkit-mask-image: var(--md-admonition-icon--circle-question); - mask-image: var(--md-admonition-icon--circle-question); - } - -:root { - --md-admonition-icon--microphone: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.microphone, - .md-typeset details.microphone { - border-color: rgb(233, 220, 148); - } - .md-typeset .microphone > .admonition-title, - .md-typeset .microphone > summary { - background-color: rgba(223, 204, 97, 0.459); - } - .md-typeset .microphone > .admonition-title::before, - .md-typeset .microphone > summary::before { - background-color: rgb(15, 37, 65); - -webkit-mask-image: var(--md-admonition-icon--microphone); - mask-image: var(--md-admonition-icon--microphone); - } - - -:root { - --md-admonition-icon--tower-observation: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.tower-observation, - .md-typeset details.tower-observation { - border-color: rgb(201, 182, 10); - } - .md-typeset .tower-observation > .admonition-title, - .md-typeset .tower-observation > summary { - background-color: rgba(208, 216, 102, 0.459); - } - .md-typeset .tower-observation > .admonition-title::before, - .md-typeset .tower-observation > summary::before { - background-color: rgb(177, 98, 9); - -webkit-mask-image: var(--md-admonition-icon--tower-observation); - mask-image: var(--md-admonition-icon--tower-observation); - } - -:root { - --md-admonition-icon--circle-info: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.circle-info, - .md-typeset details.circle-info { - border-color: rgb(238, 156, 131); - } - .md-typeset .circle-info > .admonition-title, - .md-typeset .circle-info > summary { - background-color: rgba(240, 199, 19, 0.459); - } - .md-typeset .circle-info > .admonition-title::before, - .md-typeset .circle-info > summary::before { - background-color: rgb(235, 98, 80); - -webkit-mask-image: var(--md-admonition-icon--circle-info); - mask-image: var(--md-admonition-icon--circle-info); - } - -:root { - --md-admonition-icon--python: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.python, - .md-typeset details.python { - border-color: rgb(112, 201, 10); - } - .md-typeset .python > .admonition-title, - .md-typeset .python > summary { - background-color: rgba(54, 143, 13, 0.459); - } - .md-typeset .python > .admonition-title::before, - .md-typeset .python > summary::before { - background-color: rgb(3, 116, 12); - -webkit-mask-image: var(--md-admonition-icon--python); - mask-image: var(--md-admonition-icon--python); - } - -:root { - --md-admonition-icon--quote-right: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.quote-right, - .md-typeset details.quote-right { - border-color: rgb(211, 241, 190); - } - .md-typeset .quote-right > .admonition-title, - .md-typeset .quote-right > summary { - background-color: rgba(205, 231, 176, 0.459); - } - .md-typeset .quote-right > .admonition-title::before, - .md-typeset .quote-right > summary::before { - background-color: rgb(87, 172, 62); - -webkit-mask-image: var(--md-admonition-icon--quote-right); - mask-image: var(--md-admonition-icon--quote-right); - } - -:root { - --md-admonition-icon--image: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.image, - .md-typeset details.image { - border-color: rgb(211, 241, 190); - } - .md-typeset .image > .admonition-title, - .md-typeset .image > summary { - background-color: rgba(205, 231, 176, 0.459); - } - .md-typeset .image > .admonition-title::before, - .md-typeset .image > summary::before { - background-color: rgb(87, 172, 62); - -webkit-mask-image: var(--md-admonition-icon--image); - mask-image: var(--md-admonition-icon--image); - } - - -:root { - --md-admonition-icon--table: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.table, - .md-typeset details.table { - border-color: rgb(211, 241, 190); - } - .md-typeset .table > .admonition-title, - .md-typeset .table > summary { - background-color: rgba(205, 231, 176, 0.459); - } - .md-typeset .table > .admonition-title::before, - .md-typeset .table > summary::before { - background-color: rgb(87, 172, 62); - -webkit-mask-image: var(--md-admonition-icon--table); - mask-image: var(--md-admonition-icon--table); - } - -:root { - --md-admonition-icon--glass-chart: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.glass-chart, - .md-typeset details.glass-chart { - border-color: rgb(157, 204, 226); - } - .md-typeset .glass-chart > .admonition-title, - .md-typeset .glass-chart > summary { - background-color: rgba(90, 174, 189, 0.459); - } - .md-typeset .glass-chart > .admonition-title::before, - .md-typeset .glass-chart > summary::before { - background-color: rgb(30, 46, 184); - -webkit-mask-image: var(--md-admonition-icon--glass-chart); - mask-image: var(--md-admonition-icon--glass-chart); - } - -:root { - --md-admonition-icon--file-export: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.file-export, - .md-typeset details.file-export { - border-color: rgb(243, 234, 103); - } - .md-typeset .file-export > .admonition-title, - .md-typeset .file-export > summary { - background-color: rgba(233, 208, 95, 0.459); - } - .md-typeset .file-export > .admonition-title::before, - .md-typeset .file-export > summary::before { - background-color: rgb(168, 86, 9); - -webkit-mask-image: var(--md-admonition-icon--file-export); - mask-image: var(--md-admonition-icon--file-export); - } - -:root { - --md-admonition-icon--code: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.code, - .md-typeset details.code { - border-color: rgb(243, 234, 103); - } - .md-typeset .code > .admonition-title, - .md-typeset .code > summary { - background-color: rgba(233, 208, 95, 0.459); - } - .md-typeset .code > .admonition-title::before, - .md-typeset .code > summary::before { - background-color: rgb(168, 86, 9); - -webkit-mask-image: var(--md-admonition-icon--code); - mask-image: var(--md-admonition-icon--code); - } - -:root { - --md-admonition-icon--container: url('data:image/svg+xml;charset=utf-9,') - } - .md-typeset .admonition.container, - .md-typeset details.container { - border-color: rgb(223, 216, 154); - } - .md-typeset .container > .admonition-title, - .md-typeset .container > summary { - background-color: rgba(241, 228, 33, 0.459); - } - .md-typeset .container > .admonition-title::before, - .md-typeset .container > summary::before { - background-color: rgb(143, 100, ); - -webkit-mask-image: var(--md-admonition-icon--container); - mask-image: var(--md-admonition-icon--container); - } -9 diff --git a/docs/assets/stylesheets/footer.css b/docs/assets/stylesheets/footer.css deleted file mode 100644 index 14dc199dc..000000000 --- a/docs/assets/stylesheets/footer.css +++ /dev/null @@ -1,31 +0,0 @@ -#new-footer { - font-family: Lato; - font-size: 12px; - font-weight: 400; - background-color: #101010; -} - -#partners { - height: auto; - background-color: #101010; -} - -#partners #logos img { - height: 40px; - margin: 10px; -} - -#partners #logos { - padding: 10px; - text-align: center; -} - -#partners #logos .nesi-footer-logo img { - margin-right: 100px; - height: 60px; -} - -#partners #logos img { - height: 40px; - margin: 10px; -} \ No newline at end of file diff --git a/docs/assets/stylesheets/theme.css b/docs/assets/stylesheets/theme.css index 9332845af..8ff8bd7e8 100644 --- a/docs/assets/stylesheets/theme.css +++ b/docs/assets/stylesheets/theme.css @@ -35,6 +35,9 @@ } --md-status--tutorial: url('data:image/svg+xml;charset=utf-8, ') + --md-admonition-icon--prerequisite: url('data:image/svg+xml;charset=utf-8,') + --md-admonition-icon--time: url('data:image/svg+xml;charset=utf-8,') + } /* Logo biggification */ /* COMMENTED OUT FOR REANNZ LOGO */ @@ -187,6 +190,20 @@ span.md-status.md-status--deprecated { color: rgba(0, 0, 0, 0.87); } +/* Turirial deader */ +.tutorial-banner { + background: aquamarine; + color: blueviolet; + font-family: inherit; + padding: 0.01em; + margin: 0; + border-radius: 0.8em; +} +.tutorial-banner > p { + margin: 0; + padding: 0.2em 0.5em; +} +/* Calendar */ #calendar-banner { background: #fffae6; @@ -206,3 +223,95 @@ span.md-status.md-status--deprecated { font-size: 2em; cursor: pointer; } + +/* custom admonition */ +/* prereq */ + .md-typeset .admonition.prerequisite, + .md-typeset details.prerequisite { + border-color: rgb(170, 170, 60); + } + .md-typeset .prerequisite > .admonition-title, + .md-typeset .prerequisite > summary { + background-color: rgba(170, 170, 60, 0.1); + } + .md-typeset .prerequisite > .admonition-title::before, + .md-typeset .prerequisite > summary::before { + background-color: rgb(170, 170, 60); + -webkit-mask-image: var(--md-admonition-icon--prerequisite); + mask-image: var(--md-admonition-icon--prerequisite); + } + /* postreq */ + .md-typeset .admonition.postrequisite, + .md-typeset details.postrequisite { + border-color: rgb(170, 170, 60); + } + .md-typeset .postrequisite > .admonition-title, + .md-typeset .postrequisite > summary { + background-color: rgba(170, 170, 60, 0.1); + } + .md-typeset .postrequisite > .admonition-title::before, + .md-typeset .postrequisite > summary::before { + background-color: rgb(170, 170, 60); + -webkit-mask-image: var(--md-admonition-icon--postrequisite); + mask-image: var(--md-admonition-icon--postrequisite); + } +/* deprecated */ + .md-typeset .admonition.deprecated, + .md-typeset details.deprecated { + border-color: #ff1744; + } + .md-typeset .deprecated > .admonition-title, + .md-typeset .deprecated > summary { + background-color: #ff17441a; + } + .md-typeset .deprecated > .admonition-title::before, + .md-typeset .deprecated > summary::before { + background-color: #ff1744; + -webkit-mask-image: var(--md-status--deprecated); + mask-image: var(--md-status--deprecated); + } +/* time */ + .md-typeset .admonition.time, + .md-typeset details.time { + border-color: #610088; + } + .md-typeset .time > .admonition-title, + .md-typeset .time > summary { + background-color: #b700cf1a; + } + .md-typeset .time > .admonition-title::before, + .md-typeset .time > summary::before { + background-color: #ff3f66; + -webkit-mask-image: var(--md-admonition-icon--time); + mask-image: var(--md-admonition-icon--time); + } +/* objective */ + .md-typeset .admonition.time, + .md-typeset details.time { + border-color: #765981; + } + .md-typeset .time > .admonition-title, + .md-typeset .time > summary { + background-color: #5e9b2d1a; + } + .md-typeset .time > .admonition-title::before, + .md-typeset .time > summary::before { + background-color: #0e0b0b; + -webkit-mask-image: var(--md-admonition-icon--time); + mask-image: var(--md-admonition-icon--time); + } +/* key[ppoint */ + .md-typeset .admonition.keypoints, + .md-typeset details.keypoints { + border-color: #000000; + } + .md-typeset .keypoints > .admonition-title, + .md-typeset .keypoints > summary { + background-color: #e990f51a; + } + .md-typeset .keypoints > .admonition-title::before, + .md-typeset .keypoints > summary::before { + background-color: #3fffff; + -webkit-mask-image: var(--md-admonition-icon--keypoints); + mask-image: var(--md-admonition-icon--keypoints); + } diff --git a/mkdocs.yml b/mkdocs.yml index bc6e2cb37..5d1d0f533 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -102,8 +102,6 @@ plugins: module_name: macro_hooks include_dir: overrides extra_css: - - assets/stylesheets/footer.css - - assets/stylesheets/custom_admonations.css - assets/stylesheets/theme.css extra_javascript: - assets/javascripts/general.js From a4878f21143f8271e055b96013833545b09a38b4 Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Thu, 15 Jan 2026 13:45:14 +1300 Subject: [PATCH 21/23] Merge other branch, add all to top level tutorials section. --- docs/.pages.yml | 1 + docs/Batch_Computing/.pages.yml | 1 - .../Accessing_the_HPCs/VSCode.md | 2 +- .../Cheat_Sheets/Slurm-Reference_Sheet.md | 2 +- .../Intro_HPC/14-environment-variables.md | 258 ------------- .../Training/Intro_HPC/Filesystem_basics.md | 214 ----------- .../Training/Intro_HPC/Modules.md | 258 ------------- .../Training/Intro_HPC/Scheduler.md | 338 ------------------ .../OnDemand/Apps/JupyterLab/index.md | 2 +- docs/Tutorials/Introduction_To_HPC/.pages.yml | 9 + .../Introduction_To_HPC/Bash_Shell.md} | 10 +- .../Environment_And_Modules.md} | 4 +- .../Introduction_To_HPC}/Parallel.md | 0 .../Introduction_To_HPC}/Resources.md | 0 .../Introduction_To_HPC}/Scaling.md | 4 +- .../Submitting_Your_First_Job.md} | 9 +- .../What_Is_a_HPC_cluster.md | 2 +- .../Introduction_To_HPC}/writing_good_code.md | 0 18 files changed, 27 insertions(+), 1087 deletions(-) delete mode 100644 docs/Getting_Started/Getting_Help/Training/Intro_HPC/14-environment-variables.md delete mode 100644 docs/Getting_Started/Getting_Help/Training/Intro_HPC/Filesystem_basics.md delete mode 100644 docs/Getting_Started/Getting_Help/Training/Intro_HPC/Modules.md delete mode 100644 docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scheduler.md create mode 100644 docs/Tutorials/Introduction_To_HPC/.pages.yml rename docs/{Getting_Started/Getting_Help/Training/Intro_HPC/Bash_shell.md => Tutorials/Introduction_To_HPC/Bash_Shell.md} (98%) rename docs/{Software/Ako_Environment_And_Modules.md => Tutorials/Introduction_To_HPC/Environment_And_Modules.md} (99%) rename docs/{Getting_Started/Getting_Help/Training/Intro_HPC => Tutorials/Introduction_To_HPC}/Parallel.md (100%) rename docs/{Getting_Started/Getting_Help/Training/Intro_HPC => Tutorials/Introduction_To_HPC}/Resources.md (100%) rename docs/{Getting_Started/Getting_Help/Training/Intro_HPC => Tutorials/Introduction_To_HPC}/Scaling.md (93%) rename docs/{Batch_Computing/Ako_Submitting_Your_First_Job.md => Tutorials/Introduction_To_HPC/Submitting_Your_First_Job.md} (98%) rename docs/{Getting_Started/Getting_Help/Training/Intro_HPC => Tutorials/Introduction_To_HPC}/What_Is_a_HPC_cluster.md (97%) rename docs/{Getting_Started/Getting_Help/Training/Intro_HPC => Tutorials/Introduction_To_HPC}/writing_good_code.md (100%) diff --git a/docs/.pages.yml b/docs/.pages.yml index fa74dbc2a..e67e341c6 100644 --- a/docs/.pages.yml +++ b/docs/.pages.yml @@ -7,3 +7,4 @@ nav: - Storage - Data_Transfer - Service_Subscriptions + - Tutorials diff --git a/docs/Batch_Computing/.pages.yml b/docs/Batch_Computing/.pages.yml index 2d39b002a..da8072727 100644 --- a/docs/Batch_Computing/.pages.yml +++ b/docs/Batch_Computing/.pages.yml @@ -7,5 +7,4 @@ nav: - Job_Checkpointing.md - Fair_Share.md - Checksums.md - - Tutorial:_Submitting_your_first_job.md - "*" diff --git a/docs/Getting_Started/Accessing_the_HPCs/VSCode.md b/docs/Getting_Started/Accessing_the_HPCs/VSCode.md index 878f9844f..afc9139c0 100644 --- a/docs/Getting_Started/Accessing_the_HPCs/VSCode.md +++ b/docs/Getting_Started/Accessing_the_HPCs/VSCode.md @@ -83,7 +83,7 @@ Clicking on these will open a connection to that machine, you will then be promp You may find that VSCode is not utilising your preferred versions of software (e.g. when debugging or linting your Python code). -As the NeSI cluster utilises [Environment Modules](../../Batch_Computing/Ako_Submitting_Your_First_Job.md#environment-modules), changing the executable used is not just a matter of changing the path in VSCode configuration, as the libraries required will not be loaded. +As the NeSI cluster utilises [Environment Modules](../../Tutorials/Introduction_To_HPC/Submitting_Your_First_Job.md#environment-modules), changing the executable used is not just a matter of changing the path in VSCode configuration, as the libraries required will not be loaded. The only way to make sure that VSCode has access to a suitable environment, is to load the required modules in your `~/.bashrc` diff --git a/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md b/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md index 70c4e1fe0..5234418f4 100644 --- a/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md +++ b/docs/Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md @@ -8,7 +8,7 @@ description: Quick list of the most commonly used Slurm commands, flags, and env --- If you are unsure about using our job scheduler Slurm, more details can -be found on [Batch Computing Guide](../../Batch_Computing/Batch_Computing_Guide.md) and we have a self-paced tutorial on [Submitting your first job](../../Batch_Computing/Ako_Submitting_Your_First_Job.md). +be found on [Batch Computing Guide](../../Batch_Computing/Batch_Computing_Guide.md) and we have a self-paced tutorial on [Submitting your first job](../../Tutorials/Introduction_To_HPC/Submitting_Your_First_Job.md). ## Slurm Commands diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/14-environment-variables.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/14-environment-variables.md deleted file mode 100644 index b13cc5ca6..000000000 --- a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/14-environment-variables.md +++ /dev/null @@ -1,258 +0,0 @@ ---- -title: Environment Variables -teaching: 10 -exercises: 5 -questions: -- "How are variables set and accessed in the Unix shell?" -- "How can I use variables to change how a program runs?" -objectives: -- "Understand how variables are implemented in the shell" -- "Read the value of an existing variable" -- "Create new variables and change their values" -- "Change the behaviour of a program using an environment variable" -- "Explain how the shell uses the `PATH` variable to search for executables" -keypoints: -- "Shell variables are by default treated as strings" -- "Variables are assigned using \"`=`\" and recalled using the variable's name prefixed by \"`$`\"" -- "Use \"`export`\" to make an variable available to other programs" -- "The `PATH` variable defines the shell's search path" ---- - -> ## Episode provenance -> -> This episode has been remixed from the -> [Shell Extras episode on Shell Variables](https://github.com/carpentries-incubator/shell-extras/blob/gh-pages/_episodes/08-environment-variables.md) -> and the [HPC Shell episode on scripts](https://github.com/hpc-carpentry/hpc-shell/blob/gh-pages/_episodes/05-scripts.md) -{: .callout} - -The shell is just a program, and like other programs, it has variables. -Those variables control its execution, -so by changing their values -you can change how the shell behaves (and with a little more effort how other -programs behave). - -Variables -are a great way of saving information under a name you can access later. In -programming languages like Python and R, variables can store pretty much -anything you can think of. In the shell, they usually just store text. The best -way to understand how they work is to see them in action. - -Let's start by running the command `set` and looking at some of the variables -in a typical shell session: - -~~~ -$ set -~~~ -{: .language-bash} - -~~~ -COMPUTERNAME=TURING -HOME=/home/vlad -HOSTNAME=TURING -HOSTTYPE=i686 -NUMBER_OF_PROCESSORS=4 -PATH=/Users/vlad/bin:/usr/local/git/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin -PWD=/home/vlad -UID=1000 -USERNAME=vlad -... -~~~ -{: .output} - -As you can see, there are quite a few — in fact, -four or five times more than what's shown here. -And yes, using `set` to *show* things might seem a little strange, -even for Unix, but if you don't give it any arguments, -it might as well show you things you *could* set. - -Every variable has a name. -All shell variables' values are strings, -even those (like `UID`) that look like numbers. -It's up to programs to convert these strings to other types when necessary. -For example, if a program wanted to find out how many processors the computer -had, it would convert the value of the `NUMBER_OF_PROCESSORS` variable from a -string to an integer. - -## Showing the Value of a Variable - -Let's show the value of the variable `HOME`: - -~~~ -$ echo HOME -~~~ -{: .language-bash} - -~~~ -HOME -~~~ -{: .output} - -That just prints "HOME", which isn't what we wanted -(though it is what we actually asked for). -Let's try this instead: - -~~~ -$ echo $HOME -~~~ -{: .language-bash} - -~~~ -/home/vlad -~~~ -{: .output} - -The dollar sign tells the shell that we want the *value* of the variable -rather than its name. -This works just like wildcards: -the shell does the replacement *before* running the program we've asked for. -Thanks to this expansion, what we actually run is `echo /home/vlad`, -which displays the right thing. - -## Creating and Changing Variables - -Creating a variable is easy — we just assign a value to a name using "=" -(we just have to remember that the syntax requires that there are _no_ spaces -around the `=`!): - -~~~ -$ SECRET_IDENTITY=Dracula -$ echo $SECRET_IDENTITY -~~~ -{: .language-bash} - -~~~ -Dracula -~~~ -{: .output} - -To change the value, just assign a new one: - -~~~ -$ SECRET_IDENTITY=Camilla -$ echo $SECRET_IDENTITY -~~~ -{: .language-bash} - -~~~ -Camilla -~~~ -{: .output} - -## Environment variables - -When we ran the `set` command we saw there were a lot of variables whose names -were in upper case. That's because, by convention, variables that are also -available to use by _other_ programs are given upper-case names. Such variables -are called _environment variables_ as they are shell variables that are defined -for the current shell and are inherited by any child shells or processes. - -To create an environment variable you need to `export` a shell variable. For -example, to make our `SECRET_IDENTITY` available to other programs that we call -from our shell we can do: - -~~~ -$ SECRET_IDENTITY=Camilla -$ export SECRET_IDENTITY -~~~ -{: .language-bash} - -You can also create and export the variable in a single step: - -~~~ -$ export SECRET_IDENTITY=Camilla -~~~ -{: .language-bash} - -> ## Using environment variables to change program behaviour -> -> Set a shell variable `TIME_STYLE` to have a value of `iso` and check this -> value using the `echo` command. -> -> Now, run the command `ls` with the option `-l` (which gives a long format). -> -> `export` the variable and rerun the `ls -l` command. Do you notice any -> difference? -> -> > ## Solution -> > -> > The `TIME_STYLE` variable is not _seen_ by `ls` until is exported, at which -> > point it is used by `ls` to decide what date format to use when presenting -> > the timestamp of files. -> > -> {: .solution} -{: .challenge} - -You can see the complete set of environment variables in your current shell -session with the command `env` (which returns a subset of what the command -`set` gave us). **The complete set of environment variables is called -your _runtime environment_ and can affect the behaviour of the programs you -run**. - -{% include {{ site.snippets }}/scheduler/print-sched-variables.snip %} - -To remove a variable or environment variable you can use the `unset` command, -for example: - -~~~ -$ unset SECRET_IDENTITY -~~~ -{: .language-bash} - -## The `PATH` Environment Variable - -Similarly, some environment variables (like `PATH`) store lists of values. -In this case, the convention is to use a colon ':' as a separator. -If a program wants the individual elements of such a list, -it's the program's responsibility to split the variable's string value into -pieces. - -Let's have a closer look at that `PATH` variable. -Its value defines the shell's search path for executables, -i.e., the list of directories that the shell looks in for runnable programs -when you type in a program name without specifying what directory it is in. - -For example, when we type a command like `analyze`, -the shell needs to decide whether to run `./analyze` or `/bin/analyze`. -The rule it uses is simple: -the shell checks each directory in the `PATH` variable in turn, -looking for a program with the requested name in that directory. -As soon as it finds a match, it stops searching and runs the program. - -To show how this works, -here are the components of `PATH` listed one per line: - -~~~ -/Users/vlad/bin -/usr/local/git/bin -/usr/bin -/bin -/usr/sbin -/sbin -/usr/local/bin -~~~ -{: .output} - -On our computer, -there are actually three programs called `analyze` -in three different directories: -`/bin/analyze`, -`/usr/local/bin/analyze`, -and `/users/vlad/analyze`. -Since the shell searches the directories in the order they're listed in `PATH`, -it finds `/bin/analyze` first and runs that. -Notice that it will *never* find the program `/users/vlad/analyze` -unless we type in the full path to the program, -since the directory `/users/vlad` isn't in `PATH`. - -This means that I can have executables in lots of different places as long as -I remember that I need to to update my `PATH` so that my shell can find them. - -What if I want to run two different versions of the same program? -Since they share the same name, if I add them both to my `PATH` the first one -found will always win. -In the next episode we'll learn how to use helper tools to help us manage our -runtime environment to make that possible without us needing to do a lot of -bookkeeping on what the value of `PATH` (and other important environment -variables) is or should be. - -{% include links.md %} diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Filesystem_basics.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Filesystem_basics.md deleted file mode 100644 index 5dbef2d76..000000000 --- a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Filesystem_basics.md +++ /dev/null @@ -1,214 +0,0 @@ ---- -title: "NeSI Filesystem" -teaching: 15 -exercises: 5 -questions: -- "Where is the best place to store my data?" -- "How do I recover deleted files?" -- "How do I find out how much disk space I have?" -objectives: -- "Learn about the NeSI filesystems, and when to use each one." -keypoints: -- "" - ---- - -The NeSI filesystem looks something like this: - -![The file system is made up of a root directory that contains sub-directories -titled home, nesi, and system files](../fig/NesiFiletree.svg) - -The directories that are relevant to us are. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LocationDefault StorageDefault FilesBackupAccess Speed
Home is for user-specific files such as configuration files, environment setup, source code, etc./home/<username>20GB1,000,000DailyNormal
Project is for persistent project-related data, project-related software, etc./nesi/project/<projectcode>100GB100,000DailyNormal
Nobackup is a 'scratch space', for data you don't need to keep long term. Old data is periodically deleted from nobackup/nesi/nobackup/<projectcode>10TB1,000,000NoneFast
- -### Managing your data and storage (backups and quotas) - -NeSI performs backups of the `/home` and `/nesi/project` (persistent) filesystems. However, backups are only captured once per day. So, if you edit or change code or data and then immediately delete it, it likely cannot be recovered. Note, as the name suggests, NeSI does **not** backup the `/nesi/nobackup` filesystem. - -Protecting critical data from corruption or deletion is primarily your -responsibility. Ensure you have a data management plan and stick to the plan to reduce the chance of data loss. Also important is managing your storage quota. To check your quotas, use the `nn_storage_quota` command, eg - -{% include {{ site.snippets }}/filedir/sinfo.snip %} - -As well as disk space, 'inodes' are also tracked, this is the *number* of files. - -Notice that the project space for this user is over quota and has been locked, meaning no more data can be added. When your space is locked you will need to move or remove data. Also note that none of the nobackup space is being used. Likely data from project can be moved to nobackup. `nn_storage_quota` uses cached data, and so will no immediately show changes to storage use. - -For more details on our persistent and nobackup storage systems, including data retention and the nobackup autodelete schedule, -please see our [Filesystem and Quota](https://docs.nesi.org.nz/Storage/File_Systems_and_Quotas/NeSI_File_Systems_and_Quotas/) documentation. - -### Working Directory - -We will be working from the directory `{{ site.working_dir[-1] }}`. - -``` -{{ site.remote.prompt }} cd {{ site.working_dir | join: '/' }} -``` - -{: .language-bash} - -### Creating directories - - - -As previously mentioned, it is general useful to organise your work in a hierarchical file structure to make managing and finding files easier. It is also is especially important when working within a shared directory with colleagues, such as a project, to minimise the chance of accidentally affecting your colleagues work. So for this workshop you will each make a directory using the `mkdir` command within the workshops directory for you to personally work from. - -``` -{{ site.remote.prompt }} mkdir -``` - -{: .language-bash} - -You should then be able to see your new directory is there using `ls`. - -``` -{{ site.remote.prompt }} ls {{ site.working_dir | join: '/' }} -``` - -{: .language-bash} - -{% include {{ site.snippets }}/filedir/dir-contents1.snip %} - -## Create a text file - -Now let's create a file. To do this we will use a text editor called Nano to create a file called `draft.txt`: - -We will want to do this from inside the directory we just created. - -``` -{{ site.remote.prompt }} cd -{{ site.remote.prompt }} nano draft.txt -``` - -{: .language-bash} - -> ## Which Editor? -> -> When we say, '`nano` is a text editor' we really do mean 'text': it can -> only work with plain character data, not tables, images, or any other -> human-friendly media. We use it in examples because it is one of the -> least complex text editors. However, because of this trait, it may -> not be powerful enough or flexible enough for the work you need to do -> after this workshop. On Unix systems (such as Linux and macOS), -> many programmers use [Emacs](http://www.gnu.org/software/emacs/) or -> [Vim](http://www.vim.org/) (both of which require more time to learn), -> or a graphical editor such as -> [Gedit](http://projects.gnome.org/gedit/). On Windows, you may wish to -> use [Notepad++](http://notepad-plus-plus.org/). Windows also has a built-in -> editor called `notepad` that can be run from the command line in the same -> way as `nano` for the purposes of this lesson. -> -> No matter what editor you use, you will need to know where it searches -> for and saves files. If you start it from the shell, it will (probably) -> use your current working directory as its default location. If you use -> your computer's start menu, it may want to save files in your desktop or -> documents directory instead. You can change this by navigating to -> another directory the first time you 'Save As...' -{: .callout} - -Let's type in a few lines of text. -Once we're happy with our text, we can press Ctrl+O -(press the Ctrl or Control key and, while -holding it down, press the O key) to write our data to disk -(we'll be asked what file we want to save this to: -press Return to accept the suggested default of `draft.txt`). - -
screenshot of nano text editor in action
- -Once our file is saved, we can use Ctrl+X to quit the editor and -return to the shell. - -> ## Control, Ctrl, or ^ Key -> -> The Control key is also called the 'Ctrl' key. There are various ways -> in which using the Control key may be described. For example, you may -> see an instruction to press the Control key and, while holding it down, -> press the X key, described as any of: -> -> * `Control-X` -> * `Control+X` -> * `Ctrl-X` -> * `Ctrl+X` -> * `^X` -> * `C-x` -> -> In nano, along the bottom of the screen you'll see `^G Get Help ^O WriteOut`. -> This means that you can use `Control-G` to get help and `Control-O` to save your -> file. -{: .callout} - -`nano` doesn't leave any output on the screen after it exits, -but `ls` now shows that we have created a file called `draft.txt`: - -``` -{{ site.remote.prompt }} ls -``` - -{: .language-bash} - -``` -draft.txt -``` - -{: .output} - -## Copying files and directories - -In a future lesson, we will be running the R script ```{{ site.working_dir | join: '/' }}/{{ site.example.script }} ```, but as we can't all work on the same file at once you will need to take your own copy. This can be done with the **c**o**p**y command `cp`, at least two arguments are needed the file (or directory) you want to copy, and the directory (or file) where you want the copy to be created. We will be copying the file into the directory we made previously, as this should be your current directory the second argument can be a simple `.`. - -``` -{{ site.remote.prompt }} cp {{ site.working_dir | join: '/' }}/{{ site.example.script }} . -``` - -{: .output} - -We can check that it did the right thing using `ls` - -``` -{{ site.remote.prompt }} ls -``` - -{: .language-bash} - -``` -draft.txt {{ site.example.script }} -``` - -{: .output} diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Modules.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Modules.md deleted file mode 100644 index 232bcae18..000000000 --- a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Modules.md +++ /dev/null @@ -1,258 +0,0 @@ ---- -title: "Accessing software via Modules" -teaching: 15 -exercises: 5 -questions: -- "How do we load and unload software packages?" -objectives: -- "Load and use a software package." -- "Explain how the shell environment changes when the module mechanism loads or unloads packages." -keypoints: -- "Load software with `module load softwareName`." -- "Unload software with `module unload`" -- "The module system handles software versioning and package conflicts for you - automatically." ---- - -On a high-performance computing system, it is seldom the case that the software -we want to use is available when we log in. It is installed, but we will need -to "load" it before it can run. - -Before we start using individual software packages, however, we should -understand the reasoning behind this approach. The three biggest factors are: - -- software incompatibilities -- versioning -- dependencies - -Software incompatibility is a major headache for programmers. Sometimes the -presence (or absence) of a software package will break others that depend on -it. Two of the most famous examples are Python 2 and 3 and C compiler versions. -Python 3 famously provides a `python` command that conflicts with that provided -by Python 2. Software compiled against a newer version of the C libraries and -then used when they are not present will result in a nasty `'GLIBCXX_3.4.20' -not found` error, for instance. - - - -Software versioning is another common issue. A team might depend on a certain -package version for their research project - if the software version was to -change (for instance, if a package was updated), it might affect their results. -Having access to multiple software versions allows a set of researchers to -prevent software versioning issues from affecting their results. - -Dependencies are where a particular software package (or even a particular -version) depends on having access to another software package (or even a -particular version of another software package). For example, the VASP -materials science software may depend on having a particular version of the -FFTW (Fastest Fourier Transform in the West) software library available for it -to work. - -## Environment - -Before understanding environment modules we first need to understand what is meant by _environment_. - -The environment is defined by it's _environment variables_. - -_Environment Variables_ are writable named-variables. - -We can assign a variable named "FOO" with the value "bar" using the syntax. - -``` -{{ site.remote.prompt }} FOO="bar" -``` -{: .language-bash} - -Convention is to name fixed variables in all caps. - -Our new variable can be referenced using `$FOO`, you could also use `${FOO}`, -enclosing a variable in curly brackets is good practice as it avoids possible ambiguity. - -``` -{{ site.remote.prompt }} $FOO -``` -{: .language-bash} - -``` --bash: bar: command not found -``` -{: .output} - -We got an error here because the variable is evalued _in the terminal_ then executed. -If we just want to print the variable we can use the command, - -``` -{{ site.remote.prompt }} echo $FOO -``` -{: .language-bash} -``` -bar -``` -{: .output} - -We can get a full list of environment variables using the command, - -``` -{{ site.remote.prompt }} env -``` -{: .language-bash} -{% include {{ site.snippets }}/modules/env-output.snip %} - -These variables control many aspects of how your terminal, and any software launched from your terminal works. - -## Environment Modules - -Environment modules are the solution to these problems. A _module_ is a -self-contained description of a software package -- it contains the -settings required to run a software package and, usually, encodes required -dependencies on other software packages. - -There are a number of different environment module implementations commonly -used on HPC systems: the two most common are _TCL modules_ and _Lmod_. Both of -these use similar syntax and the concepts are the same so learning to use one -will allow you to use whichever is installed on the system you are using. In -both implementations the `module` command is used to interact with environment -modules. An additional subcommand is usually added to the command to specify -what you want to do. For a list of subcommands you can use `module -h` or -`module help`. As for all commands, you can access the full help on the _man_ -pages with `man module`. - -### Purging Modules - -Depending on how you are accessing the HPC the modules you have loaded by default will be different. So before we start listing our modules we will first use the `module purge` command to clear all but the minimum default modules so that we are all starting with the same modules. - -``` -{{ site.remote.prompt }} module purge -``` -{: .language-bash} - -``` - -The following modules were not unloaded: - (Use "module --force purge" to unload all): - - 1) XALT/minimal 2) slurm 3) NeSI -``` -{: .output} - -Note that `module purge` is informative. It lets us know that all but a minimal default -set of packages have been unloaded (and how to actually unload these if we -truly so desired). - -We are able to unload individual modules, unfortunately within the NeSI system it does not always unload it's dependencies, therefore we recommend `module purge` to bring you back to a state where only those modules needed to perform your normal work on the cluster. - -`module purge` is a useful tool for ensuring repeatable research by guaranteeing that the environment that you build your software stack from is always the same. This is important since some modules have the potential to silently effect your results if they are loaded (or not loaded). - -### Listing Available Modules - -To see available software modules, use `module avail`: - -``` -{{ site.remote.prompt }} module avail -``` -{: .language-bash} - -{% include {{ site.snippets }}/modules/available-modules.snip %} - -### Listing Currently Loaded Modules - -You can use the `module list` command to see which modules you currently have -loaded in your environment. On {{ site.remote.name }} you will have a few default modules loaded when you login. - -``` -{{ site.remote.prompt }} module list -``` -{: .language-bash} - -{% include {{ site.snippets }}/modules/module-list-default.snip %} - -## Loading and Unloading Software - -You can load software using the `module load` command. In this example we will be using the programming language _R_. - -Initially, R is not loaded. We can test this by using the `which` -command. `which` looks for programs the same way that Bash does, so we can use -it to tell us where a particular piece of software is stored. - -``` -{{ site.remote.prompt }} which R -``` -{: .language-bash} - -{% include {{ site.snippets }}/modules/missing-r.snip %} - -The important bit here being: - -``` -/usr/bin/which: no R in (...) -``` - -Now lets try loading the R environment module, and try again. - -{% include {{ site.snippets }}/modules/module-load-r.snip %} - -> ## Tab Completion -> -> The module command also supports tab completion. You may find this the easiest way to find the right software. -{: .callout} - -So, what just happened? - -To understand the output, first we need to understand the nature of the `$PATH` -environment variable. `$PATH` is a special environment variable that controls -where a UNIX system looks for software. Specifically `$PATH` is a list of -directories (separated by `:`) that the OS searches through for a command -before giving up and telling us it can't find it. As with all environment -variables we can print it out using `echo`. - -{% include {{ site.snippets }}/modules/r-module-path.snip %} - -You'll notice a similarity to the output of the `which` command. However, in this case, -there are a lot more directories at the beginning. When we -ran the `module load` command, it added many directories to the beginning of our -`$PATH`. - -The path to NeSI XALT utility will normally show up first. This helps us track software usage, but the more important directory is the second one: `/opt/nesi/CS400_centos7_bdw/R/4.2.1-gimkl-2022a/bin` Let's examine what's there: - -{% include {{ site.snippets }}/modules/r-ls-dir-command.snip %} - -`module load` "loads" not only the specified software, but it also loads software dependencies. That is, the software that the application you load requires to run. - -{% include {{ site.snippets }}/modules/software-dependencies.snip %} - -Before moving onto the next session lets use `module purge` again to return to the minimal environment. - -``` -{{ site.remote.prompt }} module purge -``` -{: .language-bash} - -``` -The following modules were not unloaded: - (Use "module --force purge" to unload all): - - 1) XALT/minimal 2) slurm 3) NeSI -``` -{: .output} - -## Software Versioning - -So far, we've learned how to load and unload software packages. However, we have not yet addressed the issue of software versioning. At -some point or other, you will run into issues where only one particular version -of some software will be suitable. Perhaps a key bugfix only happened in a -certain version, or version _X_ broke compatibility with a file format you use. -In either of these example cases, it helps to be very specific about what -software is loaded. - -Let's examine the output of `module avail` more closely. - -``` -{{ site.remote.prompt }} module avail -``` -{: .language-bash} - -{% include {{ site.snippets }}/modules/available-modules.snip %} - -{% include {{ site.snippets }}/modules/wrong-python-version.snip %} - -{% include links.md %} diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scheduler.md b/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scheduler.md deleted file mode 100644 index ba3980ef4..000000000 --- a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scheduler.md +++ /dev/null @@ -1,338 +0,0 @@ ---- -title: "Scheduler Fundamentals" -teaching: 15 -exercises: 10 -questions: -- "What is a scheduler and why does a cluster need one?" -- "How do I launch a program to run on a compute node in the cluster?" -- "How do I capture the output of a program that is run on a node in the - cluster?" -objectives: -- "Run a simple script on the login node, and through the scheduler." -- "Use the batch system command line tools to monitor the execution of your - job." -- "Inspect the output and error files of your jobs." -- "Find the right place to put large datasets on the cluster." -keypoints: -- "The scheduler handles how compute resources are shared between users." -- "A job is just a shell script." -- "Request _slightly_ more resources than you will need." ---- - -## Job Scheduler - -An HPC system might have thousands of nodes and thousands of users. How do we -decide who gets what and when? How do we ensure that a task is run with the -resources it needs? This job is handled by a special piece of software called -the _scheduler_. On an HPC system, the scheduler manages which jobs run where -and when. - -The following illustration compares these tasks of a job scheduler to a waiter -in a restaurant. If you can relate to an instance where you had to wait for a -while in a queue to get in to a popular restaurant, then you may now understand -why sometimes your job do not start instantly as in your laptop. - -{% include figure.html max-width="75%" caption="" - file="/fig/restaurant_queue_manager.svg" - alt="Compare a job scheduler to a waiter in a restaurant" %} - -The scheduler used in this lesson is {{ site.sched.name }}. Although -{{ site.sched.name }} is not used everywhere, running jobs is quite similar -regardless of what software is being used. The exact syntax might change, but -the concepts remain the same. - -## Interactive vs Batch - -So far, whenever we have entered a command into our terminals, we have received the response immediately in the same terminal, this is said to be an _interactive session_. - -[//]: # TODO ??Diagram?? - -This is all well for doing small tasks, but what if we want to do several things one after another without without waiting in-between? Or what if we want to repeat a series of command again later? - -This is where _batch processing_ becomes useful, this is where instead of entering commands directly to the terminal we write them down in a text file or _script_. Then, the script can be _executed_ by calling it with `bash`. - -[//]: # TODO ??Diagram?? - -Lets try this now, create and open a new file in your current directory called `example_job.sh`. -(If you prefer another text editor than nano, feel free to use that), we will put to use some things we have learnt so far. - -``` -{{ site.remote.prompt }} nano example_job.sh -``` -{: .language-bash} - - -``` -{% include example_scripts/example_job.sh %} -``` -{: .language-bash} - -> ## shebang -> -> _shebang_ or _shabang_, also referred to as _hashbang_ is the character sequence consisting of the number sign (aka: hash) and exclamation mark (aka: bang): `#!` at the beginning of a script. It is used to describe the _interpreter_ that will be used to run the script. In this case we will be using the Bash Shell, which can be found at the path `/bin/bash`. The job scheduler will give you an error if your script does not start with a shebang. -> -{: .callout} - -We can now run this script using -``` -{{ site.remote.prompt }} bash example_job.sh -``` -{: .language-bash} - -``` -Loading required package: foreach -Loading required package: iterators -Loading required package: parallel -[1] "Using 1 cpus to sum [ 2.000000e+04 x 2.000000e+04 ] matrix." -[1] "0% done..." -... -[1] "99% done..." -[1] "100% done..." -[1] "Sum is '10403.632886'." -Done! -``` -{: .output} - -You will get the output printed to your terminal as if you had just run those commands one after another. - -> ## Cancelling Commands -> -> You can kill a currently running task by pressing the keys ctrl + c. -> If you just want your terminal back, but want the task to continue running you can 'background' it by pressing ctrl + v. -> Note, a backgrounded task is still attached to your terminal session, and will be killed when you close the terminal (if you need to keep running a task after you log out, have a look at [tmux](https://docs.nesi.org.nz/Getting_Started/Cheat_Sheets/tmux-Reference_sheet/)). -{: .callout} - -## Scheduled Batch Job - -Up until now the scheduler has not been involved, our scripts were run directly on the login node (or Jupyter node). - -First lets rename our batch script script to clarify that we intend to run it though the scheduler. - -``` -mv example_job.sh example_job.sl -``` -{: .output} - -> ## File Extensions -> -> A files extension in this case does not in any way affect how a script is read, -> it is just another part of the name used to remind users what type of file it is. -> Some common conventions: -> `.sh`: **Sh**ell Script. -> `.sl`: **Sl**urm Script, a script that includes a *slurm header* and is intended to be submitted to the cluster. -> `.out`: Commonly used to indicate the file contains the std**out** of some process. -> `.err`: Same as `.out` but for std**err**. -{: .callout} - -In order for the job scheduler to do it's job we need to provide a bit more information about our script. -This is done by specifying _slurm parameters_ in our batch script. Each of these parameters must be preceded by the special token `#SBATCH` and placed _after_ the _shebang_, but before the content of the rest of your script. - -{% include figure.html max-width="100%" caption="" - file="/fig/parts_slurm_script.svg" - alt="slurm script is a regular bash script with a slurm header after the shebang" %} - -These parameters tell SLURM things around how the script should be run, like memory, cores and time required. - -All the parameters available can be found by checking `man sbatch` or on the online [slurm documentation](https://slurm.schedmd.com/sbatch.html). - -[//]: # TODO ??Vet table - -{% include {{ site.snippets }}/scheduler/option-flags-list.snip %} -> ## Comments -> -> Comments in UNIX shell scripts (denoted by `#`) are ignored by the bash interpreter. -> Why is it that we start our slurm parameters with `#` if it is going to be ignored? -> > ## Solution -> > Commented lines are ignored by the bash interpreter, but they are _not_ ignored by slurm. -> > The `{{ site.sched.comment }}` parameters are read by slurm when we _submit_ the job. When the job starts, -> > the bash interpreter will ignore all lines starting with `#`. -> > -> > This is similar to the _shebang_ mentioned earlier, -> > when you run your script, the system looks at the `#!`, then uses the program at the subsequent -> > path to interpret the script, in our case `/bin/bash` (the program 'bash' found in the 'bin' directory). -> {: .solution} -{: .challenge} - -Note that just *requesting* these resources does not make your job run faster, -nor does it necessarily mean that you will consume all of these resources. It -only means that these are made available to you. Your job may end up using less -memory, or less time, or fewer tasks or nodes, than you have requested, and it -will still run. - -It's best if your requests accurately reflect your job's requirements. We'll -talk more about how to make sure that you're using resources effectively in a -later episode of this lesson. - -Now, rather than running our script with `bash` we _submit_ it to the scheduler using the command `sbatch` (**s**lurm **batch**). - -``` -{{ site.remote.prompt }} {{ site.sched.submit.name }} {% if site.sched.submit.options != '' %}{{ site.sched.submit.options }} {% endif %}example_job.sl -``` -{: .language-bash} - -{% include {{ site.snippets }}/scheduler/basic-job-script.snip %} - -And that's all we need to do to submit a job. Our work is done -- now the -scheduler takes over and tries to run the job for us. - -## Checking on Running/Pending Jobs - -While the job is waiting -to run, it goes into a list of jobs called the *queue*. To check on our job's -status, we check the queue using the command -`{{ site.sched.status }}` (**s**lurm **queue**). We will need to filter to see only our jobs, by including either the flag `--user ` or `--me`. - -``` -{{ site.remote.prompt }} {{ site.sched.status }} {{ site.sched.flag.me }} -``` -{: .language-bash} - -{% include {{ site.snippets }}/scheduler/basic-job-status.snip %} - -We can see many details about our job, most importantly is it's _STATE_, the most common states you might see are.. - -- `PENDING`: The job is waiting in the queue, likely waiting for resources to free up or higher prioroty jobs to run. -because other jobs have priority. -- `RUNNING`: The job has been sent to a compute node and it is processing our commands. -- `COMPLETED`: Your commands completed successfully as far as Slurm can tell (e.g. exit 0). -- `FAILED`: (e.g. exit not 0). -- `CANCELLED`: -- `TIMEOUT`: Your job has running for longer than your `--time` and was killed. -- `OUT_OF_MEMORY`: Your job tried to use more memory that it is allocated (`--mem`) and was killed. - -## Cancelling Jobs - -Sometimes we'll make a mistake and need to cancel a job. This can be done with -the `{{ site.sched.del }}` command. - - - - - -In order to cancel the job, we will first need its 'JobId', this can be found in the output of '{{ site.sched.status }} {{ site.sched.flag.me }}'. - -``` -{{ site.remote.prompt }} {{site.sched.del }} 231964 -``` -{: .language-bash} - -A clean return of your command prompt indicates that the request to cancel the job was -successful. - -Now checking `{{ site.sched.status }}` again, the job should be gone. - -``` -{{ site.remote.prompt }} {{ site.sched.status }} {{ site.sched.flag.me }} -``` -{: .language-bash} - -{% include {{ site.snippets }}/scheduler/terminate-job-cancel.snip %} - -(If it isn't wait a few seconds and try again). - -{% include {{ site.snippets }}/scheduler/terminate-multiple-jobs.snip %} - -## Checking Finished Jobs - -There is another command `{{ site.sched.hist }}` (**s**lurm **acc**oun**t**) that includes jobs that have finished. -By default `{{ site.sched.hist }}` only includes jobs submitted by you, so no need to include additional commands at this point. - -``` -{{ site.remote.prompt }} {{ site.sched.hist }} -``` -{: .language-bash} - -{% include {{ site.snippets }}/scheduler/basic-job-status-sacct.snip %} - -Note that despite the fact that we have only run one job, there are three lines shown, this because each _job step_ is also shown. -This can be suppressed using the flag `-X`. - -> ## Where's the Output? -> -> On the login node, when we ran the bash script, the output was printed to the terminal. -> Slurm batch job output is typically redirected to a file, by default this will be a file named `slurm-.out` in the directory where the job was submitted, this can be changed with the slurm parameter `--output`. -{: .discussion} -> -> > ## Hint -> > -> > You can use the _manual pages_ for {{ site.sched.name }} utilities to find -> > more about their capabilities. On the command line, these are accessed -> > through the `man` utility: run `man `. You can find the same -> > information online by searching > "man ". -> > -> > ``` -> > {{ site.remote.prompt }} man {{ site.sched.submit.name }} -> > ``` -> > {: .language-bash} -> {: .solution} -{: .challenge} - -{% include {{ site.snippets }}/scheduler/print-sched-variables.snip %} - -[//]: # TODO ??Sacct more info on checking jobs. Checking log files during run. - - - - -{% include links.md %} - -[fshs]: https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard -[hisat]: https://ccb.jhu.edu/software/hisat2/index.shtml diff --git a/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md b/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md index c1005f1b3..8a8adcbbf 100644 --- a/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md +++ b/docs/Interactive_Computing/OnDemand/Apps/JupyterLab/index.md @@ -8,7 +8,7 @@ Jupyter allows you to create notebooks that contain live code, equations, visualisations and explanatory text. There are many uses for Jupyter, including data cleaning, analytics and visualisation, machine learning, numerical simulation, managing -[Slurm job submissions](../../../../Batch_Computing/Ako_Submitting_Your_First_Job.md) +[Slurm job submissions](../../../../Tutorials/Introduction_To_HPC/Submitting_Your_First_Job.md) and workflows and much more. ## Accessing Jupyter on NeSI diff --git a/docs/Tutorials/Introduction_To_HPC/.pages.yml b/docs/Tutorials/Introduction_To_HPC/.pages.yml new file mode 100644 index 000000000..924afebed --- /dev/null +++ b/docs/Tutorials/Introduction_To_HPC/.pages.yml @@ -0,0 +1,9 @@ +--- +nav: + - What is a_HPC_cluster + - Bash_Shell + - Environment_And_Modules + - Submitting_Your_First_Job + - Resources + - Scaling + - "*" diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Bash_shell.md b/docs/Tutorials/Introduction_To_HPC/Bash_Shell.md similarity index 98% rename from docs/Getting_Started/Getting_Help/Training/Intro_HPC/Bash_shell.md rename to docs/Tutorials/Introduction_To_HPC/Bash_Shell.md index 431641f7a..c4092831c 100644 --- a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Bash_shell.md +++ b/docs/Tutorials/Introduction_To_HPC/Bash_Shell.md @@ -49,7 +49,7 @@ Understanding how to navigate the file system using command line is essential fo The NeSI filesystem looks something like this: ![The file system is made up of a root directory that contains sub-directories -titled home, nesi, and system files](../fig/NesiFiletree.svg) +titled home, nesi, and system files](../../Getting_Started/Getting_Help/Training/fig/NesiFiletree.svg) The directories that are relevant to us are. @@ -198,7 +198,7 @@ You should see a directory called `{{ site.working_dir[1] }}`, and possibly sev directories "backup" and "thing"; "/Users/backup" contains "original", "pnas_final" and "pnas_sub"; "/Users/thing" contains "backup"; and "/Users/thing/backup" contains "2012-12-01", "2013-01-08" and -"2013-01-27"](../fig/filesystem-challenge.svg) +"2013-01-27"](../../Getting_Started/Getting_Help/Training/fig/filesystem-challenge.svg) > > 1. `ls pwd` > 2. `ls backup` @@ -288,7 +288,7 @@ We can see that the `-l` option has modified the command and now our output has It also includes information about the file size, time of its last modification, and permission and ownership information. Most unix commands follow this basic structure. -![Structure of a Unix command](../fig/Unix_Command_Struc.svg) +![Structure of a Unix command](../../Getting_Started/Getting_Help/Training/fig/Unix_Command_Struc.svg) The **prompt** tells us that the terminal is accepting inputs, prompts can be customised to show all sorts of info. @@ -492,7 +492,7 @@ Check that we've moved to the right place by running `pwd`. directories "backup" and "thing"; "/Users/backup" contains "original", "pnas_final" and "pnas_sub"; "/Users/thing" contains "backup"; and "/Users/thing/backup" contains "2012-12-01", "2013-01-08" and -"2013-01-27"](../fig/filesystem-challenge.svg) +"2013-01-27"](../../Getting_Started/Getting_Help/Training/fig/filesystem-challenge.svg) > > > ## Solution > > @@ -701,7 +701,7 @@ holding it down, press the O key) to write our data to disk press Return to accept the suggested default of `draft.txt`).
screenshot of nano text editor in action
+src="../../Getting_Started/Getting_Help/Training/fig/nano-screenshot.png"> Once our file is saved, we can use Ctrl+X to quit the editor and return to the shell. diff --git a/docs/Software/Ako_Environment_And_Modules.md b/docs/Tutorials/Introduction_To_HPC/Environment_And_Modules.md similarity index 99% rename from docs/Software/Ako_Environment_And_Modules.md rename to docs/Tutorials/Introduction_To_HPC/Environment_And_Modules.md index 7441079fa..7b1e4002a 100644 --- a/docs/Software/Ako_Environment_And_Modules.md +++ b/docs/Tutorials/Introduction_To_HPC/Environment_And_Modules.md @@ -1,6 +1,6 @@ --- created_at: 2026-01-13 -title: "Ako: Environment & Modules" +title: "Environment & Modules" description: How do we load and unload software packages? tags: - software @@ -10,7 +10,7 @@ status: tutorial !!! time "Time: 20 Minutes" -!!! prerequisites +!!! prerequisite - Page Link !!! objectives diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Parallel.md b/docs/Tutorials/Introduction_To_HPC/Parallel.md similarity index 100% rename from docs/Getting_Started/Getting_Help/Training/Intro_HPC/Parallel.md rename to docs/Tutorials/Introduction_To_HPC/Parallel.md diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Resources.md b/docs/Tutorials/Introduction_To_HPC/Resources.md similarity index 100% rename from docs/Getting_Started/Getting_Help/Training/Intro_HPC/Resources.md rename to docs/Tutorials/Introduction_To_HPC/Resources.md diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scaling.md b/docs/Tutorials/Introduction_To_HPC/Scaling.md similarity index 93% rename from docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scaling.md rename to docs/Tutorials/Introduction_To_HPC/Scaling.md index a76c6b5ff..cc60448f7 100644 --- a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/Scaling.md +++ b/docs/Tutorials/Introduction_To_HPC/Scaling.md @@ -23,7 +23,7 @@ In order to establish an understanding of the scaling properties we may have to Most computational tasks will have a certain amount of work that must be computed serially. -![Larger fractions of parallel code will have closer to linear scaling performance.](../fig/AmdahlsLaw2.svg) +![Larger fractions of parallel code will have closer to linear scaling performance.](../../Getting_Started/Getting_Help/Training/fig/AmdahlsLaw2.svg) Eventually your performance gains will plateau. @@ -49,7 +49,7 @@ It is worth noting that Amdahl's law assumes all other elements of scaling are h > 4. Watch the job with `squeue --me` or `watch squeue --me`. > 5. On completion of job, use `nn_seff `. > 6. Record the jobs "Elapsed", "TotalCPU", and "Memory" values in the spreadsheet. (Hint: They are the first -> numbers after the percentage efficiency in output of `nn_seff`). Make sure you have entered the values in the correct format and there is a tick next to each entry. ![Correctly entered data in spreadsheet.](../fig/correct-spreadsheet-entry.png) +> numbers after the percentage efficiency in output of `nn_seff`). Make sure you have entered the values in the correct format and there is a tick next to each entry. ![Correctly entered data in spreadsheet.](../../Getting_Started/Getting_Help/Training/fig/correct-spreadsheet-entry.png) > > > ## Solution > > diff --git a/docs/Batch_Computing/Ako_Submitting_Your_First_Job.md b/docs/Tutorials/Introduction_To_HPC/Submitting_Your_First_Job.md similarity index 98% rename from docs/Batch_Computing/Ako_Submitting_Your_First_Job.md rename to docs/Tutorials/Introduction_To_HPC/Submitting_Your_First_Job.md index 22da06fe2..7f8919f3e 100644 --- a/docs/Batch_Computing/Ako_Submitting_Your_First_Job.md +++ b/docs/Tutorials/Introduction_To_HPC/Submitting_Your_First_Job.md @@ -5,7 +5,6 @@ tags: - scheduler - tutorial description: Tutorial on how to submit your first Slurm job -title: Ako:_Submitting Your_First_Job status: tutorial --- !!! time "10 Minutes" @@ -30,7 +29,7 @@ On an HPC system, the scheduler manages which jobs run where and when. The following illustration compares these tasks of a job scheduler to a waiter in a restaurant. If you can relate to an instance where you had to wait for a while in a queue to get in to a popular restaurant, then you may now understand why sometimes your job do not start instantly as in your laptop. -![Queue manager](../assets/images/restaurant_queue_manager.svg) +![Queue manager](../../assets/images/restaurant_queue_manager.svg) The scheduler used in this lesson is [Slurm](https://slurm.schedmd.com/). Although Slurm is not used everywhere, running jobs is quite similar regardless of what software is being used. @@ -128,7 +127,7 @@ In order for the job scheduler to do its job we need to provide a bit more infor This is done by specifying Slurm parameters in our batch script. Each of these parameters must be preceded by the special token `#SBATCH` and placed after the shebang, but before the content of the rest of your script. -![](../assets/images/parts_slurm_script.svg) +![](../../assets/images/parts_slurm_script.svg) These parameters tell Slurm things around how the script should be run, like memory, cores and time required. @@ -287,7 +286,7 @@ This can be suppressed using the flag `-X`. There are two additional good sources for quick references on using Slurm: - - our [Slurm Reference Sheet](../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md) + - our [Slurm Reference Sheet](../../Getting_Started/Cheat_Sheets/Slurm-Reference_Sheet.md) - the official [Slurm documentation](https://slurm.schedmd.com/) and [cheatsheet](https://slurm.schedmd.com/pdfs/summary.pdf) !!! question "Job environment variables" @@ -318,6 +317,6 @@ This can be suppressed using the flag `-X`. - The scheduler handles how compute resources are shared between users - A job is just a shell script - Request *slightly* more resources than you need - + !!! postrequisite - Link to next page diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/What_Is_a_HPC_cluster.md b/docs/Tutorials/Introduction_To_HPC/What_Is_a_HPC_cluster.md similarity index 97% rename from docs/Getting_Started/Getting_Help/Training/Intro_HPC/What_Is_a_HPC_cluster.md rename to docs/Tutorials/Introduction_To_HPC/What_Is_a_HPC_cluster.md index 442f1af71..30d7b5087 100644 --- a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/What_Is_a_HPC_cluster.md +++ b/docs/Tutorials/Introduction_To_HPC/What_Is_a_HPC_cluster.md @@ -19,7 +19,7 @@ that are provisioned to users on demand or as needed. *Cluster* is a more specific term describing a type of supercomputer comprised of multiple smaller computers (nodes) working together. Almost all supercomputers are clusters. -![NeSI-HPC-Facility](../fig/NeSI-HPC-Facility.jpg) +![NeSI-HPC-Facility](../../Getting_Started/Getting_Help/Training/fig/NeSI-HPC-Facility.jpg) ## Access diff --git a/docs/Getting_Started/Getting_Help/Training/Intro_HPC/writing_good_code.md b/docs/Tutorials/Introduction_To_HPC/writing_good_code.md similarity index 100% rename from docs/Getting_Started/Getting_Help/Training/Intro_HPC/writing_good_code.md rename to docs/Tutorials/Introduction_To_HPC/writing_good_code.md From 022f6d4e484a860b9542163a267cb47773b0e112 Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Thu, 15 Jan 2026 13:45:30 +1300 Subject: [PATCH 22/23] Horrible formatting --- docs/assets/stylesheets/theme.css | 322 +++++++++++++++--------------- 1 file changed, 165 insertions(+), 157 deletions(-) diff --git a/docs/assets/stylesheets/theme.css b/docs/assets/stylesheets/theme.css index 8ff8bd7e8..b137117df 100644 --- a/docs/assets/stylesheets/theme.css +++ b/docs/assets/stylesheets/theme.css @@ -1,116 +1,102 @@ -:root{ - --nesi-grey : #414f5c; +:root { + --nesi-grey: #414f5c; --nesi-grey--light: #94a5ad; - --nesi-yellow :#fcce06; + --nesi-yellow: #fcce06; --nesi-purple: rgb(202, 159, 213); - --nesi-orange : rgb(244, 121, 37); - --nesi-blue : #4fbaed; - --nesi-red:#ef315e; + --nesi-orange: rgb(244, 121, 37); + --nesi-blue: #4fbaed; + --nesi-red: #ef315e; --nesi-green: #cce310; - --reannz-blue : rgb(0,185, 228); - --reannz-blue--shade-negative1:rgb(0, 127, 156); - --reannz-blue--dark: rgb(0,28, 54); + --reannz-blue: rgb(0, 185, 228); + --reannz-blue--shade-negative1: rgb(0, 127, 156); + --reannz-blue--dark: rgb(0, 28, 54); --reannz-blue--dark-shade1: #2c485d; - --reannz-grey : rgb(195,200, 200); - --reannz-black : rgb(25,25, 25); + --reannz-grey: rgb(195, 200, 200); + --reannz-black: rgb(25, 25, 25); --reannz-green: rgb(190, 184, 6); --reannz-green--dark: rgb(0, 170, 136); --reannz-orange: rgb(241, 128, 0); --reannz-purple: rgb(132, 121, 183); - [data-md-color-scheme="default"]{ - --md-primary-fg-color: var(--reannz-blue--dark); - --md-accent-fg-color: var(--reannz-blue); + [data-md-color-scheme="default"] { + --md-primary-fg-color: var(--reannz-blue--dark); + --md-accent-fg-color: var(--reannz-blue); } - /* --md-accent-bg-color: rgb(210,227,235); */ + /* --md-accent-bg-color: rgb(210,227,235); */ [data-md-color-scheme="slate"] { - --md-primary-fg-color: var(--reannz-blue--dark); - --md-accent-fg-color: var(--reannz-blue--darkish); + --md-primary-fg-color: var(--reannz-blue--dark); + --md-accent-fg-color: var(--reannz-blue--darkish); .nt-card-image>img { filter: brightness(0) invert(1); } } - --md-status--tutorial: url('data:image/svg+xml;charset=utf-8, ') - --md-admonition-icon--prerequisite: url('data:image/svg+xml;charset=utf-8,') - --md-admonition-icon--time: url('data:image/svg+xml;charset=utf-8,') - + --md-status--tutorial: url('data:image/svg+xml;charset=utf-8, '); + --md-admonition-icon--prerequisite: url('data:image/svg+xml;charset=utf-8,'); + --md-admonition-icon--time: url('data:image/svg+xml;charset=utf-8, '); } - /* Logo biggification */ - /* COMMENTED OUT FOR REANNZ LOGO */ +/* Logo biggification */ +/* COMMENTED OUT FOR REANNZ LOGO */ /* .md-header__button.md-logo img, .md-header__button.md-logo svg { height: 4rem; margin: -2rem; } */ - .md-status--tutorial::after { mask-image: var(--md-status--tutorial); -webkit-mask-image: var(--md-status--tutorial); } /* Version table stuff */ -.md-tag.md-tag-ver{ +.md-tag.md-tag-ver { color: var(--md-code-fg-color); } + .md-tag.md-tag-ver-shown { - outline: var(--md-primary-fg-color) 2px solid; + outline: var(--md-primary-fg-color) 2px solid; } .md-tag-ver-warn { text-decoration: line-through; } + .md-typeset__table { width: 100%; } + .md-typeset__table table:not([class]) { display: table } + /* convenience class. Not sure if it is used */ -.hidden{ - display: none; +.hidden { + display: none; } + /* Get support button */ -.md-button-support{ +.md-button-support { position: absolute; margin: -2rem 0 0 1rem; width: 80%; text-align: center; font-size: 0.7rem; } + /* Don't duplicate header title */ -.md-nav--primary > .md-nav__title { - display: none; +.md-nav--primary>.md-nav__title { + display: none; } + /* fix neotiri card colors */ - /* Make button more buttony */ +/* Make button more buttony */ .md-button--primary { box-shadow: grey 2px 2px 2px; } -/* prerequisite custom admonition */ -:root { - --md-admonition-icon--prerequisite: url('data:image/svg+xml;charset=utf-8,') -} - -.md-typeset .admonition.prerequisite, -.md-typeset details.prerequisite { - border-color: var(--reannz-green); -} -.md-typeset .prerequisite > .admonition-title, -.md-typeset .prerequisite > summary { - background-color: rgba(190, 184, 6, 0.1); /*above color*/ -} -.md-typeset .prerequisite > .admonition-title::before, -.md-typeset .prerequisite > summary::before { - background-color: var(--reannz-green); - -webkit-mask-image: var(--md-admonition-icon--prerequisite); - mask-image: var(--md-admonition-icon--prerequisite); -} /* Footer */ #new-footer { font-family: Lato; @@ -120,38 +106,41 @@ background-color: var(--reannz-black); } -/* e.g. inactive link text */ +/* e.g. inactive link text */ .md-typeset a { - color: var(--reannz-blue--shade-negative1); + color: var(--reannz-blue--shade-negative1); } + .md-typeset a:hover { - color: var(--reannz-blue); + color: var(--reannz-blue); } + /* Make deprecated logo stand out */ span.md-status.md-status--deprecated { - filter: invert(50%) sepia(100%) saturate(1000%) hue-rotate(330deg) brightness(70%) contrast(1000%); + filter: invert(50%) sepia(100%) saturate(1000%) hue-rotate(330deg) brightness(70%) contrast(1000%); } /* Warning symbols for licence server */ -.badge-licence-noup{ - padding: 0; - color: red; - cursor: default; +.badge-licence-noup { + padding: 0; + color: red; + cursor: default; } -.badge-licence-lowup{ - padding: 0; - color: yellow; - cursor: default; + +.badge-licence-lowup { + padding: 0; + color: yellow; + cursor: default; } /* Make cards look right */ .md-typeset .grid.cards { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); - gap: 1rem; - margin: 0 auto; - width: 100%; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); + gap: 1rem; + margin: 0 auto; + width: 100%; } .cards>a>img { @@ -199,10 +188,12 @@ span.md-status.md-status--deprecated { margin: 0; border-radius: 0.8em; } -.tutorial-banner > p { + +.tutorial-banner>p { margin: 0; padding: 0.2em 0.5em; } + /* Calendar */ #calendar-banner { @@ -214,8 +205,6 @@ span.md-status.md-status--deprecated { z-index: 9999; } - - #calendar-banner button { position: absolute; top: 4px; @@ -226,92 +215,111 @@ span.md-status.md-status--deprecated { /* custom admonition */ /* prereq */ - .md-typeset .admonition.prerequisite, - .md-typeset details.prerequisite { - border-color: rgb(170, 170, 60); - } - .md-typeset .prerequisite > .admonition-title, - .md-typeset .prerequisite > summary { - background-color: rgba(170, 170, 60, 0.1); - } - .md-typeset .prerequisite > .admonition-title::before, - .md-typeset .prerequisite > summary::before { - background-color: rgb(170, 170, 60); - -webkit-mask-image: var(--md-admonition-icon--prerequisite); - mask-image: var(--md-admonition-icon--prerequisite); - } - /* postreq */ - .md-typeset .admonition.postrequisite, - .md-typeset details.postrequisite { - border-color: rgb(170, 170, 60); - } - .md-typeset .postrequisite > .admonition-title, - .md-typeset .postrequisite > summary { - background-color: rgba(170, 170, 60, 0.1); - } - .md-typeset .postrequisite > .admonition-title::before, - .md-typeset .postrequisite > summary::before { - background-color: rgb(170, 170, 60); - -webkit-mask-image: var(--md-admonition-icon--postrequisite); - mask-image: var(--md-admonition-icon--postrequisite); - } + +.md-typeset .admonition.prerequisite, +.md-typeset details.prerequisite { + border-color: var(--reannz-green); +} + +.md-typeset .prerequisite>.admonition-title, +.md-typeset .prerequisite>summary { + background-color: rgba(190, 184, 6, 0.1); + /*above color*/ +} + +.md-typeset .prerequisite>.admonition-title::before, +.md-typeset .prerequisite>summary::before { + background-color: var(--reannz-green); + -webkit-mask-image: var(--md-admonition-icon--prerequisite); + mask-image: var(--md-admonition-icon--prerequisite); +} + +/* postreq */ +.md-typeset .admonition.postrequisite, +.md-typeset details.postrequisite { + border-color: rgb(170, 170, 60); +} + +.md-typeset .postrequisite>.admonition-title, +.md-typeset .postrequisite>summary { + background-color: rgba(170, 170, 60, 0.1); +} + +.md-typeset .postrequisite>.admonition-title::before, +.md-typeset .postrequisite>summary::before { + background-color: rgb(170, 170, 60); + -webkit-mask-image: var(--md-tabbed-icon--next); + mask-image: var(--md-tabbed-icon--next); +} + /* deprecated */ - .md-typeset .admonition.deprecated, - .md-typeset details.deprecated { - border-color: #ff1744; - } - .md-typeset .deprecated > .admonition-title, - .md-typeset .deprecated > summary { - background-color: #ff17441a; - } - .md-typeset .deprecated > .admonition-title::before, - .md-typeset .deprecated > summary::before { - background-color: #ff1744; - -webkit-mask-image: var(--md-status--deprecated); - mask-image: var(--md-status--deprecated); - } +.md-typeset .admonition.deprecated, +.md-typeset details.deprecated { + border-color: #ff1744; +} + +.md-typeset .deprecated>.admonition-title, +.md-typeset .deprecated>summary { + background-color: #ff17441a; +} + +.md-typeset .deprecated>.admonition-title::before, +.md-typeset .deprecated>summary::before { + background-color: #ff1744; + -webkit-mask-image: var(--md-status--deprecated); + mask-image: var(--md-status--deprecated); +} + /* time */ - .md-typeset .admonition.time, - .md-typeset details.time { - border-color: #610088; - } - .md-typeset .time > .admonition-title, - .md-typeset .time > summary { - background-color: #b700cf1a; - } - .md-typeset .time > .admonition-title::before, - .md-typeset .time > summary::before { - background-color: #ff3f66; - -webkit-mask-image: var(--md-admonition-icon--time); - mask-image: var(--md-admonition-icon--time); - } -/* objective */ - .md-typeset .admonition.time, - .md-typeset details.time { - border-color: #765981; - } - .md-typeset .time > .admonition-title, - .md-typeset .time > summary { - background-color: #5e9b2d1a; - } - .md-typeset .time > .admonition-title::before, - .md-typeset .time > summary::before { - background-color: #0e0b0b; - -webkit-mask-image: var(--md-admonition-icon--time); - mask-image: var(--md-admonition-icon--time); - } +.md-typeset .admonition.time, +.md-typeset details.time { + border-color: #610088; +} + +.md-typeset .time>.admonition-title, +.md-typeset .time>summary { + background-color: #b700cf1a; +} + +.md-typeset .time>.admonition-title::before, +.md-typeset .time>summary::before { + background-color: #ff3f66; + -webkit-mask-image: var(--md-admonition-icon--time); + mask-image: var(--md-admonition-icon--time); +} + +/* objectivess */ +.md-typeset .admonition.objectives, +.md-typeset details.time { + border-color: #765981; +} + +.md-typeset .objectives>.admonition-title, +.md-typeset .objectives>summary { + background-color: #5e9b2d1a; +} + +.md-typeset .objectives>.admonition-title::before, +.md-typeset .objectives>summary::before { + background-color: #0e0b0b; + -webkit-mask-image: var(--md-admonition-icon--prerequisite); + mask-image: var(--md-admonition-icon--prerequisite); +} + /* key[ppoint */ - .md-typeset .admonition.keypoints, - .md-typeset details.keypoints { - border-color: #000000; - } - .md-typeset .keypoints > .admonition-title, - .md-typeset .keypoints > summary { - background-color: #e990f51a; - } - .md-typeset .keypoints > .admonition-title::before, - .md-typeset .keypoints > summary::before { - background-color: #3fffff; - -webkit-mask-image: var(--md-admonition-icon--keypoints); - mask-image: var(--md-admonition-icon--keypoints); - } +.md-typeset .admonition.keypoints, +.md-typeset details.keypoints { + border-color: #000000; +} + +.md-typeset .keypoints>.admonition-title, +.md-typeset .keypoints>summary { + background-color: #e990f51a; +} + +.md-typeset .keypoints>.admonition-title::before, +.md-typeset .keypoints>summary::before { + background-color: #3fffff; + -webkit-mask-image: var(--md-admonition-icon--prerequisite); + mask-image: var(--md-admonition-icon--prerequisite); +} From 39d0fbe83db1a5a5c2506a96d6db61818cb3228e Mon Sep 17 00:00:00 2001 From: "callumnmw@gmail.com" Date: Fri, 16 Jan 2026 14:23:13 +1300 Subject: [PATCH 23/23] make some pages build a bit more --- .../Introduction_To_HPC/Bash_Shell.md | 944 ++++++++---------- .../Tutorials/Introduction_To_HPC/Parallel.md | 153 ++- .../Introduction_To_HPC/Resources.md | 326 +++--- docs/assets/images/clusterDiagram.png | Bin 0 -> 9238 bytes mkdocs.yml | 3 + 5 files changed, 685 insertions(+), 741 deletions(-) create mode 100644 docs/assets/images/clusterDiagram.png diff --git a/docs/Tutorials/Introduction_To_HPC/Bash_Shell.md b/docs/Tutorials/Introduction_To_HPC/Bash_Shell.md index c4092831c..6e1666f8b 100644 --- a/docs/Tutorials/Introduction_To_HPC/Bash_Shell.md +++ b/docs/Tutorials/Introduction_To_HPC/Bash_Shell.md @@ -1,41 +1,25 @@ --- -title: "Navigating Files and Directories" -teaching: 30 -exercises: 10 -questions: -- "How can I move around the cluster filesystem" -- "How can I see what files and directories I have?" -- "How can I make new files and directories." -objectives: -- "Create, edit, manipulate and remove files from command line" -- "Translate an absolute path into a relative path and vice versa." -- "Use options and arguments to change the behaviour of a shell command." -- "Demonstrate the use of tab completion and explain its advantages." -keypoints: -- "The file system is responsible for managing information on the disk." -- "Information is stored in files, which are stored in directories (folders)." -- "Directories can also store other directories, which then form a directory tree." -- "`cd [path]` changes the current working directory." -- "`ls [path]` prints a listing of a specific file or directory; `ls` on its own lists the current working directory." -- "`pwd` prints the user's current working directory." -- "`cp [file] [path]` copies [file] to [path]" -- "`mv [file] [path]` moves [file] to [path]" -- "`rm [file]` deletes [file]" -- "`/` on its own is the root directory of the whole file system." -- "Most commands take options (flags) that begin with a `-`." -- "A relative path specifies a location starting from the current location." -- "An absolute path specifies a location from the root of the file system." -- "Directory names in a path are separated with `/` on Unix, but `\\` on Windows." -- "`..` means 'the directory above the current one'; `.` on its own means 'the current directory'." +created_at: 2026-01-15 +description: Using the bash shell for file operations on NeSI +status: tutorial --- -> ## The Unix Shell -> -> This episode will be a quick introduction to the Unix shell, only the bare minimum required to use the cluster. -> -> The Software Carpentry '[Unix Shell](https://swcarpentry.github.io/shell-novice/)' lesson covers the subject in more depth, we recommend you check it out. -> -{: .callout} + +!!! objectives + + - "Create, edit, manipulate and remove files from command line" + - "Translate an absolute path into a relative path and vice versa." + - "Use options and arguments to change the behaviour of a shell command." + - "Demonstrate the use of tab completion and explain its advantages." + +!!! info The Unix Shell + + This episode will be a quick introduction to the Unix shell, only the bare minimum required to use the cluster. + The Software Carpentry '[Unix Shell](https://swcarpentry.github.io/shell-novice/)' lesson covers the subject in more depth, we recommend you check it out. + +{% set working_dir = ['nesi', 'nobackup', 'example'] %} +{% set projectcode = "nesi99991" %} +{% set example_script = "sum_array.r" %} The part of the operating system responsible for managing files and directories is called the **file system**. @@ -97,7 +81,12 @@ NeSI performs backups of the `/home` and `/nesi/project` (persistent) filesystem Protecting critical data from corruption or deletion is primarily your responsibility. Ensure you have a data management plan and stick to the plan to reduce the chance of data loss. Also important is managing your storage quota. To check your quotas, use the `nn_storage_quota` command, eg -{% include {{ site.snippets }}/filedir/sinfo.snip %} +```out +Quota_Location AvailableGiB UsedGiB Use% +project_nesi99991 800 496 62 +nobackup_nesi99991 30720 16189 53 +home_cwal219 20 13 65 +``` As well as disk space, 'inodes' are also tracked, this is the *number* of files. @@ -116,18 +105,14 @@ a command is important. First, let's find out where we are by running the command `pwd` for '**p**rint **w**orking **d**irectory'. +```sh + pwd ``` -{{ site.remote.prompt }} pwd -``` - -{: .language-bash} -``` +```out /home/ ``` -{: .output} - The output we see is what is known as a 'path'. The path can be thought of as a series of directions given to navigate the file system. @@ -141,13 +126,11 @@ Next is `home`, as it is the next part of the path we know it is inside the root we also know that home is another directory as the path continues. Finally, stored inside `home` is the directory with your username. -> ## Slashes -> -> Notice that there are two meanings for the `/` character. -> When it appears at the front of a file or directory name, -> it refers to the root directory. When it appears *inside* a path, -> it's just a separator. -{: .callout} +!!! note Slashes + Notice that there are two meanings for the `/` character. + When it appears at the front of a file or directory name, + it refers to the root directory. When it appears *inside* a path, + it's just a separator. As you may now see, using a bash shell is strongly dependent on the idea that your files are organized in a hierarchical file system. @@ -163,56 +146,40 @@ To **l**i**s**t the contents of a directory, we use the command `ls` followed by We will now list the contents of the directory we we will be working from. We can use the following command to do this: +```sh + ls {{ working_dir[0] }} ``` -{{ site.remote.prompt }} ls {{ site.working_dir[0] }} + +```out +{{ working_dir[1] }} ``` -{: .language-bash} +You should see a directory called `{{ working_dir[1] }}`, and possibly several other directories. +For the purposes of this workshop you will be working within `{{ working_dir|join('/') }}`. -``` -{{ site.working_dir[1] }} -``` - -{: .output} - -You should see a directory called `{{ site.working_dir[1] }}`, and possibly several other directories. For the purposes of this workshop you will be working within `{{ site.working_dir | join: '/' }}` - -> ## Command History -> -> You can cycle through your previous commands with the and keys. -> A convenient way to repeat your last command is to type then enter. -> -{: .callout} - -> ## `ls` Reading Comprehension -> -> What command would you type to get the following output -> -> ``` -> original pnas_final pnas_sub -> ``` -> -> {: .output} -> -> ![A directory tree below the Users directory where "/Users" contains the -directories "backup" and "thing"; "/Users/backup" contains "original", -"pnas_final" and "pnas_sub"; "/Users/thing" contains "backup"; and -"/Users/thing/backup" contains "2012-12-01", "2013-01-08" and -"2013-01-27"](../../Getting_Started/Getting_Help/Training/fig/filesystem-challenge.svg) -> -> 1. `ls pwd` -> 2. `ls backup` -> 3. `ls /Users/backup` -> 4. `ls /backup` -> -> > ## Solution -> > -> > 1. No: `pwd` is not the name of a directory. -> > 2. Possibly: It depends on your current directory (we will explore this more shortly). -> > 3. Yes: uses the absolute path explicitly. -> > 4. No: There is no such directory. -> {: .solution} -{: .challenge} +!!! tip "Command History" + You can cycle through your previous commands with the and keys. + A convenient way to repeat your last command is to type then enter. + +??? question "`ls` Reading Comprehension" + What command would you type to get the following output + + ```out + original pnas_final pnas_sub + ``` + + ![](../../Getting_Started/Getting_Help/Training/fig/filesystem-challenge.svg) + + 1. `ls pwd` + 2. `ls backup` + 3. `ls /Users/backup` + 4. `ls /backup` + + ??? Solution + 1. No: `pwd` is not the name of a directory. + 2. Possibly: It depends on your current directory (we will explore this more shortly). + 3. Yes: uses the absolute path explicitly. + 4. No: There is no such directory. ## Moving about @@ -224,30 +191,26 @@ The `cd` command is akin to double clicking a folder in a graphical interface. We will use the following command: +```sh + cd {{ working_dir|join('/') }} ``` -{{ site.remote.prompt }} cd {{ site.working_dir | join: '/' }} -``` - -{: .language-bash} -``` +```out + ``` -{: .output} You will notice that `cd` doesn't print anything. This is normal. Many shell commands will not output anything to the screen when successfully executed. We can check we are in the right place by running `pwd`. -``` -{{ site.remote.prompt }} pwd +```sh + pwd ``` -{: .language-bash} -``` -{{ site.working_dir | join: '/' }} +```out +{{ working_dir|join('/') }} ``` -{: .output} ## Creating directories @@ -255,39 +218,44 @@ We can check we are in the right place by running `pwd`. As previously mentioned, it is general useful to organise your work in a hierarchical file structure to make managing and finding files easier. It is also is especially important when working within a shared directory with colleagues, such as a project, to minimise the chance of accidentally affecting your colleagues work. So for this workshop you will each make a directory using the `mkdir` command within the workshops directory for you to personally work from. -``` -{{ site.remote.prompt }} mkdir +```sh + mkdir ``` -{: .language-bash} You should then be able to see your new directory is there using `ls`. -``` -{{ site.remote.prompt }} ls {{ site.working_dir | join: '/' }} +```sh + ls {{ working_dir|join('/') }} ``` -{: .language-bash} - -{% include {{ site.snippets }}/filedir/dir-contents1.snip %} +```sh + {{ example_script }} usr123 usr345 +``` ## General Syntax of a Shell Command We are now going to use `ls` again but with a twist, this time we will also use what are known as **options**, **flags** or **switches**. These options modify the way that the command works, for this example we will add the flag `-l` for "long listing format". -``` -{{ site.remote.prompt }} ls -l {{ site.working_dir | join: '/' }} +```sh + ls -l {{ working_dir|join('/') }} ``` {: .language-bash} -{% include {{ site.snippets }}/filedir/dir-contents2.snip %} +```out +-rw-r-----+ 1 usr9999 {{projectcode}} 460 Nov 18 17:03 +-rw-r-----+ 1 usr9999 {{projectcode}} 460 Nov 18 17:03 {{ example_script }} +drwxr-sr-x+ 3 usr9999 {{projectcode}} 4096 22 Sep 08:40 birds +drwxrws---+ 2 usr123 {{projectcode}} 4096 Nov 15 09:01 usr123 +drwxrws---+ 2 usr345 {{projectcode}} 4096 Nov 15 09:01 usr345 +``` We can see that the `-l` option has modified the command and now our output has listed all the files in alphanumeric order, which can make finding a specific file easier. It also includes information about the file size, time of its last modification, and permission and ownership information. -Most unix commands follow this basic structure. +Most Unix commands follow this basic structure. ![Structure of a Unix command](../../Getting_Started/Getting_Help/Training/fig/Unix_Command_Struc.svg) The **prompt** tells us that the terminal is accepting inputs, prompts can be customised to show all sorts of info. @@ -308,13 +276,18 @@ while `ls -S` will sort the files and directories by size. Another useful option for `ls` is the `-a` option, lets try using this option together with the `-l` option: -``` -{{ site.remote.prompt }} ls -la +```sh + ls -la ``` -{: .language-bash} -{% include {{ site.snippets }}/filedir/dir-contents3.snip %} +```out +drwxrws---+ 4 usr001 {{projectcode}} 4096 Nov 15 09:00 . +drwxrws---+ 12 root {{projectcode}} 262144 Nov 15 09:23 .. +-rw-r-----+ 1 cwal219 {{projectcode}} 460 Nov 18 17:03 {{ example_script }} +drwxrws---+ 2 usr123 {{projectcode}} 4096 Nov 15 09:01 usr123 +drwxrws---+ 2 usr345 {{projectcode}} 4096 Nov 15 09:01 usr345 +``` Single letter options don't usually need to be separate. In this case `ls -la` is performing the same function as if we had typed `ls -l -a`. @@ -322,24 +295,22 @@ You might notice that we now have two extra lines for directories `.` and `..`. These two specific hidden directories are special as they will exist hidden inside every directory, with the `.` hidden directory representing your current directory and the `..` hidden directory representing the **parent** directory above your current directory. -> ## Exploring More `ls` Flags -> -> You can also use two options at the same time. What does the command `ls` do when used -> with the `-l` option? What about if you use both the `-l` and the `-h` option? -> -> Some of its output is about properties that we do not cover in this lesson (such -> as file permissions and ownership), but the rest should be useful -> nevertheless. -> -> > ## Solution -> > -> > The `-l` option makes `ls` use a **l**ong listing format, showing not only -> > the file/directory names but also additional information, such as the file size -> > and the time of its last modification. If you use both the `-h` option and the `-l` option, -> > this makes the file size '**h**uman readable', i.e. displaying something like `5.3K` -> > instead of `5369`. -> {: .solution} -{: .challenge} + ??? question "Exploring More `ls` Flags" + + You can also use two options at the same time. What does the command `ls` do when used + with the `-l` option? What about if you use both the `-l` and the `-h` option? + + Some of its output is about properties that we do not cover in this lesson (such + as file permissions and ownership), but the rest should be useful + nevertheless. + + ??? question Solution + + The `-l` option makes `ls` use a **l**ong listing format, showing not only + the file/directory names but also additional information, such as the file size + and the time of its last modification. If you use both the `-h` option and the `-l` option, + this makes the file size '**h**uman readable', i.e. displaying something like `5.3K` + instead of `5369`. ## Relative paths @@ -364,25 +335,21 @@ In the previous command, since we did not specify an **absolute path** it ran th We will now navigate to the parent directory, the simplest way do this is to use the relative path `..`. +```sh + cd .. ``` -{{ site.remote.prompt }} cd .. -``` - -{: .language-bash} -We should now be back in `{{ site.working_dir[0] }}`. +We should now be back in `{{ working_dir[0] }}`. -``` -{{ site.remote.prompt }} pwd +```sh + pwd ``` -{: .language-bash} -``` -{{ site.working_dir[0] }} +```out +{{ working_dir[0] }} ``` -{: .output} ## Tab completion @@ -393,270 +360,237 @@ We should now be back in `{{ site.working_dir[0] }}`. For example, if you type: +```sh + cd {{ working_dir|last|slice(0,3) }} ``` -{{ site.remote.prompt }} cd {{ site.working_dir | last | slice: 0,3 }} -``` -{: .language-bash} and then press Tab (the tab key on your keyboard), the shell automatically completes the directory name for you (since there is only one possible match): +```sh + cd {{ working_dir|last }}/ ``` -{{ site.remote.prompt }} cd {{ site.working_dir | last }}/ -``` -{: .language-bash} However, you want to move to your personal working directory. If you hit Tab once you will likely see nothing change, as there are more than one possible options. Hitting Tab a second time will print all possible autocomplete options. -``` +```out cwal219/ riom/ harrellw/ ``` -{: .output} Now entering in the first few characters of the path (just enough that the possible options are no longer ambiguous) and pressing Tab again, should complete the path. Now press Enter to execute the command. +```sh + cd {{ working_dir|last }}/ ``` -{{ site.remote.prompt }} cd {{ site.working_dir | last }}/ -``` -{: .language-bash} Check that we've moved to the right place by running `pwd`. -``` -{{ site.working_dir | join: '/' }}/ -``` - -> ## Two More Shortcuts -> -> The shell interprets a tilde (`~`) character at the start of a path to -> mean "the current user's home directory". For example, if Nelle's home -> directory is `/home/nelle`, then `~/data` is equivalent to -> `/home/nelle/data`. This only works if it is the first character in the -> path: `here/there/~/elsewhere` is *not* `here/there//home/nelle/elsewhere`. -> -> Another shortcut is the `-` (dash) character. `cd` will translate `-` into -> *the previous directory I was in*, which is faster than having to remember, -> then type, the full path. This is a *very* efficient way of moving -> *back and forth between two directories* -- i.e. if you execute `cd -` twice, -> you end up back in the starting directory. -> -> The difference between `cd ..` and `cd -` is -> that the former brings you *up*, while the latter brings you *back*. -> -{: .callout} - -> ## Absolute vs Relative Paths -> -> Starting from `/home/amanda/data`, -> which of the following commands could Amanda use to navigate to her home directory, -> which is `/home/amanda`? -> -> 1. `cd .` -> 2. `cd /` -> 3. `cd home/amanda` -> 4. `cd ../..` -> 5. `cd ~` -> 6. `cd home` -> 7. `cd ~/data/..` -> 8. `cd` -> 9. `cd ..` -> -> > ## Solution -> > -> > 1. No: `.` stands for the current directory. -> > 2. No: `/` stands for the root directory. -> > 3. No: Amanda's home directory is `/home/amanda`. -> > 4. No: this command goes up two levels, i.e. ends in `/home`. -> > 5. Yes: `~` stands for the user's home directory, in this case `/home/amanda`. -> > 6. No: this command would navigate into a directory `home` in the current directory if it exists. -> > 7. Yes: unnecessarily complicated, but correct. -> > 8. Yes: shortcut to go back to the user's home directory. -> > 9. Yes: goes up one level. -> {: .solution} +```out +{{ working_dir|join('/') }}/ +``` + + !!! tip "Two More Shortcuts" + + The shell interprets a tilde (`~`) character at the start of a path to + mean "the current user's home directory". For example, if Nelle's home + directory is `/home/nelle`, then `~/data` is equivalent to + `/home/nelle/data`. This only works if it is the first character in the + path: `here/there/~/elsewhere` is *not* `here/there//home/nelle/elsewhere`. + + Another shortcut is the `-` (dash) character. `cd` will translate `-` into + *the previous directory I was in*, which is faster than having to remember, + then type, the full path. This is a *very* efficient way of moving + *back and forth between two directories* -- i.e. if you execute `cd -` twice, + you end up back in the starting directory. + + The difference between `cd ..` and `cd -` is + that the former brings you *up*, while the latter brings you *back*. + + ??? question "Absolute vs Relative Paths" + + Starting from `/home/amanda/data`, + which of the following commands could Amanda use to navigate to her home directory, + which is `/home/amanda`? + + 1. `cd .` + 2. `cd /` + 3. `cd home/amanda` + 4. `cd ../..` + 5. `cd ~` + 6. `cd home` + 7. `cd ~/data/..` + 8. `cd` + 9. `cd ..` + + ## Solution + + 1. No: `.` stands for the current directory. + 2. No: `/` stands for the root directory. + 3. No: Amanda's home directory is `/home/amanda`. + 4. No: this command goes up two levels, i.e. ends in `/home`. + 5. Yes: `~` stands for the user's home directory, in this case `/home/amanda`. + 6. No: this command would navigate into a directory `home` in the current directory if it exists. + 7. Yes: unnecessarily complicated, but correct. + 8. Yes: shortcut to go back to the user's home directory. + 9. Yes: goes up one level. + {: .solution} {: .challenge} -> ## Relative Path Resolution -> -> Using the filesystem diagram below, if `pwd` displays `/Users/thing`, -> what will `ls ../backup` display? -> -> 1. `../backup: No such file or directory` -> 2. `2012-12-01 2013-01-08 2013-01-27` -> 3. `original pnas_final pnas_sub` -> -> ![A directory tree below the Users directory where "/Users" contains the -directories "backup" and "thing"; "/Users/backup" contains "original", -"pnas_final" and "pnas_sub"; "/Users/thing" contains "backup"; and -"/Users/thing/backup" contains "2012-12-01", "2013-01-08" and -"2013-01-27"](../../Getting_Started/Getting_Help/Training/fig/filesystem-challenge.svg) -> -> > ## Solution -> > -> > 1. No: there *is* a directory `backup` in `/Users`. -> > 2. No: this is the content of `Users/thing/backup`, -> > but with `..`, we asked for one level further up. -> > 3. Yes: `../backup/` refers to `/Users/backup/`. -> > -> {: .solution} -{: .challenge} - -> ## Clearing your terminal -> -> If your screen gets too cluttered, you can clear your terminal using the -> `clear` command. You can still access previous commands using -> and to move line-by-line, or by scrolling in your terminal. -{: .callout} - -> ## Listing in Reverse Chronological Order -> -> By default, `ls` lists the contents of a directory in alphabetical -> order by name. The command `ls -t` lists items by time of last -> change instead of alphabetically. The command `ls -r` lists the -> contents of a directory in reverse order. -> Which file is displayed last when you combine the `-t` and `-r` flags? -> Hint: You may need to use the `-l` flag to see the -> last changed dates. -> -> > ## Solution -> > -> > The most recently changed file is listed last when using `-rt`. This -> > can be very useful for finding your most recent edits or checking to -> > see if a new output file was written. -> {: .solution} -{: .challenge} - -> ## Globbing -> -> One of the most powerful features of bash is *filename expansion*, otherwise known as *globbing*. -> This allows you to use *patterns* to match a file name (or multiple files), -> which will then be operated on as if you had typed out all of the matches. -> -> `*` is a **wildcard**, which matches zero or more characters. -> -> Inside the `{{ site.working_dir | join: '/' }}` directory there is a directory called `birds` -> ->``` ->{{ site.remote.prompt }} cd {{ site.working_dir | join: '/' }}/birds ->{{ site.remote.prompt }} ls ->``` -> {: .language-bash} -> -> ``` -> kaka.txt kakapo.jpeg kea.txt kiwi.jpeg pukeko.jpeg -> ``` -> {: .output} -> -> In this example there aren't many files, but it is easy to imagine a situation where you have hundreds or thousads of files you need to filter through, and globbing is the perfect tool for this. Using the wildcard character the command -> ->``` ->{{ site.remote.prompt }} ls ka* ->``` -> {: .language-bash} -> -> Will return: -> ->``` ->kaka.txt kakapo.jpeg ->``` -> {: .output} -> -> Since the pattern `ka*` will match `kaka.txt`and `kakapo.jpeg` as these both start with "ka". While the command: -> ->``` ->{{ site.remote.prompt }} ls *.jpeg ->``` -> {: .language-bash} -> -> Will return: -> ->``` ->kakapo.jpeg kiwi.jpeg pukeko.jpeg ->``` -> {: .output} -> -> As `*.jpeg` will match `kakapo.jpeg`, `kiwi.jpeg` and `pukeko.jpeg` as they all end in `.jpeg` -> You can use multiple wildcards as well with the command: -> ->``` ->{{ site.remote.prompt }} ls k*a.* ->``` -> {: .language-bash} -> -> Returning: -> ->``` ->kaka.txt kea.txt ->``` -> {: .output} -> -> As `k*a.*` will match just `kaka.txt` and `kea.txt` -> -> `?` is also a wildcard, but it matches exactly one character. So the command: -> ->``` ->{{ site.remote.prompt }} ls ????.* ->``` -> {: .language-bash} -> -> Would return: ->``` ->kaka.txt kiwi.jpeg ->``` -> {: .output} -> -> As `kaka.txt` and `kiwi.jpeg` the only files which have four characters, followed by a `.` then any number and combination of characters. -> -> When the shell sees a wildcard, it expands the wildcard to create a -> list of matching filenames *before* running the command that was -> asked for. As an exception, if a wildcard expression does not match -> any file, Bash will pass the expression as an argument to the command -> as it is. -> However, generally commands like `wc` and `ls` see the lists of -> file names matching these expressions, but not the wildcards -> themselves. It is the shell, not the other programs, that deals with -> expanding wildcards. -{: .callout} - -> ## List filenames matching a pattern -> -> Running `ls` in a directory gives the output -> `cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb` -> -> Which `ls` command(s) will -> produce this output? -> -> `ethane.pdb methane.pdb` -> -> 1. `ls *t*ane.pdb` -> 2. `ls *t?ne.*` -> 3. `ls *t??ne.pdb` -> 4. `ls ethane.*` -> ->> ## Solution ->> ->> The solution is `3.` ->> ->> `1.` shows all files whose names contain zero or more characters (`*`) ->> followed by the letter `t`, ->> then zero or more characters (`*`) followed by `ane.pdb`. ->> This gives `ethane.pdb methane.pdb octane.pdb pentane.pdb`. ->> ->> `2.` shows all files whose names start with zero or more characters (`*`) followed by ->> the letter `t`, ->> then a single character (`?`), then `ne.` followed by zero or more characters (`*`). ->> This will give us `octane.pdb` and `pentane.pdb` but doesn't match anything ->> which ends in `thane.pdb`. ->> ->> `3.` fixes the problems of option 2 by matching two characters (`??`) between `t` and `ne`. ->> This is the solution. ->> ->> `4.` only shows files starting with `ethane.`. -> {: .solution} -{: .challenge} +!!! question "Relative Path Resolution" + + Using the filesystem diagram below, if `pwd` displays `/Users/thing`, + what will `ls ../backup` display? + + 1. `../backup: No such file or directory` + 2. `2012-12-01 2013-01-08 2013-01-27` + 3. `original pnas_final pnas_sub` + + ![](../../Getting_Started/Getting_Help/Training/fig/filesystem-challenge.svg) + + ??? question Solution + 1. No: there *is* a directory `backup` in `/Users`. + 2. No: this is the content of `Users/thing/backup`, + but with `..`, we asked for one level further up. + 3. Yes: `../backup/` refers to `/Users/backup/`. + +!!! tip "Clearing your terminal" + + If your screen gets too cluttered, you can clear your terminal using the + `clear` command. You can still access previous commands using + and to move line-by-line, or by scrolling in your terminal. + +!!! question "Listing in Reverse Chronological Order" + + By default, `ls` lists the contents of a directory in alphabetical + order by name. The command `ls -t` lists items by time of last + change instead of alphabetically. The command `ls -r` lists the + contents of a directory in reverse order. + Which file is displayed last when you combine the `-t` and `-r` flags? + Hint: You may need to use the `-l` flag to see the + last changed dates. + + ??? question "Solution" + + The most recently changed file is listed last when using `-rt`. This + can be very useful for finding your most recent edits or checking to + see if a new output file was written. + + ??? question "Globbing" + + One of the most powerful features of bash is *filename expansion*, otherwise known as *globbing*. + This allows you to use *patterns* to match a file name (or multiple files), + which will then be operated on as if you had typed out all of the matches. + + `*` is a **wildcard**, which matches zero or more characters. + + Inside the `{{ working_dir|join('/') }}` directory there is a directory called `birds` + + ```sh + cd {{ working_dir|join('/') }}/birds + ls + ``` + + ```out + kaka.txt kakapo.jpeg kea.txt kiwi.jpeg pukeko.jpeg + ``` + + In this example there aren't many files, but it is easy to imagine a situation where you have hundreds or thousads of files you need to filter through, and globbing is the perfect tool for this. Using the wildcard character the command + + ```sh + ls ka* + ``` + + Will return: + + ```out + kaka.txt kakapo.jpeg + ``` + + Since the pattern `ka*` will match `kaka.txt`and `kakapo.jpeg` as these both start with "ka". While the command: + + ```sh + ls *.jpeg + ``` + + Will return: + + ```out + kakapo.jpeg kiwi.jpeg pukeko.jpeg + ``` + + As `*.jpeg` will match `kakapo.jpeg`, `kiwi.jpeg` and `pukeko.jpeg` as they all end in `.jpeg` + You can use multiple wildcards as well with the command: + + ```sh + ls k*a.* + ``` + + Returning: + + ```out + kaka.txt kea.txt + ``` + + As `k*a.*` will match just `kaka.txt` and `kea.txt` + + `?` is also a wildcard, but it matches exactly one character. So the command: + + ```sh + ls ????.* + ``` + + Would return: + + ```out + kaka.txt kiwi.jpeg + ``` + + As `kaka.txt` and `kiwi.jpeg` the only files which have four characters, followed by a `.` then any number and combination of characters. + + When the shell sees a wildcard, it expands the wildcard to create a + list of matching filenames *before* running the command that was + asked for. As an exception, if a wildcard expression does not match + any file, Bash will pass the expression as an argument to the command + as it is. + However, generally commands like `wc` and `ls` see the lists of + file names matching these expressions, but not the wildcards + themselves. It is the shell, not the other programs, that deals with + expanding wildcards. + + +??? question "List filenames matching a pattern" + + Running `ls` in a directory gives the output + `cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb` + + Which `ls` command(s) will + produce this output? + + `ethane.pdb methane.pdb` + + 1. `ls *t*ane.pdb` + 2. `ls *t?ne.*` + 3. `ls *t??ne.pdb` + 4. `ls ethane.*` + + ??? question Solution + The solution is `3.` + `1.` shows all files whose names contain zero or more characters (`*`) + followed by the letter `t`, + then zero or more characters (`*`) followed by `ane.pdb`. + This gives `ethane.pdb methane.pdb octane.pdb pentane.pdb`. + `2.` shows all files whose names start with zero or more characters (`*`) followed by + the letter `t`, + then a single character (`?`), then `ne.` followed by zero or more characters (`*`). + This will give us `octane.pdb` and `pentane.pdb` but doesn't match anything + which ends in `thane.pdb`. + `3.` fixes the problems of option 2 by matching two characters (`??`) between `t` and `ne`. + This is the solution. + `4.` only shows files starting with `ethane.`. include in terminal excersise (delete slurm files later on maybe?) @@ -664,34 +598,32 @@ include in terminal excersise (delete slurm files later on maybe?) Now let's create a file. To do this we will use a text editor called Nano to create a file called `draft.txt`: -``` -{{ site.remote.prompt }} nano draft.txt -``` -{: .language-bash} - -> ## Which Editor? -> -> When we say, '`nano` is a text editor' we really do mean 'text': it can -> only work with plain character data, not tables, images, or any other -> human-friendly media. We use it in examples because it is one of the -> least complex text editors. However, because of this trait, it may -> not be powerful enough or flexible enough for the work you need to do -> after this workshop. On Unix systems (such as Linux and macOS), -> many programmers use [Emacs](http://www.gnu.org/software/emacs/) or -> [Vim](http://www.vim.org/) (both of which require more time to learn), -> or a graphical editor such as -> [Gedit](http://projects.gnome.org/gedit/). On Windows, you may wish to -> use [Notepad++](http://notepad-plus-plus.org/). Windows also has a built-in -> editor called `notepad` that can be run from the command line in the same -> way as `nano` for the purposes of this lesson. -> -> No matter what editor you use, you will need to know where it searches -> for and saves files. If you start it from the shell, it will (probably) -> use your current working directory as its default location. If you use -> your computer's start menu, it may want to save files in your desktop or -> documents directory instead. You can change this by navigating to -> another directory the first time you 'Save As...' -{: .callout} +```sh + nano draft.txt +``` + +??? note "Which Editor?" + + When we say, '`nano` is a text editor' we really do mean 'text': it can + only work with plain character data, not tables, images, or any other + human-friendly media. We use it in examples because it is one of the + least complex text editors. However, because of this trait, it may + not be powerful enough or flexible enough for the work you need to do + after this workshop. On Unix systems (such as Linux and macOS), + many programmers use [Emacs](http://www.gnu.org/software/emacs/) or + [Vim](http://www.vim.org/) (both of which require more time to learn), + or a graphical editor such as + [Gedit](http://projects.gnome.org/gedit/). On Windows, you may wish to + use [Notepad++](http://notepad-plus-plus.org/). Windows also has a built-in + editor called `notepad` that can be run from the command line in the same + way as `nano` for the purposes of this lesson. + + No matter what editor you use, you will need to know where it searches + for and saves files. If you start it from the shell, it will (probably) + use your current working directory as its default location. If you use + your computer's start menu, it may want to save files in your desktop or + documents directory instead. You can change this by navigating to + another directory the first time you 'Save As...' Let's type in a few lines of text. Once we're happy with our text, we can press Ctrl+O @@ -706,58 +638,52 @@ src="../../Getting_Started/Getting_Help/Training/fig/nano-screenshot.png"> Once our file is saved, we can use Ctrl+X to quit the editor and return to the shell. -> ## Control, Ctrl, or ^ Key -> -> The Control key is also called the 'Ctrl' key. There are various ways -> in which using the Control key may be described. For example, you may -> see an instruction to press the Control key and, while holding it down, -> press the X key, described as any of: -> -> * `Control-X` -> * `Control+X` -> * `Ctrl-X` -> * `Ctrl+X` -> * `^X` -> * `C-x` -> -> In nano, along the bottom of the screen you'll see `^G Get Help ^O WriteOut`. -> This means that you can use `Control-G` to get help and `Control-O` to save your -> file. -{: .callout} +??? tip "Control, Ctrl, or ^ Key" + + The Control key is also called the 'Ctrl' key. There are various ways + in which using the Control key may be described. For example, you may + see an instruction to press the Control key and, while holding it down, + press the X key, described as any of: + + * `Control-X` + * `Control+X` + * `Ctrl-X` + * `Ctrl+X` + * `^X` + * `C-x` + + In nano, along the bottom of the screen you'll see `^G Get Help ^O WriteOut`. + This means that you can use `Control-G` to get help and `Control-O` to save your + file. `nano` doesn't leave any output on the screen after it exits, but `ls` now shows that we have created a file called `draft.txt`: +```sh + ls ``` -{{ site.remote.prompt }} ls -``` -{: .language-bash} -``` +```out draft.txt ``` -{: .output} ## Copying files and directories -In a future lesson, we will be running the R script ```{{ site.working_dir | join: '/' }}/{{ site.example.script }}```, but as we can't all work on the same file at once you will need to take your own copy. This can be done with the **c**o**p**y command `cp`, at least two arguments are needed the file (or directory) you want to copy, and the directory (or file) where you want the copy to be created. We will be copying the file into the directory we made previously, as this should be your current directory the second argument can be a simple `.`. +In a future lesson, we will be running the R script ```{{ working_dir|join('/') }}/{{ example_script }}```, but as we can't all work on the same file at once you will need to take your own copy. This can be done with the **c**o**p**y command `cp`, at least two arguments are needed the file (or directory) you want to copy, and the directory (or file) where you want the copy to be created. We will be copying the file into the directory we made previously, as this should be your current directory the second argument can be a simple `.`. +```sh + cp {{ working_dir|join('/') }}/{{ example_script }} . ``` -{{ site.remote.prompt }} cp {{ site.working_dir | join: '/' }}/{{ site.example.script }} . -``` -{: .output} We can check that it did the right thing using `ls` +```sh + ls ``` -{{ site.remote.prompt }} ls -``` -{: .language-bash} +```out +draft.txt {{ example_script }} ``` -draft.txt {{ site.example.script }} -``` -{: .output} ## Other File operations @@ -805,52 +731,46 @@ The same is true when deleting directories with `rm` For `mv` and `cp` if the destination path (final argument) is an existing directory the file will be placed inside that directory with the same name as the source. -> ## Moving vs Copying -> -> When using the `cp` or `rm` commands on a directory the 'recursive' flag `-r` must be used, but `mv` *does not* require it? -> ->> ## Solution ->> ->> We mentioned previously that as far the computer is concerned, *renaming* is the same operation as *moving*. ->> Contrary to what the commands name implies, *all moving is actually renaming*. ->> The data on the hard drive stays in the same place, ->> only the label applied to that block of memory is changed. ->> To copy a directory, each *individual file* inside that directory must be read, and then written to the copy destination. ->> To delete a directory, each *individual file* in the directory must be marked for deletion, ->> however when moving a directory the files inside are the data inside the directory is not interacted with, ->> only the parent directory is "renamed" to a different place. ->> ->> This is also why `mv` is faster than `cp` as no reading of the files is required. -> {: .solution} -{: .challenge} +!!! question "Moving vs Copying" -> ## Unsupported command-line options -> -> If you try to use an option (flag) that is not supported, `ls` and other commands -> will usually print an error message similar to: -> -> ``` -> $ ls -j -> ``` -> {: .language-bash} -> -> ``` -> ls: invalid option -- 'j' -> Try 'ls --help' for more information. -> ``` -> {: .error} -{: .callout} + When using the `cp` or `rm` commands on a directory the 'recursive' flag `-r` must be used, but `mv` *does not* require it? -## Getting help + ??? note Solution -Commands will often have many **options**. Most commands have a `--help` flag, as can be seen in the error above. You can also use the manual pages (aka manpages) by using the `man` command. The manual page provides you with all the available options and their use in more detail. For example, for thr `ls` command: + We mentioned previously that as far the computer is concerned, *renaming* is the same operation as *moving*. + Contrary to what the commands name implies, *all moving is actually renaming*. + The data on the hard drive stays in the same place, + only the label applied to that block of memory is changed. + To copy a directory, each *individual file* inside that directory must be read, and then written to the copy destination. + To delete a directory, each *individual file* in the directory must be marked for deletion, + however when moving a directory the files inside are the data inside the directory is not interacted with, + only the parent directory is "renamed" to a different place. + + This is also why `mv` is faster than `cp` as no reading of the files is required. + +## Unsupported command-line options + +If you try to use an option (flag) that is not supported, `ls` and other commands +will usually print an error message similar to: +```sh +ls -j ``` -{{ site.remote.prompt }} man ls + +```out +ls: invalid option -- 'j' +Try 'ls --help' for more information. ``` -{: .language-bash} +## Getting help + +Commands will often have many **options**. Most commands have a `--help` flag, as can be seen in the error above. You can also use the manual pages (aka manpages) by using the `man` command. The manual page provides you with all the available options and their use in more detail. For example, for thr `ls` command: + +```sh + man ls ``` + +```out Usage: ls [OPTION]... [FILE]... List information about the FILEs (the current directory by default). Sort entries alphabetically if neither -cftuvSUX nor --sort is specified. @@ -877,7 +797,6 @@ Mandatory arguments to long options are mandatory for short options, too. -F, --classify append indicator (one of */=>@|) to entries ...       ...       ... ``` -{: .output} To navigate through the `man` pages, you may use and to move line-by-line, @@ -888,15 +807,30 @@ Sometimes a search will result in multiple hits. If so, you can move between hit To **quit** the `man` pages, press Q. -> ## Manual pages on the web -> -> Of course, there is a third way to access help for commands: -> searching the internet via your web browser. -> When using internet search, including the phrase `unix man page` in your search -> query will help to find relevant results. -> -> GNU provides links to its -> [manuals](http://www.gnu.org/manual/manual.html) including the -> [core GNU utilities](http://www.gnu.org/software/coreutils/manual/coreutils.html), -> which covers many commands introduced within this lesson. -{: .callout} +!!! info "Manual pages on the web" + Of course, there is a third way to access help for commands: + searching the internet via your web browser. + When using internet search, including the phrase `unix man page` in your search + query will help to find relevant results. + GNU provides links to its + [manuals](http://www.gnu.org/manual/manual.html) including the + [core GNU utilities](http://www.gnu.org/software/coreutils/manual/coreutils.html), + which covers many commands introduced within this lesson. + + +!!! keypoints + - "The file system is responsible for managing information on the disk." + - "Information is stored in files, which are stored in directories (folders)." + - "Directories can also store other directories, which then form a directory tree." + - "`cd [path]` changes the current working directory." + - "`ls [path]` prints a listing of a specific file or directory; `ls` on its own lists the current working directory." + - "`pwd` prints the user's current working directory." + - "`cp [file] [path]` copies [file] to [path]" + - "`mv [file] [path]` moves [file] to [path]" + - "`rm [file]` deletes [file]" + - "`/` on its own is the root directory of the whole file system." + - "Most commands take options (flags) that begin with a `-`." + - "A relative path specifies a location starting from the current location." + - "An absolute path specifies a location from the root of the file system." + - "Directory names in a path are separated with `/` on Unix, but `\\` on Windows." + - "`..` means 'the directory above the current one'; `.` on its own means 'the current directory'." diff --git a/docs/Tutorials/Introduction_To_HPC/Parallel.md b/docs/Tutorials/Introduction_To_HPC/Parallel.md index 7771d2d82..6a1b0af16 100644 --- a/docs/Tutorials/Introduction_To_HPC/Parallel.md +++ b/docs/Tutorials/Introduction_To_HPC/Parallel.md @@ -1,27 +1,18 @@ --- -title: "What is Parallel Computing" -teaching: 20 -exercises: 10 -questions: -- "How do we execute a task in parallel?" -- "What benefits arise from parallel execution?" -- "What are the limits of gains from execution in parallel?" -- "What is the difference between implicit and explicit parallelisation." -objectives: -- "Prepare a job submission script for the parallel executable." -keypoints: -- "Parallel programming allows applications to take advantage of - parallel hardware; serial code will not 'just work.'" -- "There are multiple ways you can run " +created_at: 2026-01-16 --- + +!!! time "30 minutes" + +!!! objectives + - "Prepare a job submission script for the parallel executable." + ## Methods of Parallel Computing To understand the different types of Parallel Computing we first need to clarify some terms. -{% include figure.html url="" max-width="40%" - file="/fig/clusterDiagram.png" - alt="Node anatomy" caption="" %} +![alt text](../../assets/images/clusterDiagram.png) **CPU**: Unit that does the computations. @@ -43,7 +34,7 @@ Often called *Multithreading*. This means that all CPUs must be on the same node, most Mahuika nodes have 72 CPUs. -Shared memory parallelism is used in our example script `{{ site.example.script }}`. +Shared memory parallelism is used in our example script `{{ config.extra.example_script }}`. Number of threads to use is specified by the Slurm option `--cpus-per-task`. @@ -75,64 +66,56 @@ GPUs can be requested using `--gpus-per-node=:` Depending on the GPU type, we *may* also need to specify a partition using `--partition`. -> ## GPU Job Example -> -> Create a new script called `gpu-job.sl` -> -> ``` -> #!/bin/bash -e -> -> #SBATCH --job-name gpu-job -> #SBATCH --account {{site.sched.projectcode}} -> #SBATCH --output %x.out -> #SBATCH --mem-per-cpu 2G -> #SBATCH --gpu-per-node P100:1 -> -> module load CUDA -> nvidia-smi -> ``` -> {: .language-bash} -> -> then submit with -> -> ``` -> {{ site.remote.prompt }} sbatch gpu-job.sl -> ``` -> {: .language-bash} -> -> > ## Solution -> > -> > ``` -> > {{ site.remote.prompt }} cat gpu-job.out -> > -> > ``` -> > {: .language-bash} -> > -> > ``` -> > Tue Mar 12 19:40:51 2024 -> > +-----------------------------------------------------------------------------+ -> > | NVIDIA-SMI 525.85.12 Driver Version: 525.85.12 CUDA Version: 12.0 | -> > |-------------------------------+----------------------+----------------------+ -> > | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | -> > | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | -> > | | | MIG M. | -> > |===============================+======================+======================| -> > | 0 Tesla P100-PCIE... On | 00000000:05:00.0 Off | 0 | -> > | N/A 28C P0 24W / 250W | 0MiB / 12288MiB | 0% Default | -> > | | | N/A | -> > +-------------------------------+----------------------+----------------------+ -> > -> > +-----------------------------------------------------------------------------+ -> > | Processes: | -> > | GPU GI CI PID Type Process name GPU Memory | -> > | ID ID Usage | -> > |=============================================================================| -> > | No running processes found | -> > +-----------------------------------------------------------------------------+ -> > ``` -> > {: .output} -> {: .solution} -{: .challenge} +## GPU Job Example + +Create a new script called `gpu-job.sl` + +```sl +#!/bin/bash -e +#SBATCH --job-name gpu-job +#SBATCH --account {{config.extra.project_code}} +#SBATCH --output %x.out +#SBATCH --mem-per-cpu 2G +#SBATCH --gpu-per-node P100:1 + +module load CUDA +nvidia-smi +``` + +then submit with + +```sh + sbatch gpu-job.sl +``` + +??? question Solution + + ```out + cat gpu-job.out + ``` + + ```out + Tue Mar 12 19:40:51 2024 + +-----------------------------------------------------------------------------+ + | NVIDIA-SMI 525.85.12 Driver Version: 525.85.12 CUDA Version: 12.0 | + |-------------------------------+----------------------+----------------------+ + | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | + | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | + | | | MIG M. | + |===============================+======================+======================| + | 0 Tesla P100-PCIE... On | 00000000:05:00.0 Off | 0 | + | N/A 28C P0 24W / 250W | 0MiB / 12288MiB | 0% Default | + | | | N/A | + +-------------------------------+----------------------+----------------------+ + + +-----------------------------------------------------------------------------+ + | Processes: | + | GPU GI CI PID Type Process name GPU Memory | + | ID ID Usage | + |=============================================================================| + | No running processes found | + +-----------------------------------------------------------------------------+ + ``` ### Job Array @@ -187,16 +170,8 @@ However, unless that function is where the majority of time is spent, this is un | Job Array | | `--array` | | | General Purpose GPU | | `--gpus-per-node` | | -> ## Running a Parallel Job. -> -> Pick one of the method of Paralellism mentioned above, and modify your `example.sl` script to use this method. -> -> -> > ## Solution -> > -> > What does the printout say at the start of your job about number and location of node. -> > {: .output} -> {: .solution} -{: .challenge} - -{% include links.md %} + +!!! keypoints + - "Parallel programming allows applications to take advantage of + parallel hardware; serial code will not 'just work.'" + - "There are multiple ways you can run " diff --git a/docs/Tutorials/Introduction_To_HPC/Resources.md b/docs/Tutorials/Introduction_To_HPC/Resources.md index e9fdc9465..0e7b4e2c8 100644 --- a/docs/Tutorials/Introduction_To_HPC/Resources.md +++ b/docs/Tutorials/Introduction_To_HPC/Resources.md @@ -1,70 +1,85 @@ --- -title: "Using resources effectively" -teaching: 20 -exercises: 10 -questions: -- "How can I review past jobs?" -- "How can I use this knowledge to create a more accurate submission script?" -objectives: -- "Understand how to look up job statistics and profile code." -- "Understand job size implications." -- "Understand problems and limitations involved in using multiple CPUs." -keypoints: -- "As your task gets larger, so does the potential for inefficiencies." -- "The smaller your job (time, CPUs, memory, etc), the faster it will schedule." -math: True +created_at: 2026-01-16 --- + +!!! time "30 Minutes" + +!!! objectives + - "Understand how to look up job statistics and profile code." + - "Understand job size implications." + - "Understand problems and limitations involved in using multiple CPUs." + ## What Resources? Last time we submitted a job, we did not specify a number of CPUs, and therefore we were provided the default of `2` (1 _core_). -As a reminder, our slurm script `example_job.sl` currently looks like this. +As a reminder, our Slurm script `example_job.sl` currently looks like this. -``` -{% include example_scripts/example_job.sl.1 %} -``` +```sl +#!/bin/bash -e -{: .language-bash} +#SBATCH --job-name example_job +#SBATCH --account nesi99991 +#SBATCH --mem 300M +#SBATCH --time 00:15:00 + +module purge +module load R/4.3.1-gimkl-2022a +Rscript sum_matrix.r +echo "Done!"``` +``` We will now submit the same job again with more CPUs. We ask for more CPUs using by adding `#SBATCH --cpus-per-task 4` to our script. Your script should now look like this: -``` -{% include example_scripts/example_job.sl.2 %} -``` +```sl +#!/bin/bash -e + +#SBATCH --job-name example_job +#SBATCH --account nesi99991 +#SBATCH --mem 300M +#SBATCH --time 00:15:00 +#SBATCH --cpus-per-task 4 -{: .language-bash} +module purge +module load R/4.3.1-gimkl-2022a +Rscript sum_matrix.r +echo "Done!" +``` And then submit using `sbatch` as we did before. +```sh + sbatch example_job.sl ``` -{{ site.remote.prompt }} sbatch example_job.sl -``` - -{: .language-bash} -{% include {{ site.snippets }}/scheduler/basic-job-script.snip %} +```out +Submitted batch job 23137702 +``` -> ## Watch -> -> We can prepend any command with `watch` in order to periodically (default 2 seconds) run a command. e.g. `watch -> squeue --me` will give us up to date information on our running jobs. -> Care should be used when using `watch` as repeatedly running a command can have adverse effects. -> Exit `watch` with ctrl + c. -{: .callout} +!!! tip Watch + We can prepend any command with `watch` in order to periodically (default 2 seconds) run a command. e.g. `watch + squeue --me` will give us up to date information on our running jobs. + Care should be used when using `watch` as repeatedly running a command can have adverse effects. + Exit `watch` with ctrl + c. Note in squeue, the number under cpus, should be '4'. Checking on our job with `sacct`. Oh no! -{% include {{ site.snippets }}/scaling/OOM.snip %} -{: .language-bash} +```out +JobID JobName Partition Account AllocCPUS State ExitCode +------------ ---------- ---------- ---------- ---------- ---------- -------- +27323464 my_job large {{ config.extra.project_code }} 4 OUT_OF_ME+ 0:125 +27323464.ba+ batch {{ config.extra.project_code }} 4 OUT_OF_ME+ 0:125 +27323464.ex+ extern {{ config.extra.project_code }} 4 COMPLETED 0:0 +``` To understand why our job failed, we need to talk about the resources involved. @@ -109,20 +124,22 @@ Below is a table of common resources and issues you may face if you do not reque Since we have already run a job (successful or otherwise), this is the best source of info we currently have. If we check the status of our finished job using the `sacct` command we learned earlier. +```sh + sacct ``` -{{ site.remote.prompt }} sacct -``` - -{: .language-bash} -{% include {{ site.snippets }}/scheduler/basic-job-status-sacct.snip %} +```sh +JobID JobName Alloc Elapsed TotalCPU ReqMem MaxRSS State +--------------- ---------------- ----- ----------- ------------ ------- -------- ---------- +31060451 example_job.sl 2 00:00:48 00:33.548 1G CANCELLED +31060451.batch batch 2 00:00:48 00:33.547 102048K CANCELLED +31060451.extern extern 2 00:00:48 00:00:00 0 CANCELLED +``` With this information, we may determine a couple of things. Memory efficiency can be determined by comparing ReqMem (requested memory) with MaxRSS (maximum used memory), MaxRSS is given in KB, so a unit conversion is usually required. - -
$$ {Efficiency_{mem} = { MaxRSS \over ReqMem}} $$ @@ -133,8 +150,6 @@ So for the above example we see that 0.1GB (102048K) of our req CPU efficiency can be determined by comparing TotalCPU(CPU time), with the maximum possible CPU time. The maximum possible CPU time equal to Alloc (number of allocated CPUs) multiplied by Elapsed (Walltime, actual time passed). - - $$ {Efficiency_{cpu} = { TotalCPU \over {Elapsed \times Alloc}}} $$
@@ -147,60 +162,69 @@ Time Efficiency is simply the Elapsed Time divided by T
-$$ {Efficiency_{time} = { Elapsed \over Requested}} $$ - - +$$ {Efficiency_{time} = { Elapsed \over Requested }} $$
48 seconcds out of 15 minutes requested give a time efficiency of about 5% -> ## Efficiency Exercise -> -> Calculate for the job shown below, -> -> ``` -> JobID JobName Alloc Elapsed TotalCPU ReqMem MaxRSS State -> --------------- ---------------- ----- ----------- ------------ ------- -------- ---------- -> 37171050 Example-job 8 00:06:03 00:23:04 32G FAILED -> 37171050.batch batch 8 00:06:03 23:03.999 14082672k FAILED -> 37171050.extern extern 8 00:06:03 00:00.001 0 COMPLETED -> ``` -> -> a. CPU efficiency. -> -> b. Memory efficiency. -> -> > ## Solution -> > -> > a. CPU efficiency is `( 23 / ( 8 * 6 ) ) x 100` or around **48%**. -> > -> > b. Memory efficiency is `( 14 / 32 ) x 100` or around **43%**. -> {: .solution} -{: .challenge} +!!! question "Efficiency Exercise" + Calculate for the job shown below, + + ```out + JobID JobName Alloc Elapsed TotalCPU ReqMem MaxRSS State + --------------- ---------------- ----- ----------- ------------ ------- -------- ---------- + 37171050 Example-job 8 00:06:03 00:23:04 32G FAILED + 37171050.batch batch 8 00:06:03 23:03.999 14082672k FAILED + 37171050.extern extern 8 00:06:03 00:00.001 0 COMPLETED + ``` + + a. CPU efficiency. + b. Memory efficiency. + + ??? question Solution + a. CPU efficiency is `( 23 / ( 8 * 6 ) ) x 100` or around **48%**. + b. Memory efficiency is `( 14 / 32 ) x 100` or around **43%**. For convenience, NeSI has provided the command `nn_seff ` to calculate **S**lurm **Eff**iciency (all NeSI commands start with `nn_`, for **N**eSI **N**IWA). -``` -{{ site.remote.prompt }} nn_seff +```sh + nn_seff ``` -{: .language-bash} - -{% include {{ site.snippets }}/resources/seff.snip %} +```out +Job ID: 27323570 +Cluster: mahuika +User/Group: username/username +State: COMPLETED (exit code 0) +Cores: 1 +Tasks: 1 +Nodes: 1 +Job Wall-time: 5.11% 00:00:46 of 00:15:00 time limit +CPU Efficiency: 141.30% 00:01:05 of 00:00:46 core-walltime +Mem Efficiency: 93.31% 233.29 MB of 250.00 MB +``` Knowing what we do now about job efficiency, lets submit the previous job again but with more appropriate resources. -``` -{% include example_scripts/example_job.sl.2 %} -``` -{: .language-bash} +```sl +#!/bin/bash -e +#SBATCH --job-name example_job +#SBATCH --account nesi99991 +#SBATCH --mem 300M +#SBATCH --time 00:15:00 +#SBATCH --cpus-per-task 4 +module purge +module load R/4.3.1-gimkl-2022a +Rscript sum_matrix.r +echo "Done!" ``` -{{ site.remote.prompt }} sbatch example_job.sl + +```sh +sbatch example_job.sl ``` -{: .language-bash} Hopefully we will have better luck with this one! @@ -228,8 +252,8 @@ SMT is why you are provided 2 CPUs instead of 1 as we do not allow 2 different jobs to share a core. This also explains why you will sometimes see CPU efficiency above 100%, since CPU efficiency is based on core and not thread. -For more details please see our [documentation on Hyperthreading -](https://docs.nesi.org.nz/Scientific_Computing/Running_Jobs_on_Maui_and_Mahuika/Hyperthreading/) +For more details please see our +[documentation on Hyperthreading](https://docs.nesi.org.nz/Scientific_Computing/Running_Jobs_on_Maui_and_Mahuika/Hyperthreading/) ## Measuring the System Load From Currently Running Tasks @@ -245,32 +269,29 @@ The most reliable way to check current system stats is with `htop`. Before we can check on our job, we need to find out where it is running. We can do this with the command `squeue --me`, and looking under the 'NODELIST' column. +```sh + squeue --me ``` -{{ site.remote.prompt }} squeue --me -``` - -{: .language-bash} -{% include {{ site.snippets }}/resources/get-job-node.snip %} +```out +JOBID USER ACCOUNT NAME CPUS MIN_MEM PARTITI START_TIME TIME_LEFT STATE NODELIST(REASON) +26763045 cwal219 {{config.extra.project_code}} test 2 512M large May 11 11:35 14:46 RUNNING wbn144 +``` Now that we know the location of the job (wbn189) we can use `ssh` to run `htop` _on that node_. +```sh + ssh wbn189 -t htop -u $USER ``` -{{ site.remote.prompt }} ssh wbn189 -t htop -u $USER -``` - -{: .language-bash} You may get a message: -``` +```sh ECDSA key fingerprint is SHA256:############################################ ECDSA key fingerprint is MD5:9d:############################################ Are you sure you want to continue connecting (yes/no)? ``` -{: .language-bash} - If so, type `yes` and Enter You may also need to enter your cluster password. @@ -281,20 +302,37 @@ If you cannot connect, it may be that the job has finished and you have lost per You may see something like this, -{% include {{ site.snippets }}/resources/monitor-processes-top.snip %} +```out +top - 21:00:19 up 3:07, 1 user, load average: 1.06, 1.05, 0.96 +Tasks: 311 total, 1 running, 222 sleeping, 0 stopped, 0 zombie +%Cpu(s): 7.2 us, 3.2 sy, 0.0 ni, 89.0 id, 0.0 wa, 0.2 hi, 0.2 si, 0.0 st +KiB Mem : 16303428 total, 8454704 free, 3194668 used, 4654056 buff/cache +KiB Swap: 8220668 total, 8220668 free, 0 used. 11628168 avail Mem + + PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND + 1693 jeff 20 0 4270580 346944 171372 S 29.8 2.1 9:31.89 gnome-shell + 3140 jeff 20 0 3142044 928972 389716 S 27.5 5.7 13:30.29 Web Content + 3057 jeff 20 0 3115900 521368 231288 S 18.9 3.2 10:27.71 firefox + 6007 jeff 20 0 813992 112336 75592 S 4.3 0.7 0:28.25 tilix + 1742 jeff 20 0 975080 164508 130624 S 2.0 1.0 3:29.83 Xwayland + 1 root 20 0 230484 11924 7544 S 0.3 0.1 0:06.08 systemd + 68 root 20 0 0 0 0 I 0.3 0.0 0:01.25 kworker/4:1 + 2913 jeff 20 0 965620 47892 37432 S 0.3 0.3 0:11.76 code + 2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd +``` Overview of the most important fields: -* `PID`: What is the numerical id of each process? -* `USER`: Who started the process? -* `RES`: What is the amount of memory currently being used by a process (in +- `PID`: What is the numerical id of each process? +- `USER`: Who started the process? +- `RES`: What is the amount of memory currently being used by a process (in bytes)? -* `%CPU`: How much of a CPU is each process using? Values higher than 100 +- `%CPU`: How much of a CPU is each process using? Values higher than 100 percent indicate that a process is running in parallel. -* `%MEM`: What percent of system memory is a process using? -* `TIME+`: How much CPU time has a process used so far? Processes using 2 CPUs +- `%MEM`: What percent of system memory is a process using? +- `TIME+`: How much CPU time has a process used so far? Processes using 2 CPUs accumulate time at twice the normal rate. -* `COMMAND`: What command was used to launch a process? +- `COMMAND`: What command was used to launch a process? To exit press q. @@ -309,43 +347,37 @@ Similar as possible to actual jobs e.g. same functions etc. Use same workflow. (most issues are caused by small issues, typos, missing files etc, your test job is a jood chance to sort out these issues.). Make sure outputs are going somewhere you can see them. -> ## Serial Test -> -> Often a good first test to run, is to execute your job _serially_ e.g. using only 1 CPU. -> This not only saves you time by being fast to start, but serial jobs can often be easier to debug. -> If you confirm your job works in its most simple state you can identify problems caused by -> paralellistaion much more easily. -{: .callout} +!!! tip "Serial Test" + Often a good first test to run, is to execute your job _serially_ e.g. using only 1 CPU. + This not only saves you time by being fast to start, but serial jobs can often be easier to debug. + If you confirm your job works in its most simple state you can identify problems caused by + paralellistaion much more easily. You generally should ask for 20% to 30% more time and memory than you think the job will use. Testing allows you to become more more precise with your resource requests. We will cover a bit more on running tests in the last lesson. -> ## Efficient way to run tests jobs using debug QOS (Quality of Service) -> -> Before submitting a large job, first submit one as a test to make -> sure everything works as expected. Often, users discover typos in their submit -> scripts, incorrect module names or possibly an incorrect pathname after their job -> has queued for many hours. Be aware that your job is not fully scanned for -> correctness when you submit the job. While you may get an immediate error if your -> SBATCH directives are malformed, it is not until the job starts to run that the -> interpreter starts to process the batch script. -> -> NeSI has an easy way for you to test your job submission. One can employ the debug -> QOS to get a short, high priority test job. Debug jobs have to run within 15 -> minutes and cannot use more that 2 nodes. To use debug QOS, add or change the -> following in your batch submit script -> ->``` ->#SBATCH --qos=debug ->#SBATCH --time=15:00 -> ``` -> ->{: .language-bash} -> -> Adding these SBATCH directives will provide your job with the highest priority -> possible, meaning it should start to run within a few minutes, provided -> your resource request is not too large. -{: .callout} +## Efficient way to run tests jobs using debug QOS (Quality of Service) + +Before submitting a large job, first submit one as a test to make +sure everything works as expected. Often, users discover typos in their submit +scripts, incorrect module names or possibly an incorrect pathname after their job +has queued for many hours. Be aware that your job is not fully scanned for +correctness when you submit the job. While you may get an immediate error if your +SBATCH directives are malformed, it is not until the job starts to run that the +interpreter starts to process the batch script. +NeSI has an easy way for you to test your job submission. One can employ the debug +QOS to get a short, high priority test job. Debug jobs have to run within 15 +minutes and cannot use more that 2 nodes. To use debug QOS, add or change the +following in your batch submit script + +``sh +SBATCH --qos=debug +SBATCH --time=15:00 +``` + +Adding these SBATCH directives will provide your job with the highest priority +possible, meaning it should start to run within a few minutes, provided +your resource request is not too large. ## Initial Resource Requirements @@ -364,13 +396,13 @@ If you know someone who has used the software before, they may be able to give y -> ## Next Steps -> -> You can use this knowledge to set up the -> next job with a closer estimate of its load on the system. -> A good general rule -> is to ask the scheduler for **30%** more time and memory than you expect the -> job to need. -{: .callout} +!!! postrequisite "Next Steps" + You can use this knowledge to set up the + next job with a closer estimate of its load on the system. + A good general rule + is to ask the scheduler for **30%** more time and memory than you expect the + job to need. -{% include links.md %} +!!! keypoints + - "As your task gets larger, so does the potential for inefficiencies." + - "The smaller your job (time, CPUs, memory, etc), the faster it will schedule." diff --git a/docs/assets/images/clusterDiagram.png b/docs/assets/images/clusterDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..a7efa81b9a3d816d947eaee9a63d17f40ad52c4a GIT binary patch literal 9238 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