| CONTENTS |
As a computer user, you spend lots of time creating files. Just as the necessary counterpart of life is death, the other side of file creation is deletion. If you never delete any files, you soon have a computer's equivalent of a population explosion: your disks get full, and you must either spend money (buy and install more disk drives) or figure out which files you don't really need.
In this chapter, we'll talk about ways to get rid of files: how to do it safely, how to get rid of files that don't want to die, and how to find "stale" files — or unused files that have been around for a long time. "Safe" deletion is a particularly interesting topic, because Unix's rm command is extreme: once you delete a file, it's gone permanently. There are several solutions for working around this problem, letting you (possibly) reclaim files from the dead.
— ML
The ability to mumble about inodes is the key to social success at a Unix gurus' cocktail party. This may not seem attractive to you, but sooner or later you will need to know what an inode is.
Seriously, inodes are an important part of the Unix filesystem. You don't need to worry about them most of the time, but it does help to know what they are.
An inode is a data structure on the disk that describes a file. It holds most of the important information about the file, including the on-disk address of the file's data blocks (the part of the file that you care about). Each inode has its own identifying number, called an i-number.
You really don't care about where a file is physically located on a disk. You usually don't care about the i-number — unless you're trying to find the links (Section 9.24, Section 10.3) to a file. But you do care about the following information, all of which is stored in a file's inode:
The user and the group that own the file
Whether various users and groups are allowed to read, write, or execute the file
When the file itself was last modified, when the file was last accessed, and when the inode was last modified
Whether the file is a regular file, a special file, or some other kind of abstraction masquerading (Section 1.19) as a file
Each filesystem has a set number of inodes that are created when the filesystem is first created (usually when the disk is first initialized). This number is therefore the maximum number of files that the filesystem can hold. It cannot be changed without reinitializing the filesystem, which destroys all the data that the filesystem holds. It is possible, though rare, for a filesystem to run out of inodes, just as it is possible to run out of storage space — this can happen on filesystems with many, many small files.
The ls -l (Section 50.2) command shows much of this information. The ls -i option (Section 10.4) shows a file's i-number. The stat command lists almost everything in an inode.
— ML
Under Unix, you use the rm command to delete files. The command is simple enough; you just type rm followed by a list of files. If anything, rm is too simple. It's easy to delete more than you want, and once something is gone, it's permanently gone. There are a few hacks that make rm somewhat safer, and we'll get to those momentarily. But first, here's a quick look at some of the dangers.
To understand why it's impossible to reclaim deleted files, you need to know a bit about how the Unix filesystem works. The system contains a "free list," which is a list of disk blocks that aren't used. When you delete a file, its directory entry (which gives it its name) is removed. If there are no more links (Section 10.3) to the file (i.e., if the file only had one name), its inode (Section 14.2) is added to the list of free inodes, and its datablocks are added to the free list.
Well, why can't you get the file back from the free list? After all, there are DOS utilities that can reclaim deleted files by doing something similar. Remember, though, Unix is a multitasking operating system. Even if you think your system is a single-user system, there are a lot of things going on "behind your back": daemons are writing to log files, handling network connections, processing electronic mail, and so on. You could theoretically reclaim a file if you could "freeze" the filesystem the instant your file was deleted — but that's not possible. With Unix, everything is always active. By the time you realize you made a mistake, your file's data blocks may well have been reused for something else.
When you're deleting files, it's important to use wildcards carefully. Simple typing errors can have disastrous consequences. Let's say you want to delete all your object (.o) files. You want to type:
% rm *.o
But because of a nervous twitch, you add an extra space and type:
% rm * .o
It looks right, and you might not even notice the error. But before you know it, all the files in the current directory will be gone, irretrievably.
If you don't think this can happen to you, here's something that actually did happen to me. At one point, when I was a relatively new Unix user, I was working on my company's business plan. The executives thought, so as to be "secure," that they'd set a business plan's permissions so you had to be root (Section 1.18) to modify it. (A mistake in its own right, but that's another story.) I was using a terminal I wasn't familiar with and accidentally created a bunch of files with four control characters at the beginning of their name. To get rid of these, I typed (as root):
# rm ????*
This command took a long time to execute. When about two-thirds of the directory was gone, I realized (with horror) what was happening: I was deleting all files with four or more characters in the filename.
The story got worse. They hadn't made a backup in about five months. (By the way, this article should give you plenty of reasons for making regular backups (Section 38.3).) By the time I had restored the files I had deleted (a several-hour process in itself; this was on an ancient version of Unix with a horrible backup utility) and checked (by hand) all the files against our printed copy of the business plan, I had resolved to be very careful with my rm commands.
[Some shells have safeguards that work against Mike's first disastrous example — but not the second one. Automatic safeguards like these can become a crutch, though . . . when you use another shell temporarily and don't have them, or when you type an expression like Mike's very destructive second example. I agree with his simple advice: check your rm commands carefully! — JP]
— ML
Summary BoxHere's a summary of ways to protect yourself from accidentally deleting files:
If you want to delete with wild abandon, use rm -f (Section 14.10). — ML |
Some commands — like rm -i, find -ok, and so on — ask users to answer a "do it or not?" question from the keyboard. For example, you might have a file-deleting program or alias named del that asks before deleting each file:
% del * Remove file1? y Remove file2? y ...
If you answer y, then the file will be deleted.
What if you want to run a command that will ask you 200 questions and you want to answer y to all of them, but you don't want to type all those ys from the keyboard? Pipe the output of yes to the command; it will answer y for you:
% yes | del * Remove file1? Remove file2? ...
If you want to answer n to all the questions, you can do:
% yes n | del *
|
— JP
Most people use rm -i for safety: so they're always asked for confirmation before removing a particular file. Mike Loukides told me about another way he uses rm -i. When he has several files to remove, but the wildcards (Section 1.13) would be too painful to type with a plain rm, Mike gives rm -i a bigger list of filenames and answers "n" to filenames he doesn't want deleted.
— JP
The rm -i command asks you about each file, separately. The method in this article can give you the safety without the hassle of typing y as much.
Another approach, which I recommend, is that you create a new script or alias, and use that alias whenever you delete files. Call the alias del or Rm, for instance. This way, if you ever execute your special delete command when it doesn't exist, no harm is done — you just get an error. If you get into this habit, you can start making your delete script smarter. Here is one that asks you about each file if there are three or fewer files specified. For more than three files, it displays them all and asks you once if you wish to delete them all:
#!/bin/sh case $# in 0) echo "`basename $0`: you didn't say which file(s) to delete"; exit 1;; [123]) /bin/rm -i "$@" ;; *) echo "$*" echo do you want to delete these files\? read a case "$a" in [yY]*) /bin/rm "$@" ;; esac ;; esac
— BB
Using noclobber (Section 43.6) and read-only files only protects you from a few occasional mistakes. A potentially catastrophic error is typing:
% rm * .o
instead of:
% rm *.o
In the blink of an eye, all of your files would be gone. A simple, yet effective, preventive measure is to create a file called -i in the particular directory in which you want extra protection:
./- Section 14.13
% touch ./-i
In this case, the * is expanded to match all of the filenames in the directory. Because the file -i is alphabetically listed before any file except those that start with one of the characters !, #, $, %, &, ', ( , ), *, +, or ,, the rm command sees the -i file as a command-line argument. When rm is executed with its -i option, files will not be deleted unless you verify the action. This still isn't perfect, though. If you have a file that starts with a comma (,) in the directory, it will come before the file starting with a dash, and rm will not get the -i argument first.
The -i file also won't save you from errors like this:
% rm [a-z]* .o
If lots of users each make a -i file in each of their zillions of subdirectories, that could waste a lot of disk inodes (Section 14.2). It might be better to make one -i file in your home directory and hard link (Section 15.4) the rest to it, like this:
% cd % touch ./-i % cd somedir % ln ~/-i . ...
Second, to save disk blocks, make sure the -i file is zero-length — use the touch command, not vi or some other command that puts characters in the file.
— BB
To protect themselves from accidentally deleting files, some users create a " trash" directory somewhere and then write a "safe delete" program that, instead of rming a file, moves it into the trash directory. The implementation can be quite complex, but a simple alias or shell function will do most of what you want:
alias del "mv \!* ~/trash/."
Or, for Bourne-type shells:
del ( ) { mv "$@" $HOME/trash/.; }
Of course, now your deleted files collect in your trash directory, so you have to clean that out from time to time. You can do this either by hand or automatically, via a cron (Section 25.2) entry like this:
&& Section 35.14, -r Section 14.16
23 2 * * * cd $HOME/trash && rm -rf *
This deletes everything in the trash directory at 2:23 a.m. daily. To restore a file that you deleted, you have to look through your trash directory by hand and put the file back in the right place. That may not be much more pleasant than poking through your garbage to find the tax return you threw out by mistake, but (hopefully) you don't make lots of mistakes.
There are plenty of problems with this approach. Obviously, if you delete two files with the same name in the same day, you're going to lose one of them. A shell script could (presumably) handle this problem, though you'd have to generate a new name for the deleted file. There are also lots of nasty side effects and "gotchas," particularly if you want an rm -r equivalent, if you want this approach to work on a network of workstations, or if you use it to delete files that are shared by a team of users.
Unfortunately, this is precisely the problem. A "safe delete" that isn't really safe may not be worth the effort. Giving people a safety net with holes in it is only good if you can guarantee in advance that they won't land in one of the holes, believing themselves protected. You can patch some of the holes by replacing this simple alias with a shell script; but you can't fix all of them.
— ML
The -f option to rm is the extreme opposite of -i. It says, "Just delete the file; don't ask me any questions." The "f" stands (allegedly) for "force," but this isn't quite right. rm -f won't force the deletion of something that you aren't allowed to delete. (To understand what you're allowed to delete, you need to understand directory access permissions (Section 50.2).)
What, then, does rm -f do, and why would you want to use it?
Normally, rm asks you for confirmation if you tell it to delete files to which you don't have write access — you'll get a message like Override protection 444 for foo? (The Unix filesystem allows you to delete read-only files, provided you have write access to the directory.) With -f, these files will be deleted silently.
Normally, rm's exit status (Section 35.12) is 0 if it succeeded and 1 if it failed to delete the file. With -f, rm's return status is always 0.
I find that I rarely use rm -f on the Unix command line, but I almost always use it within shell scripts.
You probably also don't want to be interrupted if rm -f tries to delete files that don't exist because the script never created them. Generally, rm -f keeps quiet about files that don't exist; if the desired end result is for the file to be gone, it not existing in the first place is just as good.
— ML
Summary BoxA perennial problem is deleting files that have strange characters (or other oddities) in their names. The next few articles contain some hints for the following:
We'll also give hints for these:
Most tips for deleting files also work for renaming the files (if you want to keep them): just replace the rm command with mv. — ML |
Filenames can be hard to handle if their names include control characters or characters that are special to the shell. Here's a directory with three oddball filenames:
% ls What now a$file prog|.c program.c
When you type those filenames on the command line, the shell interprets the special characters (space, dollar sign, and vertical bar) instead of including them as part of the filename. There are several ways (Section 14.11) to handle this problem. One is with wildcards (Section 33.2). Type a part of the filename without the weird characters, and use a wildcard to match the rest. The shell doesn't scan the filenames for other special characters after it interprets the wildcards, so you're (usually) safe if you can get a wildcard to match. For example, here's how to rename What now to Whatnow, remove a$file, and rename prog|.c to prog.c:
% mv What* Whatnow % rm -i a* rm: remove a$file? y % mv prog?.c prog.c
Filenames with control characters are just another version of the same problem. Use a wildcard to match the part of the name that's troubling you. The real problem with control characters in filenames is that some control characters do weird things to your screen. Once I accidentally got a file with a CTRL-L in its name. Whenever I ran ls, it erased the screen before I could see what the filename was! Section 8.12 explains how, depending on your version of ls, you can use the -q or -b options to spot the offensive file and construct a wildcard expression to rename or delete it. (ls -q is the default on most Unix implementations these days, so you will probably never see this particular problem.)
— JP
Sometimes you can slip and create a file whose name starts with a dash (-), like -output or -f. That's a perfectly legal filename. The problem is that Unix command options usually start with a dash. If you try to type that filename on a command line, the command might think you're trying to type a command option.
In almost every case, all you need to do is "hide" the dash from the command. Start the filename with ./ (dot slash). This doesn't change anything as far as the command is concerned; ./ just means "look in the current directory" (Section 1.16). So here's how to remove the file -f:
% rm ./-f
(Most rm commands have a special option for dealing with filenames that start with a dash, but this trick should work on all Unix commands.)
— JP
Some versions of Unix have a lot of trouble with eight-bit filenames — that is, filenames that contain non-ASCII characters. The ls -q (Section 8.12) command shows the nonASCII characters as question marks (?), but usual tricks like rm -i * (Section 14.12) skip right over the file. You can see exactly what the filename is by using ls -b (Section 8.12):
% ls -q ???? afile bfile % rm -i * afile: ? n bfile: ? n % ls -b \t\360\207\005\254 afile bfile
On older Unixes, the -b option to ls might not be supported, in which case you can use od -c (Section 12.4) to dump the current directory, using its relative pathname . (dot) (Section 1.16), character by character. It's messier, and isn't supported on all Unix platforms, but it's worth a try:
% od -c . ... 00..... \t 360 207 005 254 \0 \0 \0 \0 ...
If you can move all the other files out of the directory, then you'll probably be able to remove the leftover file and directory with rm -rf (Section 14.16, Section 14.10). Moving files and removing the directory is a bad idea, though, if this is an important system directory like /bin. Otherwise, if you use the escaped name ls -b gave you, you might be able to remove it directly by using the system call unlink (2) in Perl. Use the same escape characters in Perl that ls -b displayed. (Or, if you needed to use od -c, find the filename in the od listing of the directory — it will probably end with a series of NUL characters, like \0 \0 \0.)
perl -e 'unlink("\t\360\207\005\254");'
— JP
If wildcards don't work (Section 14.12) to remove a file with a strange name, try getting the file's i-number (Section 13.2). Then use find's -inum operator (Section 9.9) to remove the file.
Here's a directory with a weird filename. ls (with its default -q option (Section 8.12) on most versions) shows that the name has three unusual characters. Running ls -i shows each file's i-number. The strange file has i-number 6239. Give the i-number to find, and the file is gone:
% ls adir afile b???file bfile cfile dfile % ls -i 6253 adir 6239 b???file 6249 cfile 9291 afile 6248 bfile 9245 dfile % find . -inum 6239 -exec rm {} \; % ls adir afile bfile cfile dfile
Instead of deleting the file, I also could have renamed it to newname with the command:
% find . -inum 6239 -exec mv {} newname \;
If the current directory has large subdirectories, you'll probably want to keep find from recursing down into them by using the -maxdepth 1 operator. (finds that don't support -maxdepth can use -prune ( Section 9.25) for speed.)
— JP
What if you want to get rid of a directory? The standard — and safest — way to do this is to use the Unix rmdir "remove directory" utility:
% rmdir files
The rmdir command often confuses new users. It will only remove a directory if it is completely empty; otherwise, you'll get an error message:
% rmdir files rmdir: files: Directory not empty % ls files %
As in the example, ls will often show that the directory is empty. What's going on?
It's common for editors and other programs to create " invisible" files (files with names beginning with a dot). The ls command normally doesn't list them; if you want to see them, you have to use ls -A (Section 8.9):[1]
% rmdir files rmdir: files: Directory not empty % ls -A files .BAK.textfile2
Here, we see that the directory wasn't empty after all: there's a backup file that was left behind by some editor. You may have used rm * to clean the directory out, but that won't work: rm also ignores files beginning with dots, unless you explicitly tell it to delete them. We really need a wildcard pattern like .??* or .[a-zA-Z0-9]* to catch normal dotfiles without catching the directories . and ..:
% rmdir files rmdir: files: Directory not empty % ls -A files .BAK.textfile2 % rm files/.??* % rmdir files %
Other pitfalls might be files whose names consist of nonprinting characters or blank spaces — sometimes these get created by accident or by malice (yes, some people think this is funny). Such files will usually give you "suspicious" ls output (Section 8.11) (like a blank line).
If you don't want to worry about all these special cases, just use rm -r:
% rm -r files
This command removes the directory and everything that's in it, including other directories. A lot of people warn you about it; it's dangerous because it's easy to delete more than you realize. Personally, I use it all the time, and I've never made a mistake. I never bother with rmdir.
— ML
Sooner or later, a lot of junk collects in your directories: files that you don't really care about and never use. It's possible to write find (Section 9.1) commands that will automatically clean these up. If you want to clean up regularly, you can add some find commands to your crontab file (Section 25.2).
Basically, all you need to do is write a find command that locates files based on their last access time (-atime (Section 9.5)) and use -ok or -exec (Section 9.9) to delete them. Such a command might look like this:
% find . -atime +60 -ok rm -f {} \;
This locates files that haven't been accessed in the last 60 days, asks if you want to delete the file, and then deletes the file. (If you run it from cron, make sure you use -exec instead of -ok, and make absolutely sure that the find won't delete files that you think are important.)
Of course, you can modify this find command to exclude (or select) files with particular names; for example, the following command deletes old core dumps and GNU Emacs backup files (whose names end in ~), but leaves all others alone:
% find . \( -name core -o -name "*~" \) -atime +60 -ok rm -f {} \;
If you take an automated approach to deleting stale files, watch out for these things:
There are plenty of files (for example, Unix utilities and log files) that should never be removed. Never run any "automatic deletion" script on /usr or / or any other "system" directory.
On some systems, executing a binary executable doesn't update the last access time. Since there's no reason to read these files, you can expect them to get pretty stale, even if they're used often. But you don't want to delete them. If you cook up a complicated enough find command, you should be able to handle this automatically. Something like this should (at least partially) do the trick:
! Section 9.6, -perm Section 9.15
% find . -atime +30 ! -perm -111 ... -exec rm {} \;
Along the same lines, you'd probably never want to delete C source code, so you might modify your find command to look like this:
% find . -atime +30 ! -perm -111 ! -name "*.c" ... -exec rm {} \;
I personally find that automatically deleting files is an extreme and bizarre solution. I can't imagine deleting files without knowing exactly what I've deleted or without (somehow) saving the "trash" somewhere just in case I accidentally removed something important. To archive the deleted files on tape, you can use the find -cpio operator if your system has it. Otherwise, try a little shell script with GNU tar; the following script writes the list of files to a temporary file and then, if that succeeds, reads the list of files, writes them to tape, and removes the files if the tape write succeeds:
umask 077 files=/tmp/CLEANUP$$
if Section 35.13, && Section 35.14
if find ... -print > $files
then tar -c -T $files --remove && rm $files else echo "cleanup aborted because find returned nonzero status" fi
Okay, I've said that I don't really think that automated deletion scripts are a good idea. However, I don't have a good comprehensive solution. I spend a reasonable amount of time (maybe an hour a month) going through directories and deleting stale files by hand. I also have a clean alias that I type whenever I think about it. It looks like this:
alias clean "rm *~ junk *.BAK core #*"
That is, this alias deletes all of my Emacs (Section 19.1) backup files, Emacs autosave files (risky, I know), files named junk, some other backup files, and core dumps. I'll admit that since I never want to save these files, I could probably live with something like this:
% find ~ \( -name "*~" -o -name core \) -atime +1 -exec rm {} \;
But stil, automated deletion commands make me really nervous, and I'd prefer to live without them.
— ML
One problem with Unix: it's not terribly good at "excluding" things. There's no option to rm that says, "Do what you will with everything else, but please don't delete these files." You can sometimes create a wildcard expression (Section 33.2) that does what you want — but sometimes that's a lot of work, or maybe even impossible.
Here's one place where Unix's command substitution ( Section 28.14) operators (backquotes) come to the rescue. You can use ls to list all the files, pipe the output into a grep -v or egrep -v (Section 13.3) command, and then use backquotes to give the resulting list to rm. Here's what this command would look like:
% rm -i `ls -d *.txt | grep -v '^john\.txt$'`
This command deletes all files whose names end in .txt, except for john.txt. I've probably been more careful than necessary about making sure there aren't any extraneous matches; in most cases, grep -v john would probably suffice. Using ls -d (Section 8.5) makes sure that ls doesn't look into any subdirectories and give you those filenames. The rm -i asks you before removing each file; if you're sure of yourself, omit the -i.
Of course, if you want to exclude two files, you can do that with egrep:
% rm `ls -d *.txt | egrep -v 'john|mary'`
(Don't forget to quote the vertical bar (|), as shown earlier, to prevent the shell from piping egrep's output to mary.)
Another solution is the nom (Section 33.8) script.
— ML
Do you run find on your machine every night? Do you know what it has to go through just to find out if a file is three days old and smaller than ten blocks or owned by "fred" or setuid root? This is why I tried to combine all the things we need done for removal of files into one big find script:
Go to http://examples.oreilly.com/upt3 for more information on: cleanup
2>&1 Section 36.16
#! /bin/sh # # cleanup - find files that should be removed and clean them # out of the file system. find / \( \( -name '#*' -atime +1 \) \ -o \( -name ',*' -atime +1 \) \ -o \( -name rogue.sav -atime +7 \) \ -o \( \( -name '*.bak' \ -o -name '*.dvi' \ -o -name '*.CKP' \ -o -name '.*.bak' \ -o -name '.*.CKP' \) -atime +3 \) \ -o \( -name '.emacs_[0-9]*' -atime +7 \) \ -o \( -name core \) \ -o \( -user guest -atime +9 \) \ \) -print -exec rm -f {} \; > /tmp/.cleanup 2>&1
This is an example of using a single find command to search for files with different names and last-access times (see Section 9.5). Doing it all with one find is much faster — and less work for the disk — than running a lot of separate finds. The parentheses group each part of the expression. The neat indentation makes this big thing easier to read. The -print -exec at the end removes each file and also writes the filenames to standard output, where they're collected into a file named /tmp/.cleanup — people can read it to see what files were removed. You should probably be aware that printing the names to /tmp/.cleanup lets everyone see pathnames, such as /home/joe/personal/resume.bak, which some people might consider sensitive. Another thing to be aware of is that this find command starts at the root directory; you can do the same thing for your own directories.
—CT and JP
[1] If your version of ls doesn't have the -A option, use -a instead. You'll see the two special directory entries . and .. (Section 8.9), which you can ignore.
| CONTENTS |


PSL declare historic R1 billion in revenue
Cape Town - For the first time in the history of South African football the Premier Soccer League (PSL) on Thursday declared a record R1 billion in revenue for the 2018/2019 financial year.
At its annual general meeting (AGM) in Kempton Park, PSL chairperson Irvin Khoza confirmed that the PSL's revenue had surpassed the R1 billion mark.
Most of the organisation's funds are generated from its seven official sponsors and broadcast partners: SuperSport, Absa, Nedbank, Telkom, MTN, MultiChoice and GladAfrica.
GladAfrica recently agreed a five-year deal to sponsor SA football's second tier - the now-called GladAfrica Championship that has lifted the final figures above R1 billion.
The PSL announced revenues increased by 7% to a record R1, 005 billion, an improvement on last year's R938 million and the R884 million declared for the 2016/2017 financial year.
The increase in revenue is driven by the contractual increase in the broadcast rights agreement and inflationary increase of sponsorship revenue.
Khoza said: "The PSL cannot be bystanders while the country is going through some difficult times. Today, I appealed to my members to think on how we can all play our role and make a contribution.
"The recession in our country has unfortunately deepened and our economy seems destined for a new normal. In over two decades, two generations of South African citizens that do not have skin in the economic game have emerged.
"External marketing budgets are the first to be cut in recession. Sponsorship renewals are therefore going to be under pressure. It is under these times that the indispensability of our value proposition to that of our sponsors needs to be understood and appreciated.
"Our content appeal and following by the NSL audience is the indispensable link that the sponsors and advertisers are after in their association with our brands."
The PSL also invited Bundesliga International CEO, Robert Klein to present to the 32 members on a possible partnership between Bundesliga and PSL.
Compiled by Baden Gillion


Three UAE cinemas perfect for taking kids
Enjoy a family movie with all the gang
NoVO kidz
NOVO Cinemas
If kids want their movie served up with a warm hug then the colourful furry ‘friendly monster’ seats at the recently-launched NOVO Kidz cinema in Festival City will make their popcorn taste even sweeter – or saltier if that’s their thing.
Dubai Festival City Mall, Dubai, www.novocinemas.com (04 232 8328).
REEL JUNIOR
Reel Cinemas
Mini movie-goers can watch films in comfort on squishy beanbag seats in this cinema. Plus, the kiddie combo meals will keep little tummies satisfied from start to finish – so it’s just toilet breaks you’ll have to contend with.
The Springs Souk, The Dubai Mall and Al Ghurair Centre, www.reelcinemas.ae.
KIDS
VOX Cinemas
Because little ones can’t sit still for long, there’s Kids at VOX Cinemas where they will be glued to their luxurious primary coloured cinema seat throughout whatever family blockbuster is showing.
Various locations in Dubai and Abu Dhabi including Mercato and Yas Mall, ww.uae.voxcinemas.com.
Be the first to get all the latest Dubai news, reviews and deals into your inbox by signing up to our free newsletter, click here to sign up.


{% extends 'base.html' %} {% load static %} {% block head %}{% endblock %} {% block content %}
Build, run, revisit, revise. Encounter's are tools for DM's to use to create a better player experience.
Build a new encounter for an upcoming session, or build one in real-time for your player's current session.
BuildView all of your encounters to begin running, maintaining, or cateloging all encounters that you own or participate in.
ViewConnect to an encounter started by your dungeon master to participate and interract.
Connect


Poster Title
Duplicate this URL to create as much experimental posters as you like at the same time!


Humble Store Sale Offers Big RDR2 & Outer Worlds Discounts
by Mike SandersThe Humble Store (known for it’s ‘Humble Bundle‘ packages) is an amazing place where you can buy PC video games with proceeds going towards various charitable causes. Put simply, everyone wins!
Presuming your wallet has not been too depleted by the Black Friday sales (of which you can check some of our highlighted deals in the link here) then maybe you can afford to grab some gaming bargains as the Humble Store has officially launched its ‘Fall Sale’.
Humble Store Launches its Fall Sale
One of the main highlights of the sale is that both Red Dead Redemption 2 and The Outer Worlds have received some nice discounts. Actually, I believe that this may be the first time that either game has been offered at a cut-down rate.
What are some of the highlights of the sale though? Well, let’s give you a little taste!
- Red Dead Redemption 2 – £43.99
- The Outer Worlds – £37.49
- Borderlands 3 – £33.49
- Planet Coaster – £8.99
- Grand Theft Auto V – £12.49
- FLT Advanced Edition – £1.79
- Frostpunk – £11.24
Where Can I Check the Sale Out?
Presuming that this has whet your appetite to check out more of their gaming bargains, you can visit their official sale website via the link here!
Remember, you’re not just getting some cheap games, but you’re also doing your bit for charity. As such, you fully have our permission to splurge out on as many titles as you like!
What do you think? Which game is your pick of the sale? – Let us know in the comments!


tmp_2c78d90
and
tmp_2c78d90
DIAG Sets 5 & 6 - Horizontal contour/vector plots of DJF, JJA and ANN means
Surface Variables
DJF
JJA
ANN
ALBSURF
Albedo at surface
plot
plot
plot
PBLH
Planetary boundary layer height
plot
plot
plot
PS
Surface pressure
plot
plot
plot
PSL *
Sea level pressure
plot
plot
plot
TREFHT *
2-meter air temperature
plot
plot
plot
TS *
Surface temperature
plot
plot
plot
SST
Sea Surface temperature
plot
plot
plot
Vector Variables
DJF
JJA
ANN
SURF STRESS *
Surface wind stress (ocean)
plot
plot
plot
SURF STRESS TROP
Tropical surface wind stress (ocean)
plot
plot
plot
SURF WIND
Near surface wind
plot
plot
plot
Constant Pressure Levels
DJF
JJA
ANN
CHI 200 *
200 mb velocity potential
plot
plot
plot
EKE 850 *
850 mb transient eddy kinetic energy
plot
plot
plot
PSI 200 *
200 mb stream function
plot
plot
plot
TTRP
Tropopause temperature
plot
plot
plot
T 850 *
850 mb temperature
plot
plot
plot
T 200
200 mb temperature
plot
plot
plot
U 200 *
200 mb zonal wind
plot
plot
plot
VT 850 *
850 mb meridional heat transport
plot
plot
plot
Z 500
500 mb geopotential height
plot
plot
plot
Z 300 *
300 mb geopotential height
plot
plot
plot
Hydrologic Cycle
DJF
JJA
ANN
EP *
Evaporation - precipitation
plot
plot
plot
PRECIP
Cumulative precipitation
plot
plot
plot
PRECT *
Precipitation rate
plot
plot
plot
PRECT TROP
Tropical precipitation rate
plot
plot
plot
PREH2O *
Total precipitable water
plot
plot
plot
PREH2O TROP
Tropical total precipitable water
plot
plot
plot
QFLX
Surface water flux
plot
plot
plot
Surface Energy Fluxes
DJF
JJA
ANN
FLDS
Longwave downwelling flux
plot
plot
plot
FLDSC
Clearsky longwave downwelling flux
plot
plot
plot
FLNS *
Net longwave flux
plot
plot
plot
FLNSC
Clearsky net longwave flux
plot
plot
plot
FSDS *
Shortwave downwelling flux
plot
plot
plot
FSNS *
Net shortwave flux
plot
plot
plot
FSNS TROP
Tropical net shortwave flux
plot
plot
plot
FSNSC
Clearsky net shortwave flux
plot
plot
plot
LHFLX *
Latent heat flux
plot
plot
plot
RESSURF *
Residual energy flux
plot
plot
plot
RESSURF TROP
Tropical residual energy flux
plot
plot
plot
SHFLX *
Sensible heat flux
plot
plot
plot
Top of Model Energy Fluxes
DJF
JJA
ANN
ALBEDO
TOA albedo
plot
plot
plot
ALBEDOC
TOA clearsky albedo
plot
plot
plot
FLNT *
Net longwave flux
plot
plot
plot
FLNTC
Clearsky net longwave flux
plot
plot
plot
FSNT *
Net shortwave flux
plot
plot
plot
FSNTC
Clearsky net shortwave flux
plot
plot
plot
LWCF *
Longwave cloud forcing
plot
plot
plot
SOLIN
Incoming solar radiation
plot
plot
plot
SWCF *
Shortwave cloud forcing
plot
plot
plot
SWCF TROP
Tropical shortwave cloud forcing
plot
plot
plot
Cloud Variables
DJF
JJA
ANN
CLDHGH
High-level cloud amount
plot
plot
plot
CLDLOW
Low-level cloud amount
plot
plot
plot
CLDMED
Mid-level cloud amount
plot
plot
plot
CLDTOT *
Total cloud amount
plot
plot
plot
TGCLDIWP
Total grid-box cloud ice water path
plot
plot
plot
TGCLDLWP
Total grid-box cloud liquid water path
plot
plot
plot
TGCLDLWP TROP
Tropical Total grid-box cloud LWP
plot
plot
plot
TICLDIWP
Integrated in-cloud ice WP
plot
plot
plot
TICLDLIQWP
Integrated in-cloud liquid WP
plot
plot
plot
TICLDTWP
Integrated in-cloud ice+liquid WP
plot
plot
plot
ISCCP Cloud Simulator
DJF
JJA
ANN
MEANPTOP
Mean Cloud Top Pressure
plot
plot
plot
MEANTTOP
Mean Cloud Top Temperature
plot
plot
plot
MEANTAU
Mean Cloud Optical Thickness
plot
plot
plot
TCLDAREA
Total cloud area
plot
plot
plot
Cloud Microphysics Variables
DJF
JJA
ANN
SIWC
Grid-box Average Snow + Ice Water Content
plot
plot
plot
CDNUMC
Vertically-Integrated Cloud Droplet Concentration
plot
plot
plot
Aerosols
DJF
JJA
ANN
AODVIS
Aerosol Optical Depth
plot
plot
plot
AODDUST
Dust Optical Depth
plot
plot
plot
CFMIP Observation Simulator Package (COSP) Primary Diagnostics
CALIPSO GOCCP 2007-2010
DJF
JJA
ANN
CLDTOT_CAL
Total cloud amount
plot
plot
plot
CLDLOW_CAL
Low-level cloud amount
plot
plot
plot
CLDMED_CAL
Mid-level cloud amount
plot
plot
plot
CLDHGH_CAL
High-level cloud amount
plot
plot
plot
ISCCP-COSP From D1 Daytime Jul1983-Sep2008
DJF
JJA
ANN
CLDTOT_ISCCPCOSP
Total cloud amount (tau > 0.3)
plot
plot
plot
CLDTHICK_ISCCPCOSP
Optically thick cloud amount (tau > 23.0)
plot
plot
plot
MISR L3 CTH-OD V5 Mar2000-Nov2009
DJF
JJA
ANN
CLDTOT_MISR
Total cloud amount (tau > 0.3)
plot
plot
plot
CLDTHICK_MISR
Optically thick cloud amount (tau > 23.0)
plot
plot
plot
MODIS-COSP 2003-2010
DJF
JJA
ANN
CLDTOT_MODIS
Total cloud amount (tau > 0.3)
plot
plot
plot
CLDTHICK_MODIS
Optically thick cloud amount (tau > 23.0)
plot
plot
plot
Additional COSP Diagnostics
CALIPSO GOCCP 2007-2010
DJF
JJA
ANN
CLDTOT_CAL
Total cloud amount
plot
plot
plot
CLDLOW_CAL
Low-level cloud amount
plot
plot
plot
CLDMED_CAL
Mid-level cloud amount
plot
plot
plot
CLDHGH_CAL
High-level cloud amount
plot
plot
plot
CLOUDSAT-COSP From Level 2 GEOPROF Jun2006-Nov2010
DJF
JJA
ANN
CLDTOT_CS2
Total cloud amount
plot
plot
plot
ISCCP-COSP From D1 Daytime Jul1983-Sep2008
DJF
JJA
ANN
CLDTOT_ISCCPCOSP
Total cloud amount (tau > 0.3)
plot
plot
plot
CLDLOW_ISCCPCOSP
Low-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDMED_ISCCPCOSP
Mid-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDHGH_ISCCPCOSP
High-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDTHICK_ISCCPCOSP
Optically thick cloud amount (tau > 23.0)
plot
plot
plot
MEANPTOP_ISCCPCOSP
Mean cloud top pressure
plot
plot
plot
MEANCLDALB_ISCCPCOSP
Mean cloud albedo
plot
plot
plot
MISR L3 CTH-OD V5 Mar2000-Nov2009
DJF
JJA
ANN
CLDTOT_MISR
Total cloud amount (tau > 0.3)
plot
plot
plot
CLDLOW_MISR
Low-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDMED_MISR
Mid-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDHGH_MISR
High-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDTHICK_MISR
Optically thick cloud amount (tau > 23.0)
plot
plot
plot
MODIS-COSP 2003-2010
DJF
JJA
ANN
CLDTOT_MODIS
Total cloud amount (tau > 0.3)
plot
plot
plot
CLDLOW_MODIS
Low-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDMED_MODIS
Mid-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDHGH_MODIS
High-topped cloud amount (tau > 0.3)
plot
plot
plot
CLDTHICK_MODIS
Optically thick cloud amount (tau > 23.0)
plot
plot
plot
CLIMODIS
Total ice cloud amount
plot
plot
plot
CLWMODIS
Total liquid cloud amount
plot
plot
plot
IWPMODIS
Mean ice water path
plot
plot
plot
LWPMODIS
Mean liquid water path
plot
plot
plot
PCTMODIS
Mean cloud top pressure
plot
plot
plot
REFFCLIMODIS
Mean effective radius (ice clouds)
plot
plot
plot
REFFCLWMODIS
Mean effective radius (liquid clouds)
plot
plot
plot
TAUILOGMODIS
Log-weighted mean optical thickness (ice clouds)
plot
plot
plot
TAUWLOGMODIS
Log-weighted mean optical thickness (liquid clouds)
plot
plot
plot
TAUTLOGMODIS
Log-weighted mean optical thickness (all clouds)
plot
plot
plot
TAUIMODIS
Mean optical thickness (ice clouds)
plot
plot
plot
TAUWMODIS
Mean optical thickness (liquid clouds)
plot
plot
plot
TAUTMODIS
Mean optical thickness (all clouds)
plot
plot
plot
*WGNE diagnostic variable


epidemic infection network []. data contact model transmission viral time within-host EBOV Ebola infected number vaccination virus population {border-style dynamics px;} #ffffff;} disease infectious load size assumed used using estimates simulations distribution epidemics models showed based coverage immune nodes simulation [], contacts intervention level outbreak parameters rate thousand Fig. Health large results threshold (Fig. World antibody final higher individual patterns period potential responses Figure Sierra Simulations available day defined i.e., outcomes pathogen px; similar subjects susceptibility {font-family age cases different experimental font-size high index pattern population-level processes programs reduced reproduction strategies vaccine week Based NHPs Note Organization. Public approach assumptions control course data, data. death double; end file highest human influenza matrix modelling random replication response studies EBOV’s Epidemic Table Virus approximately article border-color border-width calculated case case-fatality case. complex conducted dose estimate extracted implementation months networks obtained onset parameter parameters. population. program provide reduce reproductive secondary shows solid; study supplementary symptom {font-style {font-weight "Availability (AUC) (Additional .–. AUC Availability Disease Estimates Infection Interface./rsif.. Leone Simulated Soc Time able age-group age-specific approaches assessments assigned basic bold challenges chosen compared courier; currently curve define detailed detectable determining differences diseases diseases, dynamic em; empirical epidemics. example express generated given hosts igraph implementations incubation individuals information low manuscript. materials�? mixing modeling network. observed package physical previous previously primates pt;} realistic required simulation, single stochastic tested timing total transmission, varied zero


{%- extends 'base.html' -%} {%- block content -%}
This page lists all of the models we have available, arranged by body parts. If you wish to narrow down the list of models based on model attributes, please have a look at our browse by attribute page.
If you're wondering why we have the collection of models we have, see our model diversity statement for more details.
{% for section in order %} {{ list_models(sections[section].models, sections[section].name) }} {% endfor %}{{ name }}
| {{ model.display_code }} - {{ model.pose }}, {% if model.arrangement == "natural" %} naturally arranged {% else %} {{ model.arrangement }} {% endif %} | {% if model.history_list %} {{ tag }} {% endfor %} {% for i in model.info_list %} {{ i }} {% endfor %} | {% endif %} {% for tag in model.tags_list %}


Overview
This add-on runs a FPGA bitfile
without needing to implement the normal VeriStand FPGA template. It allows
the transfer of basic scalar data types inline
with VeriStand's primary control loop (PCL). It also adds
support for reading/writing waveforms with FPGA DMA channels.
Repo
Location
NIVeriStandAdd-Ons/FPGA-Custom-Device · GitHub
Requirements
These drivers must be installed on the
deployment computer/target to function.
FPGA
Specifics
To use the addon, first create an FPGA
program. Use the provided FPGA IP (discussed below) or custom logic. Put items
of interest to front panel controls and indicators. Put waveforms of interest
to DMA channels. The only requirement to the FPGA code is an IRQ (address
of 30) to control when the FPGA bitfile starts. This
IRQ only needs to control when any DMA starts. Any other code can start
whenever it makes sense. Below is an example showing DMA, controls, and
indicators.
Supported Datatypes
Only certain datatypes are supported for DMA,
controls, and indicators. If a data type is not listed, it will not show up in
the addon.
Scalar data types (control and indicators)
Note: Enums are not supported. Convert
them to a U8, U16, or U32 control or indicator. Clusters are not supported.
Even if the clusters are made up of supported types. Items can be grouped
by naming them on the FPGA with a <GroupName>.<SignalName> format. Support for grouping can only
be set on the initialization screen.
DMA data types
The unsigned integer data types can be
converted into a bitpacked Boolean array. This is
discussed in detail below.
NOTE: The embedded UI on Linux targets must be
disabled or error -307556 will be returned.
Speciality IP
The addon comes with special IP for doing the
following:
This IP is located at:
C:\Users\Public\Documents\National
Instruments\NI VeriStand <Year>\Custom Devices\FPGA Addon\FPGA IP
FPGA Example Programs
Examples of how to use the speciality
IP, controls/indicators, and DMA are included in the source code in the Testing
Folder. Here is an example of the speciality IP:
Addon
Specifics
Addon Configuration
Upon
adding the addon, a configuration GUI will open.
Notice the option to group scalars. This will
combine FPGA controls or indicators named with the <GroupName>.<SignalName> format into a group of channels. This
is an option that is set upon initialization and cannot be changed after.
A previously exported addon configuration
can be imported.
On the
main page, set the path to the desired bitfile. Select the RIO device. The search
button (magnifier glass icon) will detect the available FPGAs on the current
Target/Controller.
Notice the built in help. This help provides
the details needed to use each section.
When the bitfile is
selected, the available DMA and scalar registers are discovered. To add these
scalars and DMA to the configuration, go to the Scalars and Waveforms sections
respectively.
Select the items and hit Add Selected. If an
item doesn't show up, it is likely not a supported data type or the bitfile has not been re-compiled after changes.
Any scalar integer values can be
converted to support Boolean bitpacking. However,
this is simething that must be first programmed
in the FPGA. It is also something that is not "discoverable" by the
addon. Therefore the user must configure the addon manually to match what is
programmed in the FPGA.
As an example, the FPGA program
could take 8 Boolean lines, build an array, and convert it
to a number as follows.
This significantly improves performance.
If this is implement in the FPGA, manually find the
relating indicator in the VeriStand configuraiton and
select to enable bitpacking.
Once the channel is converted to a bitpacking section, enter in the number of channels being bitpacked. Then hit apply.
This will add 8 Boolean channels to the
configuration. The user can then name the channels anything. Array index
order will be maintained regardless of naming. The top most channel is always
index 0 while the bottom most channel is always the last index (7 in this
case).
When speciality IP
is added, channels will be grouped together. Here is an example of an analog
PWM IP core.
Notice the result (or measurment)
in Inputs and the relating settings in Outputs.
Adding DMA and waveforms works in a very
similar way. Go to the Waveform Inputs or Waveform Outputs section and add
any desired DMA.
The DMA is automatically
"discoverable"' but the FPGA programming leading up to the DMA is
not. Therefore, the user must manually tell the addon how the DMA is being used
in the FPGA program. Take this FPGA loop as an example:
The DMA "Medium" has 16 channels
written per loop iteration. Each loop iteration takes 10 microseconds. The
writing is continuous. This data is interleaved. So, in the
addon DMA configuration section, define the number of channels, mode,
scheme, and expected sample period (acquisition rate). Hit apply.
Import DMA channel names for faster
setup. There is an example of the expected CSV file included with the addon.
For a DMA channel, continuous or finite
acquisitions are supported.
Again, this setting should match what was
programmed on the FPGA. If the FPGA was programmed as a continuous generation
(FPGA to Host), setting a Triggered Finite mode would cause overflows.
As with scalars, certain data types
support bitpacking. With interleaved data, multiple
channels are sampled at the same time (see "Medium" DMA example
above) and transfered one right after another within
a single loop iteration. Each channel is a data packet in the DMA. If there are
8 channels, a single acquisition/loop iteration would have 8 data packets. In
the case of bitpacked, each data packet
is a complete acquisition for a group of Boolean channels. The maximum number
of channels is set by the data type. Below is an example of an FPGA
program bitpacketing a DMA.
Notice how there is no For Loop per
single loop iteration. Notice how a single packet represents multiple
channels. In this case, select Bitpacked
from the Delacing Scheme.
NOTE: The embedded UI on Linux targets must be
disabled or error -307556 will be returned.
Addon Execution
Deploy the system definition. From within the
user interface, drag and drop channels or groups of channels.
Change required channels to controls,
such as Trigger and anything in Settings.
Certain channels can be added as Rings to show
text. The Error Code channel supports this.
To veiw
waveforms, open the Workspace.
Add a waveform plot and configure.
System Definition API
There is also a system definition API that
allows the user to programatically create an instance
of the addon from a previously exported configuration. This is
installed at:
C:\Users\Public\Documents\National
Instruments\NI VeriStand <Year>\Custom
Devices\FPGA Addon\Windows\System Definition API
An example of using this API is as follows:


The data format of Macintosh resource forks, used on Classic Mac OS and Mac OS X/macOS to store additional structured data along with a file's main data (the data fork). The kinds of data stored in resource forks include:
Macintosh file systems (MFS, HFS, HFS+, APFS) support resource forks natively, which allows storing resources along with any file. Non-Macintosh file systems and protocols have little or no support for resource forks, so the resource fork data must be stored in some other way when using such file systems or protocols. Various file formats and tools exist for this purpose, such as BinHex, MacBinary, AppleSingle, AppleDouble, or QuickTime RezWack. In some cases, resource forks are stored as plain data in separate files with a .rsrc extension, even on Mac systems that natively support resource forks.
On modern Mac OS X/macOS systems, resource forks are used far less commonly than on classic Mac OS systems, because of compatibility issues with other systems and historical limitations in the format. Modern macOS APIs and libraries do not use resource forks, and the legacy Carbon API that still used them has been deprecated since OS X 10.8. Despite this, even current macOS systems still use resource forks for certain purposes, such as custom file icons.
This page hosts a formal specification of Macintosh resource fork data using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
-- This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
--
-- This file is compatible with Lua 5.3
local class = require("class")
require("kaitaistruct")
local stringstream = require("string_stream")
require("bytes_with_io")
--
-- The data format of Macintosh resource forks,
-- used on Classic Mac OS and Mac OS X/macOS to store additional structured data along with a file's main data (the data fork).
-- The kinds of data stored in resource forks include:
--
-- * Document resources:
-- images, sounds, etc. used by a document
-- * Application resources:
-- graphics, GUI layouts, localizable strings,
-- and even code used by an application, a library, or system files
-- * Common metadata:
-- custom icons and version metadata that could be displayed by the Finder
-- * Application-specific metadata:
-- because resource forks follow a common format,
-- other applications can store new metadata in them,
-- even if the original application does not recognize or understand it
--
-- Macintosh file systems (MFS, HFS, HFS+, APFS) support resource forks natively,
-- which allows storing resources along with any file.
-- Non-Macintosh file systems and protocols have little or no support for resource forks,
-- so the resource fork data must be stored in some other way when using such file systems or protocols.
-- Various file formats and tools exist for this purpose,
-- such as BinHex, MacBinary, AppleSingle, AppleDouble, or QuickTime RezWack.
-- In some cases,
-- resource forks are stored as plain data in separate files with a .rsrc extension,
-- even on Mac systems that natively support resource forks.
--
-- On modern Mac OS X/macOS systems,
-- resource forks are used far less commonly than on classic Mac OS systems,
-- because of compatibility issues with other systems and historical limitations in the format.
-- Modern macOS APIs and libraries do not use resource forks,
-- and the legacy Carbon API that still used them has been deprecated since OS X 10.8.
-- Despite this,
-- even current macOS systems still use resource forks for certain purposes,
-- such as custom file icons.
-- See also: Inside Macintosh, More Macintosh Toolbox, Resource Manager, Resource Manager Reference, Resource File Format (https://developer.apple.com/library/archive/documentation/mac/pdf/MoreMacintoshToolbox.pdf#page=151)
-- See also: Inside Macintosh, Volume I, The Resource Manager, Format of a Resource File (https://www.pagetable.com/?p=50)
-- See also: Source (https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format)
-- See also: Source (https://github.com/dgelessus/mac_file_format_docs/blob/master/README.md#resource-forks)
ResourceFork = class.class(KaitaiStruct)
function ResourceFork:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork:_read()
self.header = ResourceFork.FileHeader(self._io, self, self._root)
self.system_data = self._io:read_bytes(112)
self.application_data = self._io:read_bytes(128)
end
--
-- Use `data_blocks` instead,
-- unless you need access to this instance's `_io`.
ResourceFork.property.data_blocks_with_io = {}
function ResourceFork.property.data_blocks_with_io:get()
if self._m_data_blocks_with_io ~= nil then
return self._m_data_blocks_with_io
end
local _pos = self._io:pos()
self._io:seek(self.header.ofs_data_blocks)
self._raw__m_data_blocks_with_io = self._io:read_bytes(self.header.len_data_blocks)
local _io = KaitaiStream(stringstream(self._raw__m_data_blocks_with_io))
self._m_data_blocks_with_io = BytesWithIo(_io)
self._io:seek(_pos)
return self._m_data_blocks_with_io
end
--
-- Storage area for the data blocks of all resources.
--
-- These data blocks are not required to appear in any particular order,
-- and there may be unused space between and around them.
--
-- In practice,
-- the data blocks in newly created resource files are usually contiguous.
-- When existing resources are shortened,
-- the Mac OS resource manager leaves unused space where the now removed resource data was,
-- as this is quicker than moving the following resource data into the newly freed space.
-- Such unused space may be cleaned up later when the resource manager "compacts" the resource file,
-- which happens when resources are removed entirely,
-- or when resources are added or grown so that more space is needed in the data area.
ResourceFork.property.data_blocks = {}
function ResourceFork.property.data_blocks:get()
if self._m_data_blocks ~= nil then
return self._m_data_blocks
end
self._m_data_blocks = self.data_blocks_with_io.data
return self._m_data_blocks
end
--
-- The resource file's resource map.
ResourceFork.property.resource_map = {}
function ResourceFork.property.resource_map:get()
if self._m_resource_map ~= nil then
return self._m_resource_map
end
local _pos = self._io:pos()
self._io:seek(self.header.ofs_resource_map)
self._raw__m_resource_map = self._io:read_bytes(self.header.len_resource_map)
local _io = KaitaiStream(stringstream(self._raw__m_resource_map))
self._m_resource_map = ResourceFork.ResourceMap(_io, self, self._root)
self._io:seek(_pos)
return self._m_resource_map
end
--
-- The resource file's header information.
--
-- System-reserved data area.
-- This field can generally be ignored when reading and writing.
--
-- This field is used by the Classic Mac OS Finder as temporary storage space.
-- It usually contains parts of the file metadata (name, type/creator code, etc.).
-- Any existing data in this field is ignored and overwritten.
--
-- In resource files written by Mac OS X,
-- this field is set to all zero bytes.
--
-- Application-specific data area.
-- This field can generally be ignored when reading and writing.
--
-- According to early revisions of Inside Macintosh,
-- this field is "available for application data".
-- In practice, it is almost never used for this purpose,
-- and usually contains only junk data.
--
-- In resource files written by Mac OS X,
-- this field is set to all zero bytes.
--
-- Resource file header,
-- containing the offsets and lengths of the resource data area and resource map.
ResourceFork.FileHeader = class.class(KaitaiStruct)
function ResourceFork.FileHeader:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.FileHeader:_read()
self.ofs_data_blocks = self._io:read_u4be()
self.ofs_resource_map = self._io:read_u4be()
self.len_data_blocks = self._io:read_u4be()
self.len_resource_map = self._io:read_u4be()
end
--
-- Offset of the resource data area,
-- from the start of the resource file.
--
-- In practice,
-- this should always be `256`,
-- i. e. the resource data area should directly follow the application-specific data area.
--
-- Offset of the resource map,
-- from the start of the resource file.
--
-- In practice,
-- this should always be `ofs_data_blocks + len_data_blocks`,
-- i. e. the resource map should directly follow the resource data area.
--
-- Length of the resource data area.
--
-- Length of the resource map.
--
-- In practice,
-- this should always be `_root._io.size - ofs_resource_map`,
-- i. e. the resource map should extend to the end of the resource file.
--
-- A resource data block,
-- as stored in the resource data area.
--
-- Each data block stores the data contained in a resource,
-- along with its length.
ResourceFork.DataBlock = class.class(KaitaiStruct)
function ResourceFork.DataBlock:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.DataBlock:_read()
self.len_data = self._io:read_u4be()
self.data = self._io:read_bytes(self.len_data)
end
--
-- The length of the resource data stored in this block.
--
-- The data stored in this block.
--
-- Resource map,
-- containing information about the resources in the file and where they are located in the data area.
ResourceFork.ResourceMap = class.class(KaitaiStruct)
function ResourceFork.ResourceMap:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.ResourceMap:_read()
self.reserved_file_header_copy = ResourceFork.FileHeader(self._io, self, self._root)
self.reserved_next_resource_map_handle = self._io:read_u4be()
self.reserved_file_reference_number = self._io:read_u2be()
self._raw_file_attributes = self._io:read_bytes(2)
local _io = KaitaiStream(stringstream(self._raw_file_attributes))
self.file_attributes = ResourceFork.ResourceMap.FileAttributes(_io, self, self._root)
self.ofs_type_list = self._io:read_u2be()
self.ofs_names = self._io:read_u2be()
end
--
-- The resource map's resource type list, followed by the resource reference list area.
ResourceFork.ResourceMap.property.type_list_and_reference_lists = {}
function ResourceFork.ResourceMap.property.type_list_and_reference_lists:get()
if self._m_type_list_and_reference_lists ~= nil then
return self._m_type_list_and_reference_lists
end
local _pos = self._io:pos()
self._io:seek(self.ofs_type_list)
self._raw__m_type_list_and_reference_lists = self._io:read_bytes((self.ofs_names - self.ofs_type_list))
local _io = KaitaiStream(stringstream(self._raw__m_type_list_and_reference_lists))
self._m_type_list_and_reference_lists = ResourceFork.ResourceMap.TypeListAndReferenceLists(_io, self, self._root)
self._io:seek(_pos)
return self._m_type_list_and_reference_lists
end
--
-- Use `names` instead,
-- unless you need access to this instance's `_io`.
ResourceFork.ResourceMap.property.names_with_io = {}
function ResourceFork.ResourceMap.property.names_with_io:get()
if self._m_names_with_io ~= nil then
return self._m_names_with_io
end
local _pos = self._io:pos()
self._io:seek(self.ofs_names)
self._raw__m_names_with_io = self._io:read_bytes_full()
local _io = KaitaiStream(stringstream(self._raw__m_names_with_io))
self._m_names_with_io = BytesWithIo(_io)
self._io:seek(_pos)
return self._m_names_with_io
end
--
-- Storage area for the names of all resources.
ResourceFork.ResourceMap.property.names = {}
function ResourceFork.ResourceMap.property.names:get()
if self._m_names ~= nil then
return self._m_names
end
self._m_names = self.names_with_io.data
return self._m_names
end
--
-- Reserved space for a copy of the resource file header.
--
-- Reserved space for a handle to the next loaded resource map in memory.
--
-- Reserved space for the resource file's file reference number.
--
-- The resource file's attributes.
--
-- Offset of the resource type list,
-- from the start of the resource map.
--
-- In practice,
-- this should always be `sizeof<resource_map>`,
-- i. e. the resource type list should directly follow the resource map.
--
-- Offset of the resource name area,
-- from the start of the resource map.
--
-- A resource file's attributes,
-- as stored in the resource map.
--
-- These attributes are sometimes also referred to as resource map attributes,
-- because of where they are stored in the file.
ResourceFork.ResourceMap.FileAttributes = class.class(KaitaiStruct)
function ResourceFork.ResourceMap.FileAttributes:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.ResourceMap.FileAttributes:_read()
self.resources_locked = self._io:read_bits_int_be(1) ~= 0
self.reserved0 = self._io:read_bits_int_be(6)
self.printer_driver_multifinder_compatible = self._io:read_bits_int_be(1) ~= 0
self.no_write_changes = self._io:read_bits_int_be(1) ~= 0
self.needs_compact = self._io:read_bits_int_be(1) ~= 0
self.map_needs_write = self._io:read_bits_int_be(1) ~= 0
self.reserved1 = self._io:read_bits_int_be(5)
end
--
-- The attributes as a packed integer,
-- as they are stored in the file.
ResourceFork.ResourceMap.FileAttributes.property.as_int = {}
function ResourceFork.ResourceMap.FileAttributes.property.as_int:get()
if self._m_as_int ~= nil then
return self._m_as_int
end
local _pos = self._io:pos()
self._io:seek(0)
self._m_as_int = self._io:read_u2be()
self._io:seek(_pos)
return self._m_as_int
end
--
-- TODO What does this attribute actually do,
-- and how is it different from `read_only`?
--
-- This attribute is undocumented and not defined in <CarbonCore/Resources.h>,
-- but ResEdit has a checkbox called "Resources Locked" for this attribute.
--
-- These attributes have no known usage or meaning and should always be zero.
--
-- Indicates that this printer driver is compatible with MultiFinder,
-- i. e. can be used simultaneously by multiple applications.
-- This attribute is only meant to be set on printer driver resource forks.
--
-- This attribute is not documented in Inside Macintosh and is not defined in <CarbonCore/Resources.h>.
-- It is documented in technote PR510,
-- and ResEdit has a checkbox called "Printer Driver MultiFinder Compatible" for this attribute.
-- See also: Apple Technical Note PR510 - Printer Driver Q&As, section '"Printer driver is MultiFinder compatible" bit' (https://developer.apple.com/library/archive/technotes/pr/pr_510.html)
--
-- Indicates that the Resource Manager should not write any changes from memory into the resource file.
-- Any modification operations requested by the application will return successfully,
-- but will not actually update the resource file.
--
-- TODO Is this attribute supposed to be set on disk or only in memory?
--
-- Indicates that the resource file should be compacted the next time it is written by the Resource Manager.
-- This attribute is only meant to be set in memory;
-- it is cleared when the resource file is written to disk.
--
-- This attribute is mainly used internally by the Resource Manager,
-- but may also be set manually by the application.
--
-- Indicates that the resource map has been changed in memory and should be written to the resource file on the next update.
-- This attribute is only meant to be set in memory;
-- it is cleared when the resource file is written to disk.
--
-- This attribute is mainly used internally by the Resource Manager,
-- but may also be set manually by the application.
--
-- These attributes have no known usage or meaning and should always be zero.
--
-- Resource type list and storage area for resource reference lists in the resource map.
--
-- The two parts are combined into a single type here for technical reasons:
-- the start of the resource reference list area is not stored explicitly in the file,
-- instead it always starts directly after the resource type list.
-- The simplest way to implement this is by placing both types into a single `seq`.
ResourceFork.ResourceMap.TypeListAndReferenceLists = class.class(KaitaiStruct)
function ResourceFork.ResourceMap.TypeListAndReferenceLists:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.ResourceMap.TypeListAndReferenceLists:_read()
self.type_list = ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList(self._io, self, self._root)
self.reference_lists = self._io:read_bytes_full()
end
--
-- The resource map's resource type list.
--
-- Storage area for the resource map's resource reference lists.
--
-- According to Inside Macintosh,
-- the reference lists are stored contiguously,
-- in the same order as their corresponding resource type list entries.
--
-- Resource type list in the resource map.
ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList = class.class(KaitaiStruct)
function ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList:_read()
self.num_types_m1 = self._io:read_u2be()
self.entries = {}
for i = 0, self.num_types - 1 do
self.entries[i + 1] = ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.TypeListEntry(self._io, self, self._root)
end
end
--
-- The number of resource types in this list.
ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.property.num_types = {}
function ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.property.num_types:get()
if self._m_num_types ~= nil then
return self._m_num_types
end
self._m_num_types = ((self.num_types_m1 + 1) % 65536)
return self._m_num_types
end
--
-- The number of resource types in this list,
-- minus one.
--
-- If the resource list is empty,
-- the value of this field is `0xffff`,
-- i. e. `-1` truncated to a 16-bit unsigned integer.
--
-- Entries in the resource type list.
--
-- A single entry in the resource type list.
--
-- Each entry corresponds to exactly one resource reference list.
ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.TypeListEntry = class.class(KaitaiStruct)
function ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.TypeListEntry:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.TypeListEntry:_read()
self.type = self._io:read_bytes(4)
self.num_references_m1 = self._io:read_u2be()
self.ofs_reference_list = self._io:read_u2be()
end
--
-- The number of resources in the reference list for this type.
ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.TypeListEntry.property.num_references = {}
function ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.TypeListEntry.property.num_references:get()
if self._m_num_references ~= nil then
return self._m_num_references
end
self._m_num_references = ((self.num_references_m1 + 1) % 65536)
return self._m_num_references
end
--
-- The resource reference list for this resource type.
ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.TypeListEntry.property.reference_list = {}
function ResourceFork.ResourceMap.TypeListAndReferenceLists.TypeList.TypeListEntry.property.reference_list:get()
if self._m_reference_list ~= nil then
return self._m_reference_list
end
local _io = self._parent._parent._io
local _pos = _io:pos()
_io:seek(self.ofs_reference_list)
self._m_reference_list = ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList(self.num_references, _io, self, self._root)
_io:seek(_pos)
return self._m_reference_list
end
--
-- The four-character type code of the resources in the reference list.
--
-- The number of resources in the reference list for this type,
-- minus one.
--
-- Empty reference lists should never exist.
--
-- Offset of the resource reference list for this resource type,
-- from the start of the resource type list.
--
-- Although the offset is relative to the start of the type list,
-- it should never point into the type list itself,
-- but into the reference list storage area that directly follows it.
-- That is,
-- it should always be at least `_parent._sizeof`.
--
-- A resource reference list,
-- as stored in the reference list area.
--
-- Each reference list has exactly one matching entry in the resource type list,
-- and describes all resources of a single type in the file.
ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList = class.class(KaitaiStruct)
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList:_init(num_references, io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self.num_references = num_references
self:_read()
end
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList:_read()
self.references = {}
for i = 0, self.num_references - 1 do
self.references[i + 1] = ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference(self._io, self, self._root)
end
end
--
-- The resource references in this reference list.
--
-- The number of references in this resource reference list.
--
-- This information needs to be passed in as a parameter,
-- because it is stored in the reference list's type list entry,
-- and not in the reference list itself.
--
-- A single resource reference in a resource reference list.
ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference = class.class(KaitaiStruct)
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference:_read()
self.id = self._io:read_s2be()
self.ofs_name = self._io:read_u2be()
self._raw_attributes = self._io:read_bytes(1)
local _io = KaitaiStream(stringstream(self._raw_attributes))
self.attributes = ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.Attributes(_io, self, self._root)
self.ofs_data_block = self._io:read_bits_int_be(24)
self._io:align_to_byte()
self.reserved_handle = self._io:read_u4be()
end
--
-- The name (if any) of the resource described by this reference.
ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.property.name = {}
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.property.name:get()
if self._m_name ~= nil then
return self._m_name
end
if self.ofs_name ~= 65535 then
local _io = self._root.resource_map.names_with_io._io
local _pos = _io:pos()
_io:seek(self.ofs_name)
self._m_name = ResourceFork.ResourceMap.Name(_io, self, self._root)
_io:seek(_pos)
end
return self._m_name
end
--
-- The data block containing the data for the resource described by this reference.
ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.property.data_block = {}
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.property.data_block:get()
if self._m_data_block ~= nil then
return self._m_data_block
end
local _io = self._root.data_blocks_with_io._io
local _pos = _io:pos()
_io:seek(self.ofs_data_block)
self._m_data_block = ResourceFork.DataBlock(_io, self, self._root)
_io:seek(_pos)
return self._m_data_block
end
--
-- ID of the resource described by this reference.
--
-- Offset of the name for the resource described by this reference,
-- from the start of the resource name area.
--
-- If the resource has no name,
-- the value of this field is `0xffff`
-- i. e. `-1` truncated to a 16-bit unsigned integer.
--
-- Attributes of the resource described by this reference.
--
-- Offset of the data block for the resource described by this reference,
-- from the start of the resource data area.
--
-- Reserved space for the resource's handle in memory.
--
-- A resource's attributes,
-- as stored in a resource reference.
ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.Attributes = class.class(KaitaiStruct)
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.Attributes:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.Attributes:_read()
self.system_reference = self._io:read_bits_int_be(1) ~= 0
self.load_into_system_heap = self._io:read_bits_int_be(1) ~= 0
self.purgeable = self._io:read_bits_int_be(1) ~= 0
self.locked = self._io:read_bits_int_be(1) ~= 0
self.protected = self._io:read_bits_int_be(1) ~= 0
self.preload = self._io:read_bits_int_be(1) ~= 0
self.needs_write = self._io:read_bits_int_be(1) ~= 0
self.compressed = self._io:read_bits_int_be(1) ~= 0
end
--
-- The attributes as a packed integer,
-- as they are stored in the file.
ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.Attributes.property.as_int = {}
function ResourceFork.ResourceMap.TypeListAndReferenceLists.ReferenceList.Reference.Attributes.property.as_int:get()
if self._m_as_int ~= nil then
return self._m_as_int
end
local _pos = self._io:pos()
self._io:seek(0)
self._m_as_int = self._io:read_u1()
self._io:seek(_pos)
return self._m_as_int
end
--
-- Indicates that this resource reference is a system reference rather than a regular local reference.
-- This attribute is nearly undocumented.
-- For all practical purposes,
-- it should be considered reserved and should always be zero.
--
-- This attribute was last documented in the Promotional Edition of Inside Macintosh,
-- in the Resource Manager chapter,
-- on pages 37-41,
-- in a "System References" section that calls itself "of historical interest only".
-- The final versions of Inside Macintosh only mention this attribute as "reserved for use by the Resource Manager".
-- <CarbonCore/Resources.h> contains a `resSysRefBit` constant,
-- but no corresponding `resSysRef` constant like for all other resource attributes.
--
-- According to the Inside Macintosh Promotional Edition,
-- a system reference was effectively an alias pointing to a resource stored in the system file,
-- possibly with a different ID and name (but not type) than the system reference.
-- If this attribute is set,
-- `ofs_data_block` is ignored and should be zero,
-- and `reserved_handle` contains
-- (in its high and low two bytes, respectively)
-- the ID and name offset of the real system resource that this system reference points to.
--
-- TODO Do any publicly available Mac OS versions support system references,
-- and do any real files/applications use them?
-- So far the answer seems to be no,
-- but I would like to be proven wrong!
--
-- Indicates that this resource should be loaded into the system heap if possible,
-- rather than the application heap.
--
-- This attribute is only meant to be used by Mac OS itself,
-- for System and Finder resources,
-- and not by normal applications.
--
-- This attribute may be set both in memory and on disk,
-- but it only has any meaning while the resource file is loaded into memory.
--
-- Indicates that this resource's data should be purgeable by the Mac OS Memory Manager.
-- This allows the resource data to be purged from memory if space is needed on the heap.
-- Purged resources can later be reloaded from disk if their data is needed again.
--
-- If the `locked` attribute is set,
-- this attribute has no effect
-- (i. e. locked resources are never purgeable).
--
-- This attribute may be set both in memory and on disk,
-- but it only has any meaning while the resource file is loaded into memory.
--
-- Indicates that this resource's data should be locked to the Mac OS Memory Manager.
-- This prevents the resource data from being moved when the heap is compacted.
--
-- This attribute may be set both in memory and on disk,
-- but it only has any meaning while the resource file is loaded into memory.
--
-- Indicates that this resource should be protected (i. e. unmodifiable) in memory.
-- This prevents the application from using the Resource Manager to change the resource's data or metadata,
-- or delete it.
-- The only exception are the resource's attributes,
-- which can always be changed,
-- even for protected resources.
-- This allows protected resources to be unprotected again by the application.
--
-- This attribute may be set both in memory and on disk,
-- but it only has any meaning while the resource file is loaded into memory.
--
-- Indicates that this resource's data should be immediately loaded into memory when the resource file is opened.
--
-- This attribute may be set both in memory and on disk,
-- but it only has any meaning when the resource file is first opened.
--
-- Indicates that this resource's data has been changed in memory and should be written to the resource file on the next update.
-- This attribute is only meant to be set in memory;
-- it is cleared when the resource file is written to disk.
--
-- This attribute is used internally by the Resource Manager and should not be set manually by the application.
--
-- Indicates that this resource's data is compressed.
-- Compressed resource data is decompressed transparently by the Resource Manager when reading.
--
-- For a detailed description of the structure of compressed resources as they are stored in the file,
-- see the compressed_resource.ksy spec.
--
-- A resource name,
-- as stored in the resource name storage area in the resource map.
--
-- The resource names are not required to appear in any particular order.
-- There may be unused space between and around resource names,
-- but in practice they are often contiguous.
ResourceFork.ResourceMap.Name = class.class(KaitaiStruct)
function ResourceFork.ResourceMap.Name:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function ResourceFork.ResourceMap.Name:_read()
self.len_value = self._io:read_u1()
self.value = self._io:read_bytes(self.len_value)
end
--
-- The length of the resource name, in bytes.
--
-- The resource name.
--
-- This field is exposed as a byte array,
-- because there is no universal encoding for resource names.
-- Most Classic Mac software does not deal with encodings explicitly and instead assumes that all strings,
-- including resource names,
-- use the system encoding,
-- which varies depending on the system language.
-- This means that resource names can use different encodings depending on what system language they were created with.
--
-- Many resource names are plain ASCII,
-- meaning that the encoding often does not matter
-- (because all Mac OS encodings are ASCII-compatible).
-- For non-ASCII resource names,
-- the most common encoding is perhaps MacRoman
-- (used for English and other Western languages),
-- but other encodings are also sometimes used,
-- especially for software in non-Western languages.
--
-- There is no requirement that all names in a single resource file use the same encoding.
-- For example,
-- localized software may have some (but not all) of its resource names translated.
-- For non-Western languages,
-- this can lead to some resource names using MacRoman,
-- and others using a different encoding.


Session History (-)
Your query history will be displayed here. It can be edited or re-set.
List A (-)
Items in this list can be compared to those in List B, or added to a node in the query_graph via the bulk import functionality.
List B (-)
Items in this list can be compared to those in List A, or added to a node in the query_graph via the bulk import functionality.
Compare Lists A and B
Items in lists A and B will be automatically displayed side-by-side for ease of comparison.
Recent ARAX System Activity


{{ totalenrolments_per_day }}average enrolments per day over last 30 days
{{ totalenrolments }}Total Enrolments
Enrolments For Courses
{{course.meta.name}}
{{ course.enrolments }} total enrolments
{{ course.perday }} enrolments per day
{{ course.certificates }} certificates given
currently the course is {{ course.status }}
Learner Progress and Certificates
Registered: Registered for course but did not access any content.
Viewed: Anyone who accessed the ’Courseware’ tab (the home of the videos, problem sets, and
assessment) within the edX platform for the course. Note that there exist course materials outside
of the ’Courseware’ tab, such as the Syllabus or the Discussion forums.
Explored: Anyone who accessed at least half of the chapters in the courseware (chapters are the
highest level on the ”courseware” menu housing course content).
Certified: Anyone who earned a certificate.
Demographics
Top Countries (total {{total_countries}} countries)
Top Countries (total {{total_countries}} countries)


Protocols
The following protocols are available globally.
-
A
See moreDistanceSortFunction
that defines it’sdistancePoint
based on aDirection
. Any distance based sort functions that use a direction variable in order to determine the setup of the animation should implement this protocol.Declaration
Swift
public protocol DirectionSortFunction: DistanceSortFunction
-
A
See moreSortFunction
implementation that contain basic methods needed for doing distance comparisons. If you are implementing aSortFunction
that considers distance to be one of it’s weighting mechanisms for sorting the views on the screen, then implementing this protocol would provide improvements over the standardSortFunction
.Declaration
Swift
public protocol DistanceSortFunction: SortFunction
-
For all the views on the screen, we need to find some way of organizing them so that when we start the animation, each view will know when to start their individual animation. The concept of a
See moreSortFunction
is just that. Given a view, the subviews of that view are sorted in a way that when animated they resemble the nature of that sort function. There are many different types of sort functions because there are so many ways to sort the subviews that are on the screen. If you don’t see a stock one that fits your need, feel free to implement this protocol and use your own customSortFunction
with Spruce.Declaration
Swift
public protocol SortFunction
-
Used to keep track of the
See moreUIView
object and a changing reference point. Since Spruce allows for recursive subview lookup, we need to handle changing the coordinate space. Once the coordinate space has been accounted for we can then alter the reference point.Declaration
Swift
public protocol View
-
A
See moreDistanceSortFunction
that uses a position attribute to define an animation’s starting point.Declaration
Swift
public protocol PositionSortFunction: DistanceSortFunction
-
A
See moreSortFunction
that takes into account the vertical and horizontal weight of the position of views. The lighter the weight the the faster those views will start to animate. For example, if you had a lightverticalWeight
and a heavyhorizontalWeight
, the views that are vertically aligned with the starting position will animate before those that are horizontally aligned. This allows you to define the exact rigidness of aradial
likeSortFunction
.Declaration
Swift
public protocol WeightSortFunction: SortFunction
-
A
See moreDistanceSortFunction
that uses a corner attribute to define an animation’s starting point.Declaration
Swift
public protocol CornerSortFunction: DistanceSortFunction


Robert Peston: Whose side are you choosing in this election’s new class war?
by Peston's PoliticsI am not sure if it is class war exactly but something very like it is back.
Perhaps it is a hybrid of a class, eco and generational war.
In that Labour is planning to sting those earning £80,000 a year or more with an additional tax burden just short of £20bn from higher taxes on income, capital (wealth) and dividends (on assets either directly held or in savings schemes).
As for businesses and financial institutions, they are being whacked for almost £50bn, in a dizzying array of increased levies on profits, assets and financial trading, and - eccentrically perhaps for a party saying it wants to encourage a green hi-tech economy - a reduction in allowances for spending on research.
And there’ll be a further £11bn windfall levy on carbon spewing oil companies - and businesses failing to meet environmental standards would be kicked off the stock exchange.
That is the stick with which Jeremy Corbyn intends to beat the “billionaires” he holds in contempt. Though slightly less emotively and more accurately the shadow chancellor John McDonnell insists it is the top 5% who will pay for the improved public services Labour is promising.
Actually some lower earners would be penalised by Labour’s reversal of inheritance tax cuts and abolition of the married persons allowance.
And if companies respond to the tax rises by lifting prices or cutting employment, we’ll all pay some kind of price.
But that is to quibble.
Corbyn’s Labour is looking to the private sector and to the richest one-twentieth of us - most of them over 50 - to finance significantly increased spending on welfare, schools, hospitals, personal care for the elderly and students (tuition fees abolished; maintenance grants restored).
Perhaps most symbolically there would be a 5% pay rise for all public sector workers - who will now need an even better reason than they may have already had NOT to vote for Corbyn’s Labour.
Theoretically everyone would benefit if Labour’s £450bn of borrowing for all manner of green investment and nationalisations accelerated overall growth.
And there could also be a stimulus from the £500bn of government backed loans and investments Labour would want to make over ten years from a new National Investment Bank.
- Labour pledges 'green industrial revolution' with nuclear power and a digging over of allotment laws
How much of that state-directed investment will be spilled milk like the state investment of yore we cannot know until we see the calibre of the new breed of public sector technocrat.
The important point though is that under Labour there would be a massive shift of economic and political clout away from the executive or boss class, away from owners of capital and away from boomers (hello Jeremy Corbyn) and towards the state, the government, employees (promised a universal £10-an-hour living wage) and trade unions (who would gain important new collective bargaining rights to set pay and working conditions for whole sectors).
We haven’t seen an election defined quite in this way by economic and demographic interests since 1992. Like it or not, you are going to have to choose a side.


SMContact Class Reference
| Inherits from | NSObject |
|---|---|
| Declared in | SMContact.h |
sources
Source of contact such as SPiDR, Facebook, LinkedIn .. etc.
@property (strong, nonatomic, nullable) NSString *sources
Availability
2.0.0
Discussion
Source of contact such as SPiDR, Facebook, LinkedIn .. etc.
Declared In
SMContact.h
emailAddress
Email address of the user.
@property (strong, nonatomic, nullable) NSString *emailAddress
Availability
2.0.0
Discussion
Email address of the user.
Declared In
SMContact.h
entryId
Unique identifier of the entry.
@property (strong, nonatomic, nullable) NSString *entryId
Availability
2.0.0
Discussion
Unique identifier of the entry.
Declared In
SMContact.h
fax
Fax number of the user.
@property (strong, nonatomic, nullable) NSString *fax
Availability
2.0.0
Discussion
Fax number of the user.
Declared In
SMContact.h
firstName
First name of the user.
@property (strong, nonatomic, nullable) NSString *firstName
Availability
2.0.0
Discussion
First name of the user.
Declared In
SMContact.h
lastName
Last name of the user.
@property (strong, nonatomic, nullable) NSString *lastName
Availability
2.0.0
Discussion
Last name of the user.
Declared In
SMContact.h
friendStatus
Friend status of the user.
@property (nonatomic) BOOL friendStatus
Availability
2.0.0
Discussion
Friend status of the user.
Declared In
SMContact.h
homePhone
Home phone number of the user.
@property (strong, nonatomic, nullable) NSString *homePhone
Availability
2.0.0
Discussion
Home phone number of the user.
Declared In
SMContact.h
mobilePhone
Mobile phone number of the user.
@property (strong, nonatomic, nullable) NSString *mobilePhone
Availability
2.0.0
Discussion
Mobile phone number of the user.
Declared In
SMContact.h
nickName
Name of the user as it will appear for a personal contact.
@property (strong, nonatomic, nullable) NSString *nickName
Availability
2.0.0
Discussion
Name of the user as it will appear for a personal contact.
Declared In
SMContact.h
pager
Pager number of the user.
@property (strong, nonatomic, nullable) NSString *pager
Availability
2.0.0
Discussion
Pager number of the user.
Declared In
SMContact.h
photoUrl
URL from which to retrieve the picture of the user.
@property (strong, nonatomic, nullable) NSString *photoUrl
Availability
2.0.0
Discussion
URL from which to retrieve the picture of the user.
Declared In
SMContact.h
primaryContact
User’s primary contact number (this should be prefered number for contacting the user).
@property (strong, nonatomic, nonnull) SMUriAddress *primaryContact
Availability
2.0.0
Discussion
User’s primary contact number (this should be prefered number for contacting the user).
Declared In
SMContact.h
workPhone
Work phone number of the user.
@property (strong, nonatomic, nullable) NSString *workPhone
Availability
2.0.0
Discussion
Work phone number of the user.
Declared In
SMContact.h
– initWithDictionary:
Constructor method with NSDictionary
- (id)initWithDictionary:(nonnull NSDictionary *)dictionary
Parameters
dictionary |
Contact information dictionary |
|---|
Availability
2.0.0
Discussion
Constructor method with NSDictionary
Declared In
SMContact.h


To follow along, load this in your browser: https://www.ryanpatrickrandall.com/talks/engl102.html
Created by Ryan P. Randall
I'm here to help you prepare for your next assignment. And the rest of your classes, to be honest.
We'll talk about the inquiry process and advanced searching.
"Research" is not finding a hidden cave full of facts.
So what is it?
Let's take three minutes to talk about how you currently research things. What do you do? How do you start? How do you end?
Where do you tend to look?
How do you decide if it's good to use?
When do you know it's time to stop?
Wait: how did you even know what question you were asking?
It might surprise you, but expert writers go through that middle circle repeatedly.
Ask yourself questions in each part to help you move along!
The Seattle Community Colleges's research process puzzle shows evaluation as central.
aka "I'm happy for you & I'm gonna let you finish
but I need to get this paper done"
The Library can help most with the first three parts.
Here's some great places to start!
Let's work on developing the keywords for your search.
| Topic | Broader | Narrower | Synonym | Related | |
|---|---|---|---|---|---|
| examples: | car | vehicle | Honda | automobile | truck |
Let's try searching for books related to our topic.
How did this go? Let me know at https://bit.ly/cwilif!
Please schedule an appointment with a CWI Librarian if you'd like further research assistance.
You can also get help from the College of Western Idaho Libraries through our online chat, our FAQ pages, calling or texting us, and email!
Thank you for your time!
"Pulling a book off the shelf" photo by Bennington College's Crossett Library with a CC BY-NC-SA 2.0 license.
Blakeslee, S. (2004). The CRAAP test. LOEX Quarterly, 31(3), 6-7. Retrieved from https://commons.emich.edu/loexquarterly/vol31/iss3/4.
"Purpose" photo by Seth Sawyers with a CC BY 2.0 license and given some minimal filtering by Ryan.