diff --git a/20221130.1710 b/20221210.0854 similarity index 100% rename from 20221130.1710 rename to 20221210.0854 diff --git a/Gemfile b/Gemfile index 26a7a59..c3004cd 100644 --- a/Gemfile +++ b/Gemfile @@ -34,6 +34,9 @@ gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] # do not have a Java counterpart. gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] -gem "webrick", "~> 1.7" +#gem "webrick", "~> 1.7" +#gem "webrick", ">=2.2.8" gem "jekyll", "~> 3.9" + +gem "webrick", "~> 1.8" diff --git a/Gemfile.lock b/Gemfile.lock index eeb512d..6580388 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,35 +1,46 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.6) + activesupport (6.0.6.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) zeitwerk (~> 2.2, >= 2.2.2) - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.11.1) colorator (1.1.0) - commonmarker (0.23.6) - concurrent-ruby (1.1.10) - dnsruby (1.61.9) - simpleidn (~> 0.1) + commonmarker (0.23.10) + concurrent-ruby (1.3.4) + dnsruby (1.72.2) + simpleidn (~> 0.2.1) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) ethon (0.16.0) ffi (>= 1.15.0) eventmachine (1.2.7) - execjs (2.8.1) - faraday (2.7.1) - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) - ffi (1.15.5) + execjs (2.9.1) + faraday (2.12.0) + faraday-net_http (>= 2.0, < 3.4) + json + logger + faraday-net_http (3.3.0) + net-http + ffi (1.17.0-aarch64-linux-gnu) + ffi (1.17.0-aarch64-linux-musl) + ffi (1.17.0-arm-linux-gnu) + ffi (1.17.0-arm-linux-musl) + ffi (1.17.0-arm64-darwin) + ffi (1.17.0-x86-linux-gnu) + ffi (1.17.0-x86-linux-musl) + ffi (1.17.0-x86_64-darwin) + ffi (1.17.0-x86_64-linux-gnu) + ffi (1.17.0-x86_64-linux-musl) forwardable-extended (2.6.0) gemoji (3.0.1) github-pages (227) @@ -197,21 +208,35 @@ GEM gemoji (~> 3.0) html-pipeline (~> 2.2) jekyll (>= 3.0, < 5.0) + json (2.7.2) kramdown (2.3.2) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) liquid (4.0.3) - listen (3.7.1) + listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.1) mercenary (0.3.6) minima (2.5.1) jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.16.3) - nokogiri (1.13.9-x86_64-darwin) + minitest (5.25.1) + net-http (0.4.1) + uri + nokogiri (1.16.7-aarch64-linux) + racc (~> 1.4) + nokogiri (1.16.7-arm-linux) + racc (~> 1.4) + nokogiri (1.16.7-arm64-darwin) + racc (~> 1.4) + nokogiri (1.16.7-x86-linux) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) octokit (4.25.1) faraday (>= 1, < 3) @@ -219,13 +244,12 @@ GEM pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (4.0.7) - racc (1.6.0) + racc (1.8.1) rb-fsevent (0.11.2) - rb-inotify (0.10.1) + rb-inotify (0.11.1) ffi (~> 1.0) - rexml (3.2.5) + rexml (3.3.7) rouge (3.26.0) - ruby2_keywords (0.0.5) rubyzip (2.3.2) safe_yaml (1.0.5) sass (3.7.4) @@ -236,24 +260,33 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) - simpleidn (0.2.1) - unf (~> 0.1.4) + simpleidn (0.2.3) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) thread_safe (0.3.6) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) - tzinfo (1.2.10) + tzinfo (1.2.11) thread_safe (~> 0.1) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) unicode-display_width (1.8.0) - webrick (1.7.0) - zeitwerk (2.6.6) + uri (0.13.1) + webrick (1.8.1) + zeitwerk (2.6.18) PLATFORMS - x86_64-darwin-18 + aarch64-linux + aarch64-linux-gnu + aarch64-linux-musl + arm-linux + arm-linux-gnu + arm-linux-musl + arm64-darwin + x86-linux + x86-linux-gnu + x86-linux-musl + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl DEPENDENCIES github-pages (~> 227) @@ -265,7 +298,7 @@ DEPENDENCIES tzinfo (>= 1, < 3) tzinfo-data wdm (~> 0.1.1) - webrick (~> 1.7) + webrick (~> 1.8) BUNDLED WITH - 2.3.26 + 2.5.16 diff --git a/_layouts/post.html b/_layouts/post.html index c9a03be..565d632 100644 --- a/_layouts/post.html +++ b/_layouts/post.html @@ -1,6 +1,7 @@ --- layout: default --- +
diff --git a/_posts/2022-12-15-dircmp.py-improvements.markdown b/_posts/2022-12-15-dircmp.py-improvements.markdown new file mode 100644 index 0000000..fdaf502 --- /dev/null +++ b/_posts/2022-12-15-dircmp.py-improvements.markdown @@ -0,0 +1,146 @@ +--- +layout: post +title: "dircmp.py - a plan to improve and extend" +categories: unix python +--- + +## dircmp.py + +### A plan to improve and extend + +This note pertains to [dircmp.py](https://github.com/decuser/decuser_python_playground/blob/master/dircmp/dircmp.py) a program that I wrote to give me information about two directories for the purpose of deciding what to keep and what to remove and to learn about python. The note is a draft note and as such it's not very refined and it may lack in many ways, but I thought it might be interesting to put it out there and let anyone see it. Email me if you have comments or suggestions. + + + +#### Caveats + +The comparisons here are between simple folders and files (including hidden files). By simple, I don't mean small - I use the program to compare very large directories. However, the tool was developed for comparing directories containing user files and not as a system maintenance tool. I haven't done much investigating of hard / soft symlinks or exotic setups. + +#### Random Observation + +When originally creating the program, I had the thought that git's organization would provide an ideal filesystem for keeping changes and being able to see those changes easily. Just keep file contents in blobs, their digests, names, and locations elsewhere. Files with identical contents would share the blob and digests, but the names and locations could differ. When saving a new file, do a digest, check the registry, link to the blob, etc. Sure, it'd be slow, but integral. A little above my paygrade, but percolating in the back of my mind. + +#### Features under consideration + +* Synchronization Planning +* Synchronization Execution with Undo and potentially segregation + +#### Other potential enhancements + +* Historical comparisons (save results and use for future compares) + +#### Future research + +* symlinks and exotic setups :) + +#### Background +Currently, the program does a great job of identifying differences and matches between two directory trees. However, it does not do a good job of providing the user with plans to synchronize those trees or the ability to synchronize directories. + +When I started this project, my goal was to identify, not address, so the program met its objectives. Now, I want to have the program generate plans to synchronize and perform the synchroniztion. + +#### Current functionality + +Looking at the program as a whole and as a black box, it takes a directory or pair of directories and compiles a set of results... + +##### Results + +Pair Results Report + +* duplicate files found in either directory +* exact matches found in both directories +* files that only exist in one of the directories +* files that have the same names but different digests +* files that have different names but same digest + +Single Results Report + +* duplicate files found in directory + +##### Method of Operation + +The comparisons are done using a calculated digest for every file that exists within the scope of the comparison, either a single level, or recursive. + +##### Options + +The program supports the following options for controlling its behavior: + +* -h, --help - show a help message and exit +* -b, --brief - Brief mode - suppress file lists +* -a, --all - Include hidden files in comparisons +* -r, --recurse - Recurse subdirectories +* -f, --fast - Perform shallow digests (super fast, but necessarily less accurate) +* -d, --debug - Debug mode +* -c, --compact - Compact mode +* -s, --single - Single directory mode +* -v, --version - show program's version number and exit + +#### Discussion + +All in all, it works great. I've used it a lot. It's fast and accurate. However, in using it, it has become apparent that what I really want it to do is tell me how to get two directories to synchronize. + +I have used rsync (prolly best of breed) and tried many, many other programs to quickly and easily sync directories, and I haven't liked any of them, in the end. Usually, I wind up losing files that I don't want to lose, sometimes through unintentional misuse of the tool, especially with rsync's arcane syntax, but usually through an inability to figure out what the tool actually does (not how it does what it does, but what the results are) and thinking two directories are synced after running the tool only to find out later that they weren't ... not exactly. + +At least with dirsync.py as it exists today, I know exactly what it is doing. The results are detailed and precise. It lives to tell me, in detail, what differences exist between two directories. With this information in hand, it is possible to determine a finite plan to synchronize them. + +Interestingly, synchronization can be accomplished with several distinct outcomes, as follows. + +#### Synchronize how? + +In the following discussions, I will use left and right to differentiate the two directories being discussed and will only discuss synchronizing two directories. + +##### One Way Synchronizations + +* Left to Right - *right directory is made to exactly match the left directory* +* Right to Left - *left directory is made to exactly match the right directory* + +Conflicts arising in one way synchronizations are resolved by order definition - files and directories from one side are chosen whenever there is a mismatch. + +##### Two Way Sychronizations + +Whenever two way synchronizations are performed, there is a likelihood of conflicts and it is important to consider strategies to resolve those conflicts. This is where synchronization gets tricky. + +Here are the possible strategies + +* Preserve None - *remove conflicts from left and right (neither win)* +* Preserve Left - *merge left into right (left wins)* +* Preserve Right - *merge right into left (right wins)* +* Preserve Both (versioning) *merge both ways (both win) and create versions when there is a conflict* + + +##### Thoughts before diving into the details + +I think that inline with providing undo, it may be useful to preserve conflicts for the user... as in, when there's a conflict, move the loser (one side, or both) into a separate area (preserving prior location information) for the user to decide what to do with. Given a robust enough functionality, this may be moot, but I remember doing this sorta thing before and it being useful. + +#### Rough sketch strategy + +* Analyze directories to determine what needs to change +* Report status +* Stage changes +* Make changes (as economically and safely as possible) + * Stage a modification + * Save recovery information + * Make the modification +* Report changes + +#### Thoughts related to the economics + +The expenses in this program are the costs of computing digests, comparing those digests, and copying files. Deletions are cheap, as are moves. So, the program should only compute digests as requested. When fast mode is active, the algorithm only reads a portion of the file, rather than the entirety, so this must be taken into account. Comparisons of the digest are mandatory. Copying files is expensive and should be minimized. + +Interestingly, when I started looking at this part of the code, I figured out that my fast digest approach probably needs to be improved. My premise, when I wrote it was that big files tend not to change in small ways over time - movies, images, and such. So, files over 10MB were considered candidates for an optimization of the digest process... This has proved to be a good intuition, but there are certainly some exceptions that could cause problems with the simple approach currently in the code (read the file size in bytes, read the first 1MB and the last 1MB and use these for the digest). I remember coming up with a strategy more along the lines of 100MB being the threshold and taking 100MB of random samples from the file. I don't remember why I changed it, but it was prolly just a matter of it taking too long and/or being somewhat more complicated to implement for the time I set aside to do the work... either way, the current code is quite basic, but fast... and it's worked fine because the only large files that I've used it on have been normal user files that simply don't change much in the middle. Still, this is definitely an area to optimize. The easiest example of a file that would be problematic that I can think of is a VM drive file... When in doubt, don't use fast mode :). + +#### Stuff to think about + +* Fast digest - what's a better approach that's still fast (sampling is slow, but is it necessary)? +* I seem to remember counting being challenging - does the program count correctly or does it need a fix? +* Symlinks are weird, but are they a problem? +* How to develop a changeset - linear, in a single pass, what? +* How to handle the undo functionality +* What to do about destructive changes - save the to be destroyed file somewhere +* How to handle duplicate versioning - naming, save somewhere +* Given past experience, what to do about voluminous reporting - definitely need better delineation of sections (very hard to differentiate in terminal) +* Tkinter? I dunno, I prefer something like avalonia, but that's .net, still should this have a ui? +* Order to do the coding - left to right and right to left first, then merges, which preservation strategies in what order? + +The playground has the latest code and branches [https://github.com/decuser/decuser_python_playground](https://github.com/decuser/decuser_python_playground) + +*post last updated 2022-12-15 17:53:00 -0600* \ No newline at end of file diff --git a/_posts/2022-12-15-usenix-flame-award-2022.markdown b/_posts/2022-12-15-usenix-flame-award-2022.markdown new file mode 100644 index 0000000..35590f0 --- /dev/null +++ b/_posts/2022-12-15-usenix-flame-award-2022.markdown @@ -0,0 +1,55 @@ +--- +layout: post +title: "Warren Toomey Awarded 2022 USENIX Flame" +categories: unix +--- + +Warren Toomey, the founder and maintainer of all things related to The Unix Heritage Society (TUHS) [https://www.tuhs.org/](https://www.tuhs.org/) has been awarded the 2022 USENIX Lifetime Achievment Award ("The Flame"). + +Without TUHS, it would hardly even be possible to enjoy retro unix explorations. This is a well earned accolade by an unassuming and very hard working individual. + +Congratulations, Warren! + +![flame](https://www.tuhs.org/Images/flame.jpg){: width="480" } + + + + +### About Warren Toomey + +Warren retired in 2021 after a three decade career of teaching Computer Science and IT in tertiary institutions including the University of New South Wales, Bond University and TAFE Queensland (a polytechnic/community college). His teaching was always systems focussed: computer architecture, operating systems, systems programming, networking and cybersecurity. Warren was first introduced to Unix at the end of 1982 at a Summer School at the University of Wollongong, but lost access to it when he started his undergraduate degree in 1984. This loss was the driving force behind his fascination with Unix and its history. Fortunately, Minix, 386BSD and FreeBSD came along at just the right time to slake Warren's thirst for Unix. He founded the Unix Heritage Society in 1994 (originally named the PDP-11 Unix Preservation Society) and has nurtured it since. Now retired, Warren's interests now include dressage riding, and he has become a competent groom for his wife Kaz, a professional 'Big Tour' rider. + +### Past recipients of the Flame + +* Chet Ramey (2020) +* Margo Seltzer (2019) +* Eddie Kohler (2018) +* Tom Anderson (2014) +* John Mashey (2012) +* Dan Geer (2011) +* Ward Cunningham (2010) +* In Honor of Gerald J. Popek (2009) +* Andrew S. Tanenbaum (2008) +* Peter Honeyman (2007) +* Radia Perlman (2006) +* Michael Stonebraker (2005) +* M. Douglas McIlroy (2004) +* Rick Adams (2003) +* James Gosling (2002) +* The GNU Project and all its contributors (2001) +* Richard Stevens (2000) +* The X Window System Community at Large (1999) +* Tim Berners-Lee (1998) +* Brian W. Kernighan (1997) +* The Software Tools Project (1996) +* The Creation of USENET (1995) +* Networking Technologies (1994) +* Berkeley UNIX (1993) + +Read more about the award and its recipients at [https://www.usenix.org/about/awards/flame](https://www.usenix.org/about/awards/flame) + +Read more about why Warren started TUHS at [https://minnie.tuhs.org/Blog/2015_12_14_why_start_tuhs.html](https://minnie.tuhs.org/Blog/2015_12_14_why_start_tuhs.html) + +\- will + +*post added 2022-12-15 17:52:00 -0600* diff --git a/_posts/2022-12-29-building-sculpt-22.10-on-debian-11.6.md b/_posts/2022-12-29-building-sculpt-22.10-on-debian-11.6.md new file mode 100644 index 0000000..f63c7b1 --- /dev/null +++ b/_posts/2022-12-29-building-sculpt-22.10-on-debian-11.6.md @@ -0,0 +1,309 @@ +--- +layout: post +title: "Building Sculpt 22.10 on Debian 11.6 Bullseye" +categories: operating-systems genode sculpt +--- +This note is about building a bootable Sculpt OS 22.10 image using a Debian 11 "Bullseye" Guest OS running in VirtualBox. This is useful as a starting point for building a custom image. My Thinkpad T430 runs Sculpt just fine, but wifi doesn't work, so I would like to add the needed firmware. This is work in that direction. + +The note also applies, leaving out the VirtualBox specifics, to building Sculpt OS 22.10 on a Debian instance running on metal (confirmed working 12/28). + + + +### Resources + +* Genode Operating System Framework Website [https://genode.org/](https://genode.org/) +* Genode OS Framework 22.05 Foundations Document [html](https://genode.org/documentation/genode-foundations/22.05/index.html) [pdf](https://genode.org/documentation/genode-foundations-22-05.pdf) +* Sculpt OS 22.10 Documentation [html](https://genode.org/documentation/articles/sculpt-22-10) [pdf](https://genode.org/documentation/sculpt-22-10.pdf) +* Mailing List [https://genode.org/community/mailing-lists](https://genode.org/community/mailing-lists) +* Genodians - Stories around the Genode Operating System [https://genodians.org/](https://genodians.org/) +* Git repository - [https://github.com/genodelabs/genode](https://github.com/genodelabs/genode) + +### Prerequisites + +* Host system - Mine is 2010 Mac Pro running Mojave +* VirtualBox w/extension pack - I'm running 6.1.40 + +### Download the Debian 11.6 Bullseye netinst.iso + + `aria2c https://gemmei.ftp.acc.umu.se/debian-cd/current/amd64/iso-cd/debian-11.6.0-amd64-netinst.iso` + +### Create a new debian virtualbox instance +* name: debian-11.6 +* 8GB RAM +* 2 CPUs +* 20GB HDD +* attach ~/shared +* attach debian-11.6.0-amd64-netinst.iso + +### Install Debian + +Start the VM and let it boot to the installer. Choose Install and not Graphical Install to use the perfectly adequate and much faster text installer. + +Make the following choice for packages: + +* Debian desktop environment + * Cinnamon (relatively lightweight and just works) +* standard system utilities + +### Prepare Debian for building Sculpt + +#### Add user to sudo + +* enable sudo with no password + + ``` +su - +visudo +%sudo ALL=(ALL:ALL) NOPASSWD:ALL +``` + +* add user to sudo group + + `usermod -a -G sudo wsenn` + +* Restart to get the group to take (should just require logout and back in, but it's what it is) + +#### Install Packages + +* update apt package list and upgrade packages + + `sudo apt update && sudo apt full-upgrade -y` + +* install basic dev tools + + Note: build-essential and gdisk are already installed) + + * basics + * build-essential + * vim + * vbox dependencies + * dkms + * linux-headers + * build system dependencies see Genode Foundations - Getting Started + * autoconf + * autogen + * bison + * byacc + * ccache + * e2tools + * expect + * flex + * gdisk + * git-gui + * gperf + * libsdl2-dev + * libxml2-utils + * qemu + * subversion + * xorriso + * xsltproc + + Note: apt will ignore already installed packages and different base selections such as Gnome vs Cinnamon may result in a different mix of already installed packages. + + ``` +sudo apt install build-essential vim \ + dkms linux-headers-$(uname -r) \ + autoconf autogen bison byacc ccache e2tools expect flex gdisk git-gui \ + gperf libsdl2-dev libxml2-utils qemu subversion xorriso xsltproc +``` + +* as regular user set vim as default editor + + `sudo update-alternatives --config editor # pick vim.basic` + +* turn off mouse nonsense in vim + + ``` +vi ~/.vimrc +set mouse-=a +``` + +* add sbin to path for build resize2fs requirement + + ``` +vi .bashrc +export PATH=$PATH:/sbin +``` + +#### Install Guest Additions + +* mount the cd and install guest additions + +* in vbox - `Devices->Insert Guest Additions CD Image` + + ``` +sudo mount /dev/cdrom /mnt +cd /mnt +sudo sh ./VBoxLinuxAdditions.run +``` + +* create a location to mount shared files + + `mkdir ~/shared` + +* add it to fstab + + ``` +sudo vi /etc/fstab +shared /home/wsenn/shared vboxsf defaults 0 0 +``` + +* enable vbox module for sharing + + ``` +sudo vi /etc/modules +vboxsf +``` + +* Reboot + + `sudo shutdown -r now` + + +#### Test shared folder and enable clipboard + +* Test the share + + `ls ~/shared` + + Should list any files you've put in shared. + +* Enable bi-directional clipboard + + in vbox `Devices->Shared Clipboard->Bidirectional` + + +### Install Genode Toolchain and Source Code + +* Download the toolchain and install it in /usr/local/genode + + ``` +cd ~/Downloads +wget -O genode-toolchain-21.05-x86_64.tar.xz https://sourceforge.net/projects/genode/files/genode-toolchain/21.05/genode-toolchain-21.05-x86_64.tar.xz/download +sudo tar xvPf genode-toolchain-21.05-x86_64.tar.xz +``` + +* Clone the source code and switch to the 22.10 release branch + + ``` +cd +git clone https://github.com/genodelabs/genode.git +cd genode +git checkout -b sculpt-22.10 sculpt-22.10 +``` + +### Build Sculpt + +* Get the nova kernel files + + `./tool/depot/download genodelabs/bin/x86_64/base-nova/2022-10-11` + +* Get the sculpt files + + `./tool/depot/download genodelabs/pkg/x86_64/sculpt/2022-10-13` + +* Handle vim-minimal tarball error by just restarting + +If you get an error concerning vim-minimal (I do), just restart the download of the sculpt packages... + + ``` +download genodelabs/src/vim-minimal/2022-08-30.tar.xz +download genodelabs/src/vim-minimal/2022-08-30.tar.xz.sig +xz: (stdin): Unexpected end of input +tar: Unexpected EOF in archive +tar: Unexpected EOF in archive +tar: Error is not recoverable: exiting now +make[1]: *** [/home/wsenn/genode/tool/depot/mk/downloader:45: /home/wsenn/genode/depot/genodelabs/src/vim-minimal/2022-08-30] Error 2 +``` + +* Restart the sculpt files download + + `./tool/depot/download genodelabs/pkg/x86_64/sculpt/2022-10-13` + +* Get the drivers, wifi, and ipxe files + + ``` +./tool/depot/download genodelabs/pkg/x86_64/drivers_managed-pc/2022-10-11 \ + genodelabs/pkg/x86_64/wifi/2022-10-13 \ + genodelabs/bin/x86_64/ipxe_nic_drv/2022-10-11 +``` + +* Create the build directory + + `./tool/create_builddir x86_64` + +* Edit the build configuration (required) + + `vi build/x86_64/etc/build.conf` + + * Enable parallel threads in make + + `MAKE += -j8` + + Note: if your cpu can't handle it, dial it back to -j4. + + * Enable ccache + + `CCACHE := yes` + + * Enable depot updates + + `RUN_OPT += --depot-auto-update` + + * Change from iso target to disk in QEMU_RUN_OPT + + `QEMU_RUN_OPT := --include power_on/qemu --include log/qemu --include image/disk` + + * Enable port repos by uncommenting them + * libports + * ports + * dde_linux + * dde_rump + * gems + * pc + * dde_bsd + * dde_ipxe + +* Prepare ports + + ``` +./tool/ports/prepare_port bash coreutils curl dde_ipxe dde_linux dde_rump e2fsprogs-lib gnupg grub2 jitterentropy libarchive libc libgcrypt libnl libpng libssh linux linux-firmware ncurses nova openssl stb ttf-bitstream-vera vim wpa_supplicant x86emu xz zlib +``` + +* Build the image + + `make -C build/x86_64 run/sculpt KERNEL=nova BOARD=pc` + +* Success is indicated by the creation of the image + + `Created image file var/run/sculpt.img (29140kiB)` + +### Test the created image on metal + +* Attach usb to host + +* Capture it in VirtualBox + +* Determine the assigned usb device + + ``` +sudo dmesg|grep sd +... +[ 7754.230860] sd 3:0:0:0: [sdb] Attached SCSI removable disk +``` + +* Determine the mounted drives + + `mount | grep sd` + + Note: this important as the order of assigned devices could change and you want to be sure to write to the usb and not a hard drive (virtual or otherwise). + +* Write the image to the target USB + + `sudo dd if=build/x86_64/var/run/sculpt.img of=/dev/sdb bs=1M conv=fsync` + +* Test it out with your target device (mine is T430) + +* Hope it works great! + +*post last updated 2022-12-29 11:53:00 -0600* \ No newline at end of file diff --git a/_posts/2022-12-30-building-sculpt-22.10-on-debian-11.6-no-desktop.md b/_posts/2022-12-30-building-sculpt-22.10-on-debian-11.6-no-desktop.md new file mode 100644 index 0000000..5ede477 --- /dev/null +++ b/_posts/2022-12-30-building-sculpt-22.10-on-debian-11.6-no-desktop.md @@ -0,0 +1,297 @@ +--- +layout: post +title: "Building Sculpt 22.10 on Debian 11.6 Bullseye without a Desktop" +categories: operating-systems genode sculpt +--- +Sheesh, live and learn. I didn't pay any attention to system requirements in the prior note [Building Sculpt 22.10 on Debian 11.6 Bullseye]({% post_url 2022-12-29-building-sculpt-22.10-on-debian-11.6 %}). I just glibly provisioned using a small portion of my available resources. In this note, I've corrected this oversight. The system requirements are much, much more modest than what I originally provisioned. There is no need for the overkill. + +This note is about building a bootable Sculpt OS 22.10 image using a Debian 11 "Bullseye" Guest OS running in VirtualBox without a desktop. If you were to include the desktop, expect that the system requirements would increase, but not by lot. I expect it would work with these same provisions, but would work better with more CPUs and RAM, as well as with a bigger allocation of hard disk space. + +Bottom line - The image can be built comfortably, in a reasonable amount of time (call it 15 minutes to download the toolchain, and source code, and do the build), on a system with 512 MB RAM, 1 CPU, 12 GB HDD, but it's faster with more resources provisioned, where CPU seems to be the biggest factor - more is better letting us use parallel threads in make. + + + +### Resources + +* Genode Operating System Framework Website [https://genode.org/](https://genode.org/) +* Genode OS Framework 22.05 Foundations Document [html](https://genode.org/documentation/genode-foundations/22.05/index.html) [pdf](https://genode.org/documentation/genode-foundations-22-05.pdf) +* Sculpt OS 22.10 Documentation [html](https://genode.org/documentation/articles/sculpt-22-10) [pdf](https://genode.org/documentation/sculpt-22-10.pdf) +* Mailing List [https://genode.org/community/mailing-lists](https://genode.org/community/mailing-lists) +* Genodians - Stories around the Genode Operating System [https://genodians.org/](https://genodians.org/) +* Git repository - [https://github.com/genodelabs/genode](https://github.com/genodelabs/genode) + +### Prerequisites + +* Host system - Mine is 2010 Mac Pro running Mojave +* VirtualBox w/extension pack - I'm running 6.1.40 + +### Download the Debian 11.6 Bullseye netinst.iso + + `aria2c https://gemmei.ftp.acc.umu.se/debian-cd/current/amd64/iso-cd/debian-11.6.0-amd64-netinst.iso` + +### Create a new debian virtualbox instance +* name: debian-11.6 +* 1 GB RAM (tested with 512 MB RAM) +* 2 CPU (tested with 1 CPU, no parallel threads with make) +* 12 GB HDD + +### Configure instance +* ssh port forwarding +* attach debian-11.6.0-amd64-netinst.iso + +### Install Debian + +Start the VM and let it boot to the installer. Choose Install and not Graphical Install to use the perfectly adequate and much faster text installer. + +Make the following choice for packages: + +* ssh +* standard system utilities + +### Boot the VM (even headless works fine) + +### ssh into the instance + +`ssh user@localhost -p 2222` + +### Check disk space + +``` +df -h +Filesystem Size Used Avail Use% Mounted on +udev 471M 0 471M 0% /dev +tmpfs 98M 500K 98M 1% /run +/dev/sda1 11G 1010M 9.3G 10% / +tmpfs 489M 0 489M 0% /dev/shm +tmpfs 5.0M 0 5.0M 0% /run/lock +tmpfs 98M 0 98M 0% /run/user/1000 + +``` + +### Prepare Debian for building Sculpt + +### Get rid of bracketed paste + +* as regular user + +`echo 'set enable-bracketed-paste off' >> ~/.inputrc` + +exit and reenter + +* as root + +``` +su - +echo 'set enable-bracketed-paste off' >> ~/.inputrc +``` + +exit and reenter + +#### Install Packages + +* update apt package list and upgrade packages + + `apt update && apt full-upgrade -y` + +* install basic dev tools + + Note: build-essential and gdisk are already installed) + + * basics + * build-essential + * htop + * sudo + * vim + * vbox dependencies + * dkms + * linux-headers + * build system dependencies see Genode Foundations - Getting Started + * autoconf + * autogen + * bison + * byacc + * ccache + * e2tools + * expect + * flex + * gawk + * gdisk + * git-gui + * gperf + * libsdl2-dev + * libxml2-utils + * qemu + * subversion + * xorriso + * xsltproc + + Note: apt will ignore already installed packages and different base selections such as Gnome vs Cinnamon may result in a different mix of already installed packages. + + ``` +apt install build-essential htop sudo vim \ + dkms linux-headers-$(uname -r) \ + autoconf autogen bison byacc ccache e2tools expect flex gawk \ + gdisk git-gui gperf libsdl2-dev libxml2-utils qemu subversion \ + xorriso xsltproc -y +``` + +* set vim as default editor + + `update-alternatives --config editor # pick vim.basic` + +* turn off mouse nonsense in vim as root and regular user + + `echo "set mouse-=a" >> ~/.vimrc` + +* Add user to sudo and enable sudo with no password + + ``` +visudo +%sudo ALL=(ALL:ALL) NOPASSWD:ALL +``` + +* add user to sudo group + + ``` + usermod -a -G sudo wsenn + exit + ``` + +* as regular user add sbin to path for build resize2fs requirement + + ``` +echo "export PATH=$PATH:/sbin" >> ~/.bashrc +``` + +* exit and reenter ssh + +`ssh user@localhost -p 2222` + +### Run htop to see system resources during the build + +* ssh into a second terminal instance and fire up htop + +``` +ssh user@localhost -p 2222 +htop +``` + +### Install Genode Toolchain and Source Code + +* Download the toolchain and install it in /usr/local/genode + + ``` +mkdir -p ~/Downloads +cd ~/Downloads +wget -O genode-toolchain-21.05-x86_64.tar.xz https://sourceforge.net/projects/genode/files/genode-toolchain/21.05/genode-toolchain-21.05-x86_64.tar.xz/download +sudo tar xvPf genode-toolchain-21.05-x86_64.tar.xz +``` + +* Clone the source code and switch to the 22.10 release branch + + ``` +cd +git clone https://github.com/genodelabs/genode.git +cd genode +git checkout -b sculpt-22.10 sculpt-22.10 +``` + +### Build Sculpt + +* Get the nova kernel files + + `./tool/depot/download genodelabs/bin/x86_64/base-nova/2022-10-11` + +* Get the sculpt files + + `./tool/depot/download genodelabs/pkg/x86_64/sculpt/2022-10-13` + +* Handle vim-minimal tarball error by just restarting + +You may see an error concerning vim-minimal (I do): + +``` +download genodelabs/src/vim-minimal/2022-08-30.tar.xz +download genodelabs/src/vim-minimal/2022-08-30.tar.xz.sig +xz: (stdin): Unexpected end of input +tar: Unexpected EOF in archive +tar: Unexpected EOF in archive +tar: Error is not recoverable: exiting now +make[1]: *** [/home/wsenn/genode/tool/depot/mk/downloader:45: /home/wsenn/genode/depot/genodelabs/src/vim-minimal/2022-08-30] Error 2 +``` + +* If so, just restart the download + + `./tool/depot/download genodelabs/pkg/x86_64/sculpt/2022-10-13` + +* Get the drivers, wifi, and ipxe files + + ``` +./tool/depot/download genodelabs/pkg/x86_64/drivers_managed-pc/2022-10-11 \ + genodelabs/pkg/x86_64/wifi/2022-10-13 \ + genodelabs/bin/x86_64/ipxe_nic_drv/2022-10-11 +``` + +* Create the build directory + + `./tool/create_builddir x86_64` + +* Edit the build configuration (required) + + `vi build/x86_64/etc/build.conf` + + * Enable parallel threads in make if you have more than one CPU + + `MAKE += -j4` + + * Enable ccache + + `CCACHE := yes` + + * Enable depot updates + + `RUN_OPT += --depot-auto-update` + + * Change from iso target to disk in QEMU_RUN_OPT + + `QEMU_RUN_OPT := --include power_on/qemu --include log/qemu --include image/disk` + + * Enable port repos by uncommenting them (all but world) + * libports + * ports + * dde_linux + * dde_rump + * gems + * pc + * dde_bsd + * dde_ipxe + +* Prepare ports + + ``` +./tool/ports/prepare_port bash coreutils curl dde_ipxe dde_linux dde_rump e2fsprogs-lib gnupg grub2 jitterentropy libarchive libc libgcrypt libnl libpng libssh linux linux-firmware ncurses nova openssl stb ttf-bitstream-vera vim wpa_supplicant x86emu xz zlib +``` + +* Build the image + + `make -C build/x86_64 run/sculpt KERNEL=nova BOARD=pc` + +* Success is indicated by the creation of the image + + `Created image file var/run/sculpt.img (29140kiB)` + +### Test the created image on metal + +* Transfer the image to the host + ``` + mkdir -p ~/Downloads + cd ~/Downloads + scp -P 2222 localhost:genode/build/x86_64/var/run/sculpt.img . + ``` +* Burn it to USB using your preferred tool (I use balena etcher or dd) + +* Test it out with your target device (mine is T430) + +* Hope it works great! + +*post last updated 2022-12-29 11:53:00 -0600* \ No newline at end of file diff --git a/_posts/2022-12-30-sculpt-os-22.10-a-truly-alternative-os.md b/_posts/2022-12-30-sculpt-os-22.10-a-truly-alternative-os.md new file mode 100644 index 0000000..e52861f --- /dev/null +++ b/_posts/2022-12-30-sculpt-os-22.10-a-truly-alternative-os.md @@ -0,0 +1,420 @@ +--- +layout: post +title: "Sculpt 22.10 - A Truly Alternative OS" +categories: operating-systems genode sculpt +--- +This note is about installing and running Sculpt OS 22.10 in VirtualBox. + +SculptOS is an operating system built out of components provided by the Genode Operating System Framework and as such it qualifies as a truly alternative operating system. These days, that's quite a feat. Most 'alternatives' are linux distros or flavors. This OS runs on a microkernel - Nova or any one of several other choices. It is decidedly not unix, windows, linux, haiku, beos, os/2 or any other mainstream os. + +Sculpt OS is made so that it is relatively straightforward, if not easy, to provide a secure computing environment where applications and services are built on a Trusted Computing Base... that is an application is provisioned explicitly to depend on a tree of components that are known to be trustworthy, and are sandboxed. It is similar in some ways to Qubes OS, but significantly different in others. + +The learning curve is steep. So, as I explore the environment and learn more about it, I'll post more of these notes. + +Here's the OS running stuff. + +![fortytwo](/assets/img/genode/42.png){: width="560" } + + + +### Resources + +* Genode Operating System Framework Website [https://genode.org/](https://genode.org/) +* Genode OS Framework 22.05 Foundations Document [html](https://genode.org/documentation/genode-foundations/22.05/index.html) [pdf](https://genode.org/documentation/genode-foundations-22-05.pdf) +* Sculpt OS 22.10 Documentation [html](https://genode.org/documentation/articles/sculpt-22-10) [pdf](https://genode.org/documentation/sculpt-22-10.pdf) +* Mailing List [https://genode.org/community/mailing-lists](https://genode.org/community/mailing-lists) +* Genodians - Stories around the Genode Operating System [https://genodians.org/](https://genodians.org/) +* Git repository - [https://github.com/genodelabs/genode](https://github.com/genodelabs/genode) + +### Prerequisites + +* Host system - Mine is 2010 Mac Pro running Mojave +* VirtualBox w/extension pack - I'm running 6.1.40 + +### Download the Sculpt OS Virtual Appliance + +While it may be possible to do a full installation of Sculpt OS via the standard installation ISO, the recommendation is to use the virtual appliance as it's preconfigured optimized for running in VirtualBox. + +#### Method 1 - Downloading in your browser + +* Browse to [https://genode.org](https://genode.org) +* Click the Download Button +* Click the Pre-built Sculpt OS images hyperlink +* Scroll Down to the Running Sculpt as VirtualBox appliance section +* Click the sculpt-22.10.ova link to download +* Click the signature link to download + +##### Method 2 - Using Aria/curl/wget to Download Directly + +``` + aria2c https://genode.org/files/sculpt/sculpt-22-10.ova + aria2c https://genode.org/files/sculpt/sculpt-22-10.ova.asc +``` + +### Check the signature + +``` +gpg --verify sculpt-22-10.ova.asc +... +gpg: Good signature from "Genode Labs Depot 17.05 " [unknown] +... +``` + + +### Import the ova into VirtualBox + +* In the file explorer, double click on the Sculpt-22.10.ova file + +* Read through the Appliance Settings, and click Import + +* Acknowledge the AGPLv3 license, and click Agree + +* Genode - Sculpt 22.10 will appear as a new VM in the VM Manager + +### Run Genode + +* Click Start in the VM Manager to run Genode +* See the Genode Splash Screen + +![one](/assets/img/genode/01.png) + +* See the Genode Leitzentrale (German for Control Center) + +![two](/assets/img/genode/02.png) + +That's it to get it running. The trick is in using it. + +### Using Genode + +In the note, we are going to perform a number of steps to learn about Sculpt. This isn't a particularly useful system, but it will suffice to illustrate some key concepts present in Sculpt and the Genode Framework. + +#### Steps we will undertake + +1. Learn about Leitzentrale +2. Set up storage +3. Set up networking +4. Set up genodelabs repository +5. Download a desktop background and configure it +6. Download a window manager and configure it +7. Download a demo and configure it +8. Download a fontfs and configure it +9. Download a unix-like system shell and configure it +10. Celebrate a job well done + +##### 1. Learn about Leitzentrale + +Sculpt is running and we are seeing Leitzentale, the control center. This is where we set things up and see the relationships between active components. + +Right now, the screen is showing us 5 buttons along the top - Settings on the left, File and Components in the center, and Network and Log, on the right. A vertical stack of 7 buttons in the center of the screen - Storage, USB, Hardware, Config, Info, GUI, and ram fs. + +The buttons are show in 4 states - Yellow is active with the focus, medium gray is capable of being selected, Light gray is only in the vertical stack and shows what is present in the system and capable of being selected, dark gray is not capable of being selected. + +Clicking on one of the buttons allows us to do work in the control center: + + * Settings - Change the Font size and the Keyboard Language + + ![three](/assets/img/genode/03.png) + + * Files - view the system as files + + ![four](/assets/img/genode/04.png) + + * Components - the default view + + ![two](/assets/img/genode/02.png) + + * Network - configure the network + + ![five](/assets/img/genode/05.png) + + * Log - view the system log in split-pane + + ![six](/assets/img/genode/06.png) + +The only change I am going to make is to increase the font size to make it easier to read the buttons and such. + +`Settings->Font size->Large` + +![seven](/assets/img/genode/07.png) + +##### 2. Set up storage + +In this step, we could choose one of the drives that are attached to the VM, but instead, we will choose the ramfs as it is available and will disappear when we are done, which is convenient in this case. + +`ram fs` + +![eight](/assets/img/genode/08.png) + +Then click Use. + +`ram fs->Use` + +![eighta](/assets/img/genode/08a.png) + +After you pick Use, the system will briefly display a Preparing button. After the Preparing button disappears, you will be left with a Depot button, showing that a depot is available on the ram fs. A depot is a location for storing downloaded assets and is needed for the system to be able to download applications. You should notice that a + sign has appeared at the top of the stack of buttons in the center of the screen. + +![nine](/assets/img/genode/09.png) + +Click on the ram fs button to close the opened view. + +![ten](/assets/img/genode/10.png) + +As you can see, depot is dependent on ram fs. + +##### 3. Set up networking + +To configure networking, just click Network and Wired. + +`Network->Wired` + +![eleven](/assets/img/genode/11.png) + +It takes a couple of seconds for the nic to configure. Once the nic is configured, the IP address should appear, and a nic router and nic drv button should appear in Leitzentrale as shown above. + + +##### 4. Set up genodelabs repository + +Now that we have a ram fs based depot available and network connectivity, let's configure the genodelabs software repository. To do so, click on the + sign to add components to Leitzentrale and Sculpt OS. + +`+` + +![twelve](/assets/img/genode/12.png) + +When you click on the + sign, 4 choices appear, shared fs, usb devices rom, vm fs, and Depot ... The correct choice is Depot ..., the others are something you would have needed to set up manually. Click on Depot... + +`+->Depot...` + +![thirteen](/assets/img/genode/13.png) + +When you click on Depot... before having added any repos, Selection... appears as the only choice. Click it. + +`+->Depot...->Selection...` + +![fourteen](/assets/img/genode/14.png) + +Now, a number of available repos is shown. We will stick to genodelabs for this note, the others are people at genodelabs who have made their personal repos available. Click on genodelabs. + +`+->Depot...->Selection...->genodelabs` + +![fifteen](/assets/img/genode/15.png) + +The progress of the download will appear briefly in the bottom left. After the repo is added, it will show as a filled in yellow box. This adds genodelabs to the Depot. Click anywhere outside of the dialog to close out the add component dialog. + +![sixteen](/assets/img/genode/16.png) + +##### 5. Download a desktop background and configure it + +With a software repository configured, we can download a desktop background and begin seeing what Sculpt and Genode have to offer. + +First select the genode labs repository. Click on +, then Depot, then genodelabs + +`+->Depot...->genodelabs...` + +![seventeen](/assets/img/genode/17.png) + +Now we see what categories of software are available to add to the system. In this case, we select GUI. + +`...->genodelabs->GUI` + +![eighteen](/assets/img/genode/18.png) + +A number of GUI dependent applications are shown, we want the sticks blue backdrop. Select it. + +`...->genodelabs->GUI->sticks blue backdrop...` + +![nineteen](/assets/img/genode/19.png) + +The dialog will change and the only option is Install, click the Button. + +`...->genodelabs->GUI->sticks blue backdrop...->Install` + +![twenty](/assets/img/genode/20.png) + +The package will be downloaded and installed to the ram fs and we will be presented with the configuration dialog for the application. The GUI configuration item shows 4 choices, system GUI server, desktop lock screen, desktop background, and keyboard focus. These are all capabilities present in the Genode framework and are part of the trusted computing base. At this point, we are being asked which capability we want the sticks blue backdrop application to have access to. The obvious choice is the right choice, desktop background. Select it. + +`...->sticks blue backdrop...->GUI->desktop background` + +![twentyone](/assets/img/genode/21.png) + +After selecting the capability, GUI will be replaced by the capability and show as a filled yellow circle. and we can add the new component by clicking on Add Component. + +`...->sticks blue backdrop...->Add Component` + +![twentytwo](/assets/img/genode/22.png) + + +Take a moment to consider this. We have now extended the trusted computing base of our OS. We have added the desktop background and given it permission to serve as our background by adding the capability. Not too much exposure, for sure, but the surface has been extended. This is made explicitly visible in Leitzentrale - see that sticks blue background has been added to the GUI node. + +![twentythree](/assets/img/genode/23.png) + +Take note of the fact that we see the background through the Leitzentrale. To remove the Leitzentrale from view and see Sculpt OS with our desktop background in all its glory, press F12 to toggle Leitzentrale off. + +`F12` + +![twentyfour](/assets/img/genode/24.png) + +Press `F12` again to toggle Leitzentrale on again and continue on in the note. + + +##### 6. Download a window manager and configure it + +A desktop background with a configured ram fs, nic, and depot make for a pretty paltry os. Let's start adding some truly useful components. Let's begin by adding a window manager to make windows pretty and functional. I will not show images for as many intermediary steps from here on out, but only those that are particularly informative, but I will describe every step. + +Navigate to the list of GUI applications for genodelabs. + +`+->Depot...->genodelabs...->GUI` + +![twentyfive](/assets/img/genode/25.png) + +Here we see our desktop background and several other choices. Pick themed wm... + +`+->Depot...->genodelabs...->GUI->themed wm...` + +![twentysix](/assets/img/genode/26.png) + +Click Install. + +`...->themed wm...->Install` + + +Configure the capabilities we want to expose to the window manager (just know that we only trust this component because we trust genodelabs). I will show the first two and then describe the others. + +Select keyboard focus for the GUI (focus) capability. We want the window manager to handle the keyboard focus. + +`...->GUI (focus)->keyboard focus` + +![twentyseven](/assets/img/genode/27.png) + +Select system gui server for the gui capability. We want the window manager to work with the system GUI server to do its thing. + +`...->GUI->system GUI server` + +![twentyeight](/assets/img/genode/28.png) + +Select pointer shape for the Report (shape) capability in order to control the mouse pointer, global clipboard for the Report (clipboard) to be able to write to the global clipboard, and global clipboard for the ROM (clipboard) capability to be able to read the global clipboard. + +![twentynine](/assets/img/genode/29.png) + +Our component view has been affected and a themed wm node added to the GUI node. + +![thirty](/assets/img/genode/30.png) + + +##### 7. Download a demo and configure it + +Now that we have a window manager, let's get an app to run a window. In this case we will get the nano3d demo. + +This time, I will be even terser with the explanation. Click the add component button, select Depot, then genode labs, then demos. + +`+->Depot...->genodelabs...->Demos...` + +Pick nano3d and click the Install button to install it. + +To configure the application, select GUI and themed wm as the GUI capability. + +`nano3d->GUI->themed wm` + +Click Add Component to add the component into our Sculpt'ed OS. You will see it running behind Leitzentrale and that nano3d has been added to the themed wm node. + +![thirtyone](/assets/img/genode/31.png) + +Toggle Leitzentrale with F12 to see nano3d running in Sculpt OS under the control of the themed wm. + +`F12` + +![thirtytwo](/assets/img/genode/32.png) + +Just for fun, let's remove the background to get a clearer look at the demo. + +Press F12 and in Leitzentrale, click on the sticks blue backdrop node, and select Remove. + +![thirtythree](/assets/img/genode/33.png) + +This results in the backdrop node being removed. + +![thirtyfour](/assets/img/genode/34.png) + +Press F12 to toggle Leitzentrale and see the demo without the distraction of the background, feel free to move it around and see the wm do its magic. + +`F12` + +![thirtyfive](/assets/img/genode/35.png) + +When you get tired of it, press F12 again, and remove nano3d. By the way, any component you remove is still available without your having to redownload it, just navigate to it again and it will skip the download and just ask you to reconfigure the capabilities. + +##### 8. Download a fontfs and configure it + +We need a fontfs as a dependency of the next step. Even terser. + +Install the font fs by adding the component. + +`+->Depot...->genodelabs...->GUI...->font fs...` + +Then select system font config as its ROM (config) capability and Add the component into our Sculpted OS. The added node will be attached to the info node and its only capability will be reading the system font configuration information - not much security risk there. + +The result will appear as follows + +![thirtysix](/assets/img/genode/36.png) + +##### 9. Download a unix-like system shell and configure it + +Now, let's add a real and useful application to our OS. The system as delivered comes with a simple shell. To access that shell, click ram fs and inspect. When you do so, the Leitzentrale will add in a new node into the top row of buttons, called inspect. + +![thirtyseven](/assets/img/genode/37.png) + +Click it and the inspect shell will be revealed. + +![thirtyeight](/assets/img/genode/38.png) + +Carefully look around and when you're done, click the Inspect node to return to the Leitzentrale. + +To remove the Inspect capability, just click on ram fs, then Inspect and it will be removed (the button, which was yellow after you enabled it, will return to the normal gray). + +The inspect shell is useful for a number of system related tasks, but a more powerful shell that offers up a larger number of unix-like tools, is what we're after. Tersest yet on the instruction front. + +`+->Depot...->genodelabs...->Tools...->system shell...` + +* themed wm +* writeable system configuration +* read-only system reports +* ram fs +* fonts fs +* default vim configuration +* themed wm +* themed wm +* custom virtual memory objects + +![thirtynine](/assets/img/genode/39.png) + +Add the component and it will appear behind Leitzentrale. Press F12 to reveal it and play with it in sculpt. A couple of observations, the system shell component is running in the wm, it runs in a window. The inspect shell was part of Leitzentrale and did not have a window per se. + +![forty](/assets/img/genode/40.png) + +Also, if you close the window and return to Leitzentrale, you can click on the system shell node and click Restart to restart the shell. + +Here is what the nodes look like now + +![fortyone](/assets/img/genode/41.png) + + +##### 10. Celebrate a job well done + +The note has led you through a basic tutorial of how to start using Sculpt OS. Sculpt OS is built on the Genode Operating System Framework. It allows you, the user to exert fine-grained control over your operating environment. By placing new applications into the environment with care you can be assured that your components execute in a trusted computing base that is fairly minimal and severely limit the amount of attackable surface area you expose. + +##### Shutting down + +Well, here you have kindof caught me out. I don't really know how to shut this thing down. I've asked on the genode mailing list, but I still haven't quite figured it out. + +So, in lieu of a better approach, we will reset Sculpt and sneak in a power off while it's rebooting :). + +In either Inspect shell or System Shell, vim config/system and change the system state to "reset" + +`` + +When you write the changes `ESC:wq`, the system will reboot, power off the VM before it restarts (Ignore the fatal keyboard error)! + +I'll prolly update this note over time, but I wanted it out there while it was still fresh. + +Ciao! + +*post last updated 2022-12-29 11:53:00 -0600* \ No newline at end of file diff --git a/_posts/2023-01-07-fossil-on-truenas.md b/_posts/2023-01-07-fossil-on-truenas.md new file mode 100644 index 0000000..65486d0 --- /dev/null +++ b/_posts/2023-01-07-fossil-on-truenas.md @@ -0,0 +1,231 @@ +--- +layout: post +title: "Installing and running Fossil on TrueNAS Core" +categories: operating-systems truenas-core fossil +--- +This note is about installing and running Fossil SCM on TrueNAS Core. + +Fossil is brought to us by the same people who developed SQLite. It was created to serve their needs, but is useful to everybody with a similar set of needs (pretty much any dev team). According to the fossil folks over at [https://fossil-scm.org](https://fossil-scm.org), "Fossil is a simple, high-reliability, distributed software configuration management system..." To mme, it's my git-killer. + +I have been running Fossil for about a year to see if it was worth replacing git for my own use. After this year, while I still like git and I will continue to use it for disposable repos, I have completely jumped ship for my own repos and won't be going back to hosting them on anything else anytime soon. Fossil is very lightweight, fast and responsive, has a fantastic server side ui, and is slightly more intuitive to use. It is also easier to recover from when things go wonky. + + + +I will be posting more about TrueNAS Core in the near future, as I learn more about it (so far, it rocks!). + +### Requirements + +* A host to work from (I'm using Mac Pro, Mojave) +* A TrueNAS Core instance (mine is TrueNAS-13.0-U3.1 running on a Lenovo Thinkcentre m92p w/lots of memory, disks, a working network, etc. + +### Overview + +This is a quick guide for getting fossil up and running in a FreeBSD 13.1 jail, running in TrueNAS Core instance. The steps are: + +* Create the Jail + + * Start the add jail wizard + * Name it and choose the FreeBSD Release version + * Configure the network + * Review the Summary and hit Submit +* Configure the Jail + * Start the Jail + * Open the Jail's Shell + * Add a new user + * Enable and start sshd + * Get ssh working + * Do updates and upgrades + * Install sudo and configure + * Add a mount point for the fossils directory + * Mount the fossil directory in the jail in TrueNAS UI + * Stop the jail + * Add the mount point + * Start the jail + * Install fossil + * Add a tweak to rc file + * Start fossil + * Browse to the repos + +#### Create the Jail + +##### Start the add jail wizeard +* Select Jails->Add->Wizard + + +##### Name it and choose the FreeBSD Release version + +``` + Name: fossil + Jail Type: Default (Clone Jail) + Release 13.1 RELEASE + Next +``` + +##### Configure the network + +``` + DHCP Autoconfigure IPv4 (it will pick VNET and Berkley Packet Filter) + Next +``` + +##### Review the Summary and hit Submit + +``` + Jail Summary + + Jail Name: fossil + Release: 13.1-RELEASE + DHCP Autoconfigure IPv4: Yes + VNET Virtual Networking: Yes + NAT Autoconfigure IPv4: No +``` + +* Click Submit + +#### Configure the Jail + +##### Start the Jail + +* Select the jail and click the Start button + +##### Open the Jail's Shell + +* Select the jail and click Shell + +##### Add a user (add them to wheel) + +` adduser` + +##### Enable and start sshd for the jail + +``` +sysrc sshd_enable="YES" +service sshd start +``` + +##### Get sshd working + +* Get the ip address for the jail + +``` +ifconfig +... +192.168.254.24 +... +``` + +* On the host add an entry to /etc/hosts + +`192.168.254.24 fossil fossil.sentech` + +* Copy your ssh key over + +`ssh-copy-id fossil` + +* ssh in, become root, and change the password + + ``` +ssh fossil +su - +passwd +``` + +* turn DNS off for sshd - it adds latency + +``` +vi /etc/ssh/sshd_config +UseDNS no +``` + +* Restart sshd and relogin + +``` +service sshd restart +exit + +ssh fossil +``` + +##### Do updates and upgrades + +``` +su - +pkg update +pkg upgrade -y +``` + +##### Install sudo and configure + +``` +pkg install sudo +visudo +%wheel ALL=(ALL:ALL) NOPASSWD: ALL +exit +sudo ls +``` + +##### Add a mount point for the fossils directory + +`sudo mkdir -p /zfs/fossils` + +##### Mount the fossil directory in the jail in the TrueNAS UI + +###### Stop the jail using TrueNAS UI + +###### add mountpoint for /zfs/fossils + +``` +Source: /mnt/zfs/fossils +Destination: /zfs/fossils +``` + +* Click Submit + +###### Start the jail using TrueNAS UI + +Note: the filesystem will appear to be a regular directory, +do zfs operations in TrueNas... + +* If your fossils are owned by a user, chown them to nobody + +``` +ssh fossil +sudo chown -R nobody:nobody /zfs/fossils +``` + +##### Install fossil + +`pkg install fossil` + + +##### Add a tweak to rc file + +* Add support for fossil_errorlog variable to fossil_args + +Put the following with the other fossil_args + +``` +vi /usr/local/etc/rc.d/fossil +[ -n "${fossil_errorlog}" ] && fossil_args="${fossil_args} --errorlog ${fossil_errorlog}" +``` + +* Configure using rc vars + +``` +sysrc fossil_enable="YES" +sysrc fossil_repolist="YES" +sysrc fossil_directory="/zfs/fossils" +sysrc fossil_listenall="YES" +sysrc fossil_errorlog="/zfs/fossils/fossil.log" +``` + +##### Start fossil +service fossil start + +##### Browse to the repos +http://fossil:8080 + +Tool around and convince yourself things are working and celebrate! + + +*post last updated 2023-01-07 15:36:00 -0600* diff --git a/_posts/2023-01-16-dragonfly.md b/_posts/2023-01-16-dragonfly.md new file mode 100644 index 0000000..1e504e9 --- /dev/null +++ b/_posts/2023-01-16-dragonfly.md @@ -0,0 +1,545 @@ +--- +layout: post +title: "Installing and running DragonFly BSD 6.4" +categories: operating-systems bsd dragonfly-bsd +--- +This note is about installing and running DragonFly BSD 6.4 + +![one](/assets/img/dragonfly/01.jpeg) + +DragonFly BSD from [https://dragonflybsd.org](https://dragonflybsd.org) is a BSD :). As such, it is a rock and the userland is sane. It was forked from FreeBSD long ago and is renowned for its HAMMER FS. I started the exploration with the intention of learning more about HAMMER and have enjoyed the journey. + + + +Link to high res image: + +* [dragonfly-running on metal](/assets/img/dragonfly/01-big.jpeg) + +I like DragonFly BSD, but there is a bit of a learning curve, even for someone used to FreeBSD... I say this as someone who has been using FreeBSD for more than a decade and while there is some overlap, it's still pretty different. Maybe if I had used an earlier version of FreeBSD it would seem more familiar, but I started with 8. + +### Requirements + +---- + +* A machine to run it on - I put it on my Dell Optiplex 755, Core 2 Quad  CPU   Q9550  @ 2.83GHz w/8GB RAM, and a 240 GB SSD +* DragonFly BSD 6.4 USB image from [https://www.dragonflybsd.org/download/](https://www.dragonflybsd.org/download/) + +### Resources + +---- + +* DragonFly BSD Handbook [https://www.dragonflybsd.org/docs/handbook/](https://www.dragonflybsd.org/docs/handbook/) +* Mailing List and IRC [https://www.dragonflybsd.org/mailinglists/](https://www.dragonflybsd.org/mailinglists/) +* DragonFly Digest [https://www.dragonflydigest.com/](https://www.dragonflydigest.com/) + + +### Getting started + +---- + +#### Create a workarea on your existing system + +``` +mkdir -p ~/Downloads/dragonfly +cd ~/Downloads/dragonfly/ +``` + +#### Download the image, decompress it, and verify it + +Note that md5's of the releases are available at [http://avalon.dragonflybsd.org/iso-images/md5.txt](http://avalon.dragonflybsd.org/iso-images/md5.txt) + +MD5 (dfly-x86_64-6.4.0_REL.img) = b3b23e1a18292c46643f8df435e4ab68 + +``` +aria2c https://mirror-master.dragonflybsd.org/iso-images/dfly-x86_64-6.4.0_REL.img.bz2 +bzip2 -d dfly-x86_64-6.4.0_REL.img.bz2 +md5 dfly-x86_64-6.4.0_REL.img +MD5 (dfly-x86_64-6.4.0_REL.img) = b3b23e1a18292c46643f8df435e4ab68 +``` +#### Burn it to USB - I use Balena Etcher + + +### Installing DragonFly BSD + +---- + +#### Boot to the USB stick + +#### DragonFly Boot Menu + +The DragonFly Boot Menu will appear after a few seconds. + +* Choose `1. Boot DragonFly [kernel]` + +The bootup process takes a minute or so... be patient. + +#### Running the DragonFly BSD Installer + +---- + +* login as `installer` with no password + + +The installer will begin and display its dialogs: + +##### Welcome screen and staring the installation + +* Welcome to DragonFly BSD + + A brief description of Dragonfly BSD is presented. + + * Choose `Install DragonFly BSD` + +* Begin Installation + + The installer describes what it's about to do. + + * Again, choose `Install DragonFly BSD` + +##### Disk Setup + +* UEFI or legacy BIOS + + * Choose `Legacy BIOS` (or UEFI, if you have it) + +* Select Disk - a list of disks is presented. + + * Choose `da0: 244198MB` + +* How Much Disk? - asks you how much of the disk (all of it, or just part of it). + + * Choose `Use Entire Disk` + +* Are you absolutely sure? + + * Acknowledge by choosing `OK` + +* Information + + ``` +The disk +da0: 244198MB +was formatted. +``` + * Acknowledge by choosing `OK` + +##### File System Setup + +* Select file system + * Choose `Use HAMMER2` as recommended. +* Create Subpartitions + + ``` +/boot 1024M +swap 16G +/ 166G +/build * +``` + * Choose `Accept and Create` + +The filesystem is created. + +##### OS Installation + +* Install OS + + * Choose `Begin Installing Files` + + It will take a couple of minutes for the operating system files to be written to disk. + +##### Boot Block Installation + +* Install Bootblock(s) + + ``` + Disk Drive Install Bootblock? Packet Mode? + [da0 ] [X] [X] + ``` + * Choose Accept and Install Bootblocks + + * Information + + `Bootblocks were successfully installed!` + + * Acknowledge by choosing `OK` + +##### Completing the installation + +* DragonFly BSD is Installed! + +The base installation, now it's time to configure the system. + +* Choose `Configure this system` + +#### Configuring the newly installed system + +---- + +#### Timezone configuration + +* Choose `Select Timezone` + +* Local or UTC (Greenwich Mean Time) clock + + * Choose `YES` + +* Select Timezone + + * Choose `America` + + * Choose `Chicago` + + * Information + + ``` +The Time Zone has been set to +/mnt/usr/share/zoneinfo/America/Chicago. +``` + * Acknowledge by choosing `OK` + +##### Date and Time configuration + +* Set date and time + + * Set Time/Date as you like + + * Confirm your choices by choosing `OK` + + * Information + + `The time and date have been set.` + + * Acknowledge by choosing `OK` + +##### Keyboard map configuration + +* Choose `Set keyboard map` + + * Select Keyboard Map + + * Choose `us.pc-ctrl-kbd` + +##### Root password configuration + +* Choose `Set root password` + + * Set Root Password + + * Enter root password + + * Enter root password again + + * Choose `Accept and Set Password` + + * Information + + `The root password has been set.` + + * Acknowledge by choosing `OK` + +##### Additional user configuration + +* Choose `Add a user` + + * Add user + + * + ``` + Username wsenn +Real Name Will Senn +Password ** +Password again ** +Shell /bin/sh +Home Directory /home/wsenn +User ID (leave blank) +Login Group (leave blank) +Other Group Membership [wheel,video] +``` + + * Choose `Accept and Add` + + * Information + + `The user 'wsenn' was added.` + + * Acknowledge by choosing `OK` + +##### Network configuration + +* Choose `Configure network interfaces` + + * Assign IP Address + + * choose `em0` + + * Use DHCP + + * Choose `Use DHCP` + + It takes a few seconds to initialize the nic. + + * Information + + `Lots of em0 info is displayed` + + * Acknowledge by choosing `OK` + +##### Hostname and domain configuration + +* Choose `Configure hostname and domain` + + * Enter your hostname + + * Enter your domain + + * Confirm your selections by choosing `OK` + +##### Console font configuration (optional) + +Probably don't need to change it but if you do... + +Choose cp437 fonts + +##### Screen map configuration + +Probably don't need to change it but if you do... + +Choose the iso-8859-1 to cp437 screen map + +##### Wrapping up configuration + +* Choose `Return to Welcome Screen` + +* Choose `Reboot This Computer` + + * Reboot + + * Choose `Reboot` + +* Remove the USB Stick and reboot + +I had to power cycle the computer at this point. + +### Running DragonFly BSD + +---- + +The computer will reboot and display the Dragonfly BSD Boot manager. + +``` +F1 DF/FBSD +Default: F1 +``` + +After about 10 seconds, the computer will boot the default entry (DragonFly BSD). + +The Dragonfly BSD Boot menu will appear and a countdown timer will count down before booting the default entry - `1. DragonFly BSD (kernel)`. + + +#### Login as regular user + +``` +login: wsenn +password: +``` + +#### Get the ip + +``` +ifconfig +... +192.168.254.12 +... +``` + +#### Temporarily change ssh to allow password based logins + +``` +su - + +vi /etc/ssh/sshd_config +PasswordAuthentication yes +service sshd restart +``` + +#### Copy over your user key (if you plan to log in remotely) + +on remote host + +`ssh-copy-id loki` + +#### Change ssh back to only allow key based logins + +on loki + +``` +su - + +vi /etc/ssh/sshd_config +PasswordAuthentication no +service sshd restart +``` + +#### Log in over ssh + +``` +ssh loki +``` + +#### Do updates and upgrade + +Note: 6.4.0 ships with an old version of pkg and the upgrade fails as a result and blows away the pkg configuration. The simple solution is to copy the sample configuration over and rerun the upgrade as described below. + +``` +pkg update +pkg upgrade +``` + +This results in the following error: + +``` +Updating Avalon repository catalogue... +Avalon repository is up to date. +All repositories are up to date. +New version of pkg detected; it needs to be installed first. +The following 1 package(s) will be affected (of 0 checked): + +Installed packages to be UPGRADED: + pkg: 1.14.4 -> 1.18.4 [Avalon] + +Number of packages to be upgraded: 1 + +3 MiB to be downloaded. + +Proceed with this action? [y/N]: Y +[1/1] Fetching pkg-1.18.4.pkg: 100% 3 MiB 790.6kB/s 00:04 +Checking integrity... done (0 conflicting) +[1/1] Upgrading pkg from 1.14.4 to 1.18.4... +[1/1] Extracting pkg-1.18.4: 100% +pkg: Failed to execute lua script: [string "-- args: etc/pkg.conf.sample..."]:12: attempt to call a nil value (field 'stat') +pkg: lua script failed +No active remote repositories configured. +``` + +##### Restore the borked configuration + +`cp /usr/local/etc/pkg/repos/df-latest.conf.sample /usr/local/etc/pkg/repos/df-latest.conf` + +##### Rerun the upgrade step + +`pkg upgrade` + +This time, things ought to be good. + +#### Install some useful baseline packages + +``` +pkg install sudo vim bash sysrc +visudo +uncomment +%wheel ALL=(ALL:ALL) NOPASSWD: ALL + +exit +``` + +#### Change the user shell to bash + +as user + +``` +chsh +/usr/local/bin/bash +``` + + +#### Install a Windowing Environment + +``` +sudo -s +pkg install xorg xf86-input-evdev windowmaker leafpad nautilus chromium slim slim-themes + +echo "exec wmaker" > .xinitrc + +sysrc slim_enable="YES" +sysrc dbus_enable="YES" +sysrc snd_hda_load="YES" + +sysrc -f /boot/loader.conf autoboot_delay="1" + +sudo shutdown -r now +``` +should restart with slim + +#### Login, fire up Chrome and youtube, stuff oughta just work + +* Right-click on the desktop, open a terminal, then + +`chrome` + + +logging out of windowmaker takes 10 seconds then beep + + +### Post installation rigamarole + +---- + +I have an ASUS ATI Radeon HD 650 Silence video card. I did the following to learn more about it. + +``` +kldload radeon +kldstat +Id Refs Address Size Name + 1 26 0xffffffff80200000 1ada9a8 kernel + 2 1 0xffffffff81cdb000 7c550 ehci.ko + 3 1 0xffffffff81d58000 8a1f0 xhci.ko + 4 1 0xffffffff82600000 16000 ums.ko + 5 1 0xffffffff82616000 19a7000 radeon.ko + 6 1 0xffffffff83fbd000 baa000 drm.ko + 7 1 0xffffffff84b67000 1f000 iicbus.ko + 8 1 0xffffffff84b86000 a000 radeonkmsfw_CAICOS_pfp.ko + 9 1 0xffffffff84b90000 b000 radeonkmsfw_CAICOS_me.ko +10 1 0xffffffff84b9b000 a000 radeonkmsfw_BTC_rlc.ko +11 1 0xffffffff84ba5000 f000 radeonkmsfw_CAICOS_mc.ko +12 1 0xffffffff84bb4000 f000 radeonkmsfw_CAICOS_smc.ko +13 1 0xffffffff84bc3000 3b000 radeonkmsfw_SUMO_uvd.ko +``` + +I have onboard sound. Here's the exploration. + +``` +kldload snd_hda +cat /dev/random > /dev/dsp +``` + +Static sound ensues :). + +``` +cat /dev/sndstat +Installed devices: +pcm0: (play/rec) default +pcm1: (play/rec) +pcm2: (play) + +dmesg|grep pcm +pcm0: at nid 18 and 20 on hdaa0 +pcm1: at nid 17 and 21 on hdaa0 +pcm2: at nid 3 on hdaa1 +``` + +I mucked up loader.conf and booting became an issue. Here's the fix. + +* insert usb and boot to it +* select r for ramdisk +* in the booted system, `mount /dev/da0s1a` +* find and edit `loader.conf` in /mnt +* reboot + + +I originally had a janky mouse, the fix was to install `xf86-input-evdev` + +To enable X11 over ssh +sudo vi /etc/ssh/sshd_config +X11Forwarding yes + +*post last updated 2023-01-19 13:12:00 -0600* diff --git a/_posts/2023-01-23-fossil-merging-binary-files.markdown b/_posts/2023-01-23-fossil-merging-binary-files.markdown new file mode 100644 index 0000000..dea7fc2 --- /dev/null +++ b/_posts/2023-01-23-fossil-merging-binary-files.markdown @@ -0,0 +1,202 @@ +--- +layout: post +title: "Merging binary files in Fossil - to do or not to do?" +categories: fossil merging +--- + +This is a note about merging (or not merging) binary files in Fossil. + +## Scenario + +Two users Marilyn and Jim update to latest and begin working on their versions of the repository. Marilyn, changes a binary file called DEMO and commits her changes. Meanwhile, Jim changes his DEMO and tries to commit his changes. When he does so, he is warned that a fork would result from his commit. + +**Current Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3)) + id1((2))-..->STOP[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + +In this note, I look at different solutions to the problems arising when two different committers try to commit changes to the same binary file. This is just a note, not a published solution set. It presents my current thinking on the matter and will inevitably evolve as my understanding of Fossil grows. + + + +Here's the forum discussion that led to the current exploration: + +[https://fossil-scm.org/forum/forumpost/6d7e1a942e](https://fossil-scm.org/forum/forumpost/6d7e1a942e) + +In diagram 1.1 above, both Jim and Marilyn start with commit 2. Marilyn edits the binary, adds it and commits, creating commit 3. Jim, meanwhile, edits the same binary file, adds it and tries to commit. But, fossil warns him that the commit could result in a fork and tells him to either branch or add --allow-fork to his command. + +At this point, Jim has some reasonable options: + +1. He can stash his work, revert the changes, update to commit 3 (with Marilyn's changes), pop his stash, add and commit his changes as commit 4. +2. He can revert his changes and accept Marilyn's work by updating to commit 3. +3. He can fork the repository and allow multiple threads of development - commit 3 and 4. + +There are probably other scenarios possible, but these are the most reasonable. + +### Option 1 - Jim wants his changes to be the latest + +**Current Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3)) + id1((2))-..->STOP[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + + +**Desired Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3))-->id3((4))-.->STOP[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + + +Where 4 is Jim's commit. + +To achieve this desired situation, the following commands are executed by Jim: + +``` +fossil stash save -m "stashing j's changes" +fossil update +fossil stash pop +fossil add . +fossil commit -m "j's changes" +``` + +### Option 2 - Jim wants Marilyn's changes to be the latest + +**Current Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3)) + id1((2))-..->STOP[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + + +**Desired Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3))-.->STOP[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + +This is the simplest solution. Jim just reverts his changes and updates to Marilyn's commit, 3. + +To achieve this desired situation, the following commands are executed by Jim: + +``` +fossil revert +fossil update +``` + +### Option 3 - Jim wants to create a fork + +**Current Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3)) + id1((2))-..->STOP[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + + +**Desired Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3))-..->STOP[ ] + id1((2))--->id4((4))-.->STOP2[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 + style STOP2 fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + + +This is not what I would call an ideal situation as it will likely lead to a need to merge the fork later, but it's simple enough to create: + +``` +fossil commit --allow-fork -m "j's change" +``` + +#### Merging the fork + +To merge the fork, just decide which fork needs to be merged and do it. In this case, Jim decides to merge Marilyn's fork back into his, with his changes being latest. + +**Current Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3))-..->STOP[ ] + id1((2))--->id4((4))-.->STOP2[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 + style STOP2 fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + + + +**Desired Situation** + +{% raw %} +
+flowchart LR + START[ ]-->id1((2))-->id2((3))--->id5((5)) + id1((2))--->id4((4))-->id5((5))-.->STOP[ ] + style START fill-opacity:0, stroke-opacity:0 + style STOP fill-opacity:0, stroke-opacity:0 +
+{% endraw %} + +To achieve this desired situation, the following commands are executed by Jim: + +``` +fossil timeline +20:12:26 [3d37827c81] *CURRENT* j's changes (user: Jim tags: trunk) +20:11:46 [02a9bbd315] m's changes (user: Marilyn tags: trunk) + +fossil checkout 02a9bbd315 +DEMO + +# get j's changed DEMO +fossil update 3d37827c81 DEMO +fossil merge +fossil add . +fossil commit -m "merging j's changes" +``` + +This is very much a note in progress. As I learn more and find better ways of doing things, I will update it. + +\- will diff --git a/_posts/2023-01-23-mermaid.md b/_posts/2023-01-23-mermaid.md new file mode 100644 index 0000000..87c90a5 --- /dev/null +++ b/_posts/2023-01-23-mermaid.md @@ -0,0 +1,173 @@ +--- +layout: post +title: "Enabling Mermaid in Jekyll without a Plugin" +categories: github jekyll mermaid +--- +Mermaid is a javascript tool to generate graphics - diagrams and charts and such using markdown-like syntax. This note describes adding it into a jekyll site such as mine [https://decuser.github.io](https://decuser.github.io) + +{% raw %} +
+flowchart LR + id1((a)) --> id2((b)) & c--> d +
+{% endraw %} + +Flowchart Example + + + +## Resources + +* mermaid-js github repo - [https://github.com/mermaid-js/mermaid](https://github.com/mermaid-js/mermaid) +* jekyll home - [https://jekyllrb.com](https://jekyllrb.com/) +* mermaid flowchart basics - [https://mermaid.js.org/syntax/flowchart.html](https://mermaid.js.org/syntax/flowchart.html) + + +## Installation + +The installation of mermaid is straightforward and does not require a plugin. Just add the .js and .map file of your chosen distribution to your assets folder, add a script tag to the _layouts/_post.html file, and then use the appropriate incantation in your posts. + +### Install the mermaid-js dist files + +The current version of Mermaid, at the time of this post, is 9.3.0. It is available at: + +[https://unpkg.com/browse/mermaid@9.3.0/dist](https://unpkg.com/browse/mermaid@9.3.0/dist) + +The files I chose to install were: + +* mermaid.js +* mermaid.js.map +* mermaid.min.js +* mermaid.min.js.map + +Downloading these specific files was a little tricky. So, for future reference, here's what I did (may change over time): + +1. Browse to the dist directory +2. Locate the file of interest - say, `mermaid.js` +3. Click on its link to open it's page +4. Right-click on View Raw and Save Link As... +5. Put the file where you like + +Using aria2, I just downloaded them directly: + +``` +mkdir ~/Downloads/mermaid +cd ~/Downloads/mermaid +aria2c https://unpkg.com/mermaid@9.3.0/dist/mermaid.js +aria2c https://unpkg.com/mermaid@9.3.0/dist/mermaid.js.map +aria2c https://unpkg.com/mermaid@9.3.0/dist/mermaid.min.js +aria2c https://unpkg.com/mermaid@9.3.0/dist/mermaid.min.js.map +``` + +Then in the repo, I created a folder for them and copied them in: + +``` +cd ~/sandboxes-git/decuser.github.io +mkdir -p assets/mermaid-9.3.0 +cp ~/Downloads/mermaid/* assets/mermaid-9.3.0 +``` + +### Modify `_layouts/post.html` and `index.html` + +Add a script tag for mermaid into post.html and index.html just after the jekyll header: + +`` + +### Edit a post with mermaid markup + +In a post, just add some mermaid markup. This creates a digraph: + +``` +{% raw %} +
+graph TD; + A-->B; + A-->C; + B-->D; + C-->D; +
+{% endraw %} +``` + +{% raw %} +
+graph TD; + A-->B; + A-->C; + B-->D; + C-->D; +
+{% endraw %} + +Digraph Example + +This creates a gitgraph: + +``` +{% raw %} +
+gitGraph + commit id: "First" + commit id: "Second" + branch develop + commit id: "Third" + checkout main +
+{% endraw %} +``` + +{% raw %} +
+gitGraph + commit id: "First" + commit id: "Second" + branch develop + commit id: "Third" + checkout main +
+{% endraw %} + +Gitgraph Example + + +This creates a flow chart: + +``` +{% raw %} +
+flowchart LR + id1((a)) --> id2((b)) & c--> d +
+{% endraw %} +``` + +{% raw %} +
+flowchart LR + id1((a)) --> id2((b)) & c--> d +
+{% endraw %} + +Flowchart Example + +### Test the changes + +`bundle exec jekyll s` + +browse to [http://localhost:4000](http://localhost:4000) + +### Deploy the changes + +``` +git add . +git commit -m "added mermaid to site and posted" +git push +``` + +Navigate to [https://github.com/decuser/decuser.github.io/actions](https://github.com/decuser/decuser.github.io/actions) and watch it deploy. + +### Test the deployment + +* Browse to [https://decuser.github.io](https://decuser.github.io) and see it live. + +*post last updated 2023-01-23 12:13:00 -0600* diff --git a/_posts/2023-01-23-site-update.markdown b/_posts/2023-01-23-site-update.markdown new file mode 100644 index 0000000..29cbb1c --- /dev/null +++ b/_posts/2023-01-23-site-update.markdown @@ -0,0 +1,13 @@ +--- +layout: post +title: "Site Update for Monday, January 23, 2023" +categories: general +--- + +Today, I did my 50th deployment (this is the 51st) of the blog, adding mermaid-js support to the site. So, now I can add in flow diagrams and such as I explore fossil scm or other flowing stuff. + +I hope you're finding the posts here interesting, useful, or fun. If you like, drop me a note and tell me what is needed, what's good, what needs to go. As always, please be constructive :). + + + +\- will diff --git a/_posts/2023-01-24-x-windows-dev-on-mac.markdown b/_posts/2023-01-24-x-windows-dev-on-mac.markdown new file mode 100644 index 0000000..6a02ad3 --- /dev/null +++ b/_posts/2023-01-24-x-windows-dev-on-mac.markdown @@ -0,0 +1,357 @@ +--- +layout: post +title: "Setting up for X-Windows Development on MacOS" +categories: operating-systems mojave x-windows +--- + +This note describes setting up a development environment for doing X Windows Development on Mac OS from the ground up. The notes do apply to other environments... with minor tweaks (I tried the same basic setup on Debian Linux, DragonFly BSD, and FreeBSD with no major issues). + +This is enough setup to build applications in X Windows using Xlib - the lowest level of programming in X... other than the X Protocol :). I did this because I have developed an interest in how graphical interfaces work and X, for all its quirks, is not self-limiting, crippled, partially proprietary or any of that nonsense and it is widely used. + +After setting up, downloading some source, building and deploying, here's what we're looking at... on a Mac: + +![one](/assets/img/xwindows/01-small.jpeg) + + + +## Resources + +* XQuartz - [https://www.xquartz.org](https://www.xquartz.org/) +* XQuartz Developer Information - [https://www.xquartz.org/Developer-Info.html](https://www.xquartz.org/Developer-Info.html) +* MacPorts - [https://www.macports.org/install.php](https://www.macports.org/install.php) +* X.org Foundation - [https://www.x.org/wiki](https://www.x.org/wiki) +* Xlib Programming Manual R5 3rd Edition Example Files - [https://resources.oreilly.com/examples/9781565920026](https://resources.oreilly.com/examples/9781565920026/) +* Xeyes source code - last updated a year or so ago - [https://gitlab.freedesktop.org/xorg/app/xeyes](https://gitlab.freedesktop.org/xorg/app/xeyes) + +## System Requirements + +* MacOS - I'm running this on Mojave, but have tested it on Monterrey as well +* XQuartz - I'm running 2.8.4 +* Macports - I'm running 2.8.0 +* Some code to run in X - I'm using xeyes from X itself and basicwin from Volume One of The Definitive Guides to the X Window System: Xlib Programming Manual for Version 11 R4/R5 by Adrian Nye + +## Getting MacOS Ready + +There are only a few small steps to take to prepare MacOS for doing X Windows development: + +1. Install XQuartz +2. Install MacPorts (to satisfy any dependencies and fill tool gaps like imake) +3. Install imake +4. Configure and Test XQuartz +5. Build xeyes and basicwin +6. Celebrate + +### 1. Install XQuartz + +Head over to [https://www.xquartz.org](https://www.xquartz.org/) and download the install package. Run it. Logout as advised when install is complete and log back in. + +### 2. Install MacPorts + +Browse to [https://www.macports.org/install.php](https://www.macports.org/install.php) and grab an installer for your version of MacOS. Run it. + +### 3. Install imake + +Open terminal and type `sudo port install imake` to install it. + +### 4. Configure and test XQuartz + +Start XQuartz (it's in /Applications/Utilities) + +* Open Preferences +* Click Input + * If you need 3 button mouse emulation (trackpad), Check the box + * Check Enable key equivalents under X11 +* Click Output + * Check Full-screen mode and Auto-show menu bar in full-screen mode +* Click Pasteboard and enable any helpful settings you like + +Note: When you enable full-screen mode, your x windows will appear on a separate desktop. This is different behavior than you will be used to if you have already been using X on your Mac, but it's more in line with a typical x windows environment this way + +#### Investigating the XQuartz startup file situation + +I wanted to use twm as the window manager instead of quartz-wm. So, I made some additional changes to the startup environment. + +##### Finding xinitrc + +On Mac OS, XQuartz provides the X11 environment (the server and many of the clients). The server is configured via xinitrc. This file can be found using `find`: + +``` +find /opt -name xinitrc +/opt/X11/etc/X11/xinit/xinitrc +``` + +##### Looking at the delivered xinitrc + +A look at this file shows that it provides a mechanism for customization using an `.xinitrc.d` directory: + +``` +cat /opt/X11/etc/X11/xinit/xinitrc +#!/bin/sh + +userresources=$HOME/.Xresources +usermodmap=$HOME/.Xmodmap +sysresources=/opt/X11/etc/X11/xinit/.Xresources +sysmodmap=/opt/X11/etc/X11/xinit/.Xmodmap + +# merge in defaults and keymaps + +if [ -f $sysresources ]; then + + if [ -x /usr/bin/cpp ] ; then + xrdb -merge $sysresources + else + xrdb -nocpp -merge $sysresources + fi + + + +fi + +if [ -f $sysmodmap ]; then + xmodmap $sysmodmap +fi + +if [ -f "$userresources" ]; then + + if [ -x /usr/bin/cpp ] ; then + xrdb -merge "$userresources" + else + xrdb -nocpp -merge "$userresources" + fi + + + +fi + +if [ -f "$usermodmap" ]; then + xmodmap "$usermodmap" +fi + +# start some nice programs + +if [ -d /opt/X11/etc/X11/xinit/xinitrc.d ] ; then + for f in /opt/X11/etc/X11/xinit/xinitrc.d/?*.sh ; do + [ -x "$f" ] && . "$f" + done + unset f +fi + +twm & +xclock -geometry 50x50-1+1 & +xterm -geometry 80x50+494+51 & +xterm -geometry 80x20+494-0 & +exec xterm -geometry 80x66+0+0 -name login +``` + +I have included the entire file because it is worth seeing, but the relevant portion is at the end of the file: + +``` +if [ -d /opt/X11/etc/X11/xinit/xinitrc.d ] ; then + for f in /opt/X11/etc/X11/xinit/xinitrc.d/?*.sh ; do + [ -x "$f" ] && . "$f" + done + unset f +fi +``` + +This snippet looks in `/opt/X11/etc/X11/xinit/xinitrc.d` for any `.sh` files and runs them. + +##### Looking in the `/opt/X11/etc/X11/xinit/xinitrc.d` directory + +To see what's going on, take a look at the directory: + +``` +ls /opt/X11/etc/X11/xinit/xinitrc.d +10-fontdir.sh 98-user.sh 99-quartz-wm.sh +``` + +They're each interesting in their own right, but the one we're interested in is `98-user.sh`. Let's take a look at it: + +``` +cat /opt/X11/etc/X11/xinit/xinitrc.d/98-user.sh +if [ -d "${HOME}/.xinitrc.d" ] ; then + for f in "${HOME}"/.xinitrc.d/*.sh ; do + [ -x "$f" ] && . "$f" + done + unset f +fi +``` + +Well, that looks familiar. It appears that it looks for a .xinitrc.d folder in the users directory and runs any `.sh` files it finds. That's our hook for running `twm`. + +#### Setting twm as the window manager + +To set twm as the window manager requires us to create a startup file and give it execute permission: + +``` +mkdir -p ~/.xinitrc.d +cat < ~/.xinitrc.d/99-wm.sh +#!/bin/sh +exec twm +EOF +chmod +x ~/.xinitrc.d/99-wm.sh +``` + +#### Test twm + +Close XQuartz if it is currently running so that it will pick up the changes you have made up to this point and reopen it. To change to the desktop, ensure that XQuartz has the focus (click on it) and type the three key combination `Command-Option-a` or from the menu, select XQuartz->Toggle Full Screen: + +![two](/assets/img/xwindows/02.png) + +Your screen should switch to twm. Position your mouse somewhere near top left to position the xterm window: + +![three](/assets/img/xwindows/03.png) + +To switch between your x windows session and MacOS, just press `Command-Option-a` or move your mouse to the top of the screen and from the menu, select XQuartz->Toggle Full Screen. + +Your X Windows will continue running until you either exit twm, or close XQuartz. The proper way to do it is to close any running application and exit twm. In order to close open applications, you can type `CTL-d` to close the applications input (works for terminal and a lot of unix utilities) or use the kill command from the twm menu. To bring up the twm menu, left click on the desktop, outside of any window, while in X Windows, and the twm menu will appear: + +![four](/assets/img/xwindows/04.png) + +To exit twm, bring its menu up and click exit. + +Note: Occasionally, in my experience, if you don't exit twm cleanly, it will display a phantom window frame on the screen when you start it up (no big whoop, but annoying). So, exit correctly or ignore the cruft. + +Read more about twm at [https://www.oreilly.com/library/view/x-window-system/9780937175149/Chapter03.html](https://www.oreilly.com/library/view/x-window-system/9780937175149/Chapter03.html) + +From now on, we will be running any x applications in twm. Just note that they will also work fine in xquartz-wm and appear to be more integrated with MacOS, then. We can build our apps in a regular MacOS terminal and enjoy easy cut and paste, but let's run the apps in xterm. + +### 5. Build xeyes and basicwin + +Now that we have a working X Window environment to explore let's try building a couple of apps. First, let's build my all time favorite X client, xeyes. + +#### Get the xeyes source + +``` +cd ~/sandboxes-git +git clone https://gitlab.freedesktop.org/xorg/app/xeyes +cd xeyes +``` + +#### Build xeyes from source + +I won't apologize for this next bit, suffice it to say that some sorcery is involved... and glomming the XQuartz Developer Information page at [https://www.xquartz.org/Developer-Info.html](https://www.xquartz.org/Developer-Info.html). The instructions there are way out of date, but they do give a hint as to how to set up your environment for building X applications from the X.Org distribution (of which xeyes is part). + +That said, I will apologize, in advance, if your build fails due to missing dependencies (like autoconf). I have been running this system for a while and I do a lot of development on it, so I probably have already installed some of the dependencies (how would I know, right?). Anyway, if you do hit a notice that you are missing a library or dev tool, just `sudo port install` it. + +Now, without further ado, let's build xeyes: + +``` +export ACLOCAL="aclocal -I /opt/X11/share/aclocal" +export PKG_CONFIG_PATH="/opt/X11/share/pkgconfig:/opt/X11/lib/pkgconfig" +export CFLAGS="-Wall -O0 -ggdb3 -arch x86_64 -pipe" +export OBJCFLAGS=$CFLAGS +export LDFLAGS=$CFLAGS +autoreconf -fvi +./configure --prefix=/opt/X11 --disable-dependency-tracking +make +``` +These commands tell autoreconf, configure, and make, respectively where to find pkgconfig, aclocal, etc., and then execute the command to build the app. + +If all is well in the world, you should see: + +``` +Making all in man + GEN xeyes.1 + CC Eyes.o + CC transform.o + CC xeyes.o + CCLD xeyes +``` + +and, the file xeyes should now be present in the directory: + +``` +ls -l xeyes +-rwxr-xr-x 1 wsenn staff 30944 Jan 24 18:34 xeyes +``` + +Yay, let's run it. Switch over to your twm and open an xterm. In the xterm window, run xeyes: + +``` +cd ~/sandboxes-git/xeyes +./xeyes +``` + +![five](/assets/img/xwindows/05.png) + +#### Get the basicwin source + +OK. That was fun, but we need to get closer to our goal of doing Xlib development. Let's build basicwin from the Xlib Programmer's Manual. + +``` +mkdir -p ~/sandboxes-git +cd ~/sandboxes-git +git clone https://resources.oreilly.com/examples/9781565920026.git xlib-pm +``` + +#### Create a temporary location for our source code + +``` +mkdir -p ~/work +cd ~/work +tar xvf ~/sandboxes-git/xlib-pm/xlibprgs4.tar.Z +cd xlib/basicwin/basic +``` + +#### Build basicwin from source + +Unlike xeyes, above, we don't need any special incantations to make this next part work. We can follow what Adrian Nye wrote nearly 30 years ago: + +``` +xmkmf +make +``` + +If all went well, we will see something along the lines of: + +``` +19 warnings generated. +rm -f basicwin +/usr/bin/cc -o basicwin -Os -Wall -Wpointer-arith -no-cpp-precomp -L/opt/local/lib basicwin.o -lXext -lX11 +``` + +Nevermind the warnings, a lot has changed with our c environment over the years. The good news is we now have a new executable: + +``` +ls -l basicwin +-rwxr-xr-x 1 wsenn staff 14792 Jan 24 18:48 basicwin +``` + +Switch over to twm, open a new xterm, and run it: + +``` +cd ~/work/xlib/basicwin/basic +./basicwin +``` + +![six](/assets/img/xwindows/06.png) + +### 6. Celebrate + +Yeeha! That's worth celebrating. Next, tweak that basicwin source code. get a book on Xlib and really dig in, get one on XT, get one on Motif, go crazy and read up on QT and GTK+, just have fun. I'm just getting started, so it's all new to me. I'm planning = to start with Xlib and work my way up the stack. + +## Some extras + +The more observant folks prolly wondered a few things: + +1. Where did that browser come from in the cool screenshot? + ``` +sudo port install midori +``` +Midori rocks! Super fast and runs in X. I use it over ssh all of the time - firefox is great, but it sucks over the network. Not so midori! +2. Same question for the other app? + ``` +sudo port install htop +``` + htop is a pretty process monitor for terminal (and xterm). +3. How did he capture those screenshots. + This took quite a bit of trial and error. Folks on the web recommend using `xwd`, I couldn't get it to grab the right window (the desktop) no matter what incantation I gave it. + What did work was Mac OS's built in `Screenshot.app` application. I just gave it a 10 second timeout, chose the select window option, clicked Capture, and then speedily opened twm and waited for the timeout to occur. + +Links to high res images: + +* [x windows running root window mac os](/assets/img/xwindows/01-big.png) + + +*post last updated 2023-02-13 21:02:00 -0600* diff --git a/_posts/2023-01-31-xlib-basics.markdown b/_posts/2023-01-31-xlib-basics.markdown new file mode 100644 index 0000000..b692e30 --- /dev/null +++ b/_posts/2023-01-31-xlib-basics.markdown @@ -0,0 +1,1097 @@ +--- +layout: post +title: "Xlib basics" +categories: development x-windows xlib +--- + +This note explores the basics of Xlib. It covers enough to open a window, configure it, display a message, respond to some events, and close it gracefully - see figure 1 for a hint at what this will look like. + +Why xlib? Well, because we can, because it is the lowest level above the X protocol (sending bits around), and because, contrary to many espoused beliefs these days, knowing how to do something the 'hard way' helps you understand what's going on with the 'easy way'... and when things inevitably go wrong, you want to have a clue. + +Figure 1. A Basic Xlib Application + + +![one](/assets/img/xlib/01.png) + + + +Disclosure - I am not an expert in X. These notes represent my stumbling around trying to figure things out. If you know better, drop me a line and I'll probably make an adjustment. + +First things first, old books and old notes are fantastic, but don't expect things to work as they describe all of the time. This note is written in 2023 and the exploration it unveils is specific to the times and environment of the author. Sure, a lot of it should translate to other times and environments, but at least keep it mind. + +## Systems tested + +* MacPro and Macbook Pro running MacOS Mojave 10.14.6 (tested with XQuartz and macports X11) +* Dell Optiplex 755 running FreeBSD 13.1 +* IBM ThinkCentre M92p running FreeBSD 13.1 +* Lenovo Thinkpad T430 running Debian Bullseye 11.6 + +## Some Resources + +* XQuartz - [https://www.xquartz.org](https://www.xquartz.org/) +* XQuartz Developer Information - [https://www.xquartz.org/Developer-Info.html](https://www.xquartz.org/Developer-Info.html) +* MacPorts - [https://www.macports.org/install.php](https://www.macports.org/install.php) +* X.org Foundation - [https://www.x.org/wiki](https://www.x.org/wiki) +* Xlib - C Language X Interface [https://www.x.org/docs/X11/xlib.pdf](https://www.x.org/docs/X11/xlib.pdf) +* The source code for the program developed in this note is [available here](/assets/files/xlib/xlib-article-files.tar.gz) + +## A bibliography + +* Foster-Johnson, E. & Reichard, K. (1992). *X Window Applications Programming*, 2nd ed. New York: MIS Press. +* Nye, A. (1995). *Xlib Programming Manual for Version 11 R4/R5*, 3rd ed. Vol. 1 in series The Definitive Guides to the X Window System. O'Reilly & Associates. +* Nye, A. (1993). *Xlib Reference Manual for Version 11 R4/R5*, 3rd ed.. Vol. 2 in series The Definitive Guides to the X Window System. O'Reilly & Associates. +* Quercia, V., & O'Reilly, T. (1993). *X Window System Users's Guide for X11 Release 5*. Vol. 3 in series The Definitive Guides to the X Window System. O'Reilly & Associates. + +## Acknowledgements + +This note wouldn't be possible without the great work of the folks who created X and those who maintain it to this day. I am appreciative of those efforts and you should be too :). The O'Reilly series of books, *The Definitive Guides to the X Window System* are the basis of much of my learned knowledge about X and how it works. Eric F. Johnson's book, *X Window Applications Programming*, inspired the approach that I have taken to developing applications for X. + +Without further ado, let's get into it. + +## Outline of what we are about to do + +In this note, I will walk you through writing some code that will: + +1. Declare some variables +2. Open a connection to the X Window Server +3. Open a window +4. Set some hints +5. Display the window +6. Handle events +7. Close the Display + +There are some terms we need to get out of the way before proceeding. Specifically, what is a server, display, screen, window manager, window, and client? + +Unfortunately, techies write reams about these things and make lots of distinctions that cloud the issue for beginners. Here's what the modern, beginning reader needs to know about their world: + +* Server, display, and screen - the X window server is a process that is most likely running on your local machine. It manages communication with the hardware that is attached to your machine, specifically the monitor(s), mice, and keyboard(s). X considers each monitor to be a screen and all of them together as a display. + +* Window manager - the window manager is a process that controls the look and feel of your UI - window borders, title bars, buttons that decorate windows, etc. + +* Window - this is just a rectangular (usually) area of the screen. + +* Client - the applications we write and the window manager are considered clients of the X window server. + +Whew! With those prelimaries out of the way, we can start designing our client. + +## Designing an X client (x windows application) + +The trick here is to decide what the app's going to do and then come up with a plan of writing it, building it, testing it, and deploying it. + +### What is the client going to do? + +This application is going to display the string "hello, world - click the mouse or press any key to exit." in a window and wait for the user to press a mouse button or a key before exiting. + +### What's the plan to writing it? + +In this project, we will just need two files, a hello.c file and a makefile. + +* hello.c will contain our working code +* makefile will contain instructions related to building, running, and cleaning up our project. + +The plan is to write the makefile first and then to write the code incrementally, adding some working code, running it, and writing some more code, until it works the way we want it to. Each time we add something it will follow the outline of steps given above. + +But first, we will explore the environment so that we know where our libraries and include files live that are needed for the development. + +#### Explore the environment + +Open up a terminal in your x windows environment. + +Find out where X lives. X is the X window server and if you are running X, you have one. But where is it? The easiest way to find it is to use `which`: + +``` +which X +/opt/X11/bin/X +``` + +This is on a Mac, FreeBSD says it's in `/usr/local/bin` and Debian says it's in `/usr/bin`. Knowing where X lives gives us an indication of where the libraries and include files are. Withouth them we won't be able to compile or link the binary of the program we are creating and it just won't run. + +To find the libraries, we can use the information we obtained to find X. In this case, we will use `/opt` as the starting point for searches on MacOS. On FreeBSD, `/usr/local`, and on Debian, `/usr`. + +``` +find /opt -iname "*libx11*" +/opt/local/lib/libX11.dylib +/opt/local/lib/libX11-xcb.a +/opt/local/lib/libX11.6.dylib +/opt/local/lib/libX11-xcb.1.dylib +/opt/local/lib/libX11.a +/opt/local/lib/libX11-xcb.dylib +... +``` + +Similarly, to find the include files, search using the same root: + +``` +find /opt/local | grep "Xlib.h" +/opt/local/include/X11/Xlib.h +``` + +With the library directory and include directory known, we almost have enough information to start building X programs. The only missing piece at this point is knowing which libraries to link to. For this, we will use a package called `pkgconf` or somesuch and a program called `pkg-config`. To get the package, just use your pkg manager to install it: + +On MacOS - `port install pkgconf` or `brew install pkgconf`, on FreeBSD - `pkg install config`, on Debian `apt install pkgconf`, etc. + +Once you have `pkgconf` installed, you can use `pkg-config` to tell you what cflags and ldflags you need to build programs: + +On MacOS + +``` +pkg-config --cflags --libs x11 +-I/opt/local/include -L/opt/local/lib -lX11 +``` + +On FreeBSD + +``` +pkg-config --cflags --libs x11 +-I/usr/local/include -D_THREAD_SAFE -pthread -L/usr/local/lib -lX11 +``` + +On Debian + +``` +pkg-config --cflags --libs x11 +-lX11 +``` + +With the location of the libraries and include files, the c flags, and linker flags handy, we have enough information to compile and link our own X programs. + +Let's put that information to good use. + +#### Write a makefile + +After you build and run a bunch of programs over and over, you will come to appreciate having a makefile. I suggest that you type it in until you have some muscle memory. Once you're comfortable with making makefiles, your programming life will be much simpler. + +Based on what we know from the previous section combined with some `make` magic, we can build a great makefile. + +Stuff we need to know: + +* cc is the standard command to invoke a c compiler on all of these systems (on MacOS and FreeBSD, it symlinks to clang, on Debian, it symlinks to gcc). +* CFLAGS - these are options to the c compiler +* LDFLAGS - these are options to the linker + +This is our makefile built from what we have learned about the environment (for MacOS, your environment may need the flags variables to be tweaked appropriately): + +``` +CC = cc +CFLAGS = -I/opt/local/include +LDFLAGS = -L/opt/local/lib -lX11 +OBJFILES = hello.o +TARGET = hello + +all: $(TARGET) + +$(TARGET): $(OBJFILES) + $(CC) $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LDFLAGS) + +run: $(TARGET) + ./$(TARGET) + +clean: + rm -f $(OBJFILES) $(TARGET) *~ +``` + +* The OBJFILES variable holds a list of .o files that need to be created by the makefile from .c source files. + +* The TARGET variable specifies the name of the executable to build. + +* all builds the target + +* $(TARGET): $(OBJFILES) specifies how the target depends on the object files and how to build the target. + +* run depends on target and runs the target (the client) + +* clean removes the files make creates + +We will test the makefile down the road. Leave it for now and move on to the fun stuff - writing code. + +#### Write the Code + +It's time to write `hello.c`. As a reminder, here is what we said the code needed to do: + +1. Declare some variables +2. Open a connection to the X Window Server +3. Open a window +4. Set some hints +5. Display the window +6. Handle events +7. Close the Display + +Let's use this as an outline for our hello.c file + +``` +/* + * hello.c - a simple x window client built on xlib + * modified 20230131 wds + */ + +#include // for fprintf +#include // for exit +#include // for xlib stuff + +int main(int argc, char** argv) +{ + /* + * 1. Declare variables + */ + + /* + * 2. Connect to the X window server + */ + + /* + * 3. Open a window + */ + + /* + * 4. Set some hints + */ + + /* + * 5. Display the window + */ + + /* + * 6. Handle events + */ + + + /* + * 7. Close the Display + */ + + return 0; +} +``` + +Save the file as `hello.c` + +**Xlib related additions** + +* Xlib.h - a header file that brings in X.h and defines a bunch of things we will need for doing xlib programming - definitions and such. + +Now that we have written the basic outline of our code, let's build it and run it to check on the steps completed so far: + +``` +make run +makefile:13: *** missing separator. Stop. +``` + +Yikes! If you see something like this, `don't panic`. It is probably just a case of tabs getting converted to spaces during cut and paste. `make` is picky, it only respects tab indent. So, delete any spaces and use a tab for indentation. + +Lesson learned, don't use spaces to indent makefiles... ever. Let's use tabs and try it again. + +``` +make +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 +``` + +Ok. No errors this time, let's go ahead and run it: + +``` +make run +./hello +``` + +Hopefully we didn't get any more errors! Moving forward we will combine the build and run steps using `make run`: + +``` +make run +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 +./hello +``` + +If you like, you can save copies of the makefile and hello.c along the way for comparison. + +This code doesn't really do anything useful yet... other than proving that the makefile 'works' and that the code doesn't have any show stopping bugs, and that we're able to run it, and, and... Ha! What we have accomplished so far isn't insignificant, but read on for more interesting development. + +X programming can be pretty complicated, so one convention we are going to adopt and love starting now, is commenting the code and organizing it rationally. In this example, we are going to stretch things just a little bit in that we will keep our code contained in a single file. It won't be long before you will want to split things up, but not this time, and this is where the use of comments will start to prove super helpful. + +##### First revision - add variable declarations + +In this first revision, we are going to go ahead and declare some variables and put those declarations at the top of our main function. As will become usual, we will build and run the result, before going on to the next revision. It used to be the norm to put declarations at the top of a scope so that things would be easy to find. These days it's a mix of folks putting them at the top and putting them closer to where they are used. We're going to use the old-school approach for now. + +Add this code into the *Declare variables* section just below main: + +``` + /* + * 1. Declare variables + */ + + // display vars + Display* display; + int screen; + Window root; + GC gc; + + // window vars + Window window; + Visual* visual = CopyFromParent; + int x, y, width, height; + char *message = "hello, world - click the mouse or press any key to exit."; + + // event loop - done and event variables + int done = 0; + XEvent event; +``` + +Let's talk about the variable declarations and definitions that were added and what they are used for since they seem to be important (appearing first). + +The first four variables, `display`, `screen`, `root`, and `gc`, refer respectively to the logical display (remember this is the coalescence of all of your monitors), the screen (think of this as one of your monitors), the root window, and the graphic context. The root window and graphic context are new, we haven't discussed them before. But, basically, the root window is the blank window taking up your whole screen where everything that appears, appears. All windows have a parent, and the parent window of your applications is the root window. The graphic context is related to our drawing text to the window. `display` is a pointer to a Display structure containing all sorts of information about the display. We will pass the pointer around a lot and if we need some of that information, we will pass it to information returning macros, but otherwise, it just is. `screen` is an integer that tells us which screen to use in a multi-screen environment. `root` is a Window structure that contains information about a window. We pass it around and provide it when asked for it. `gc` is a GC, it is needed to draw stuff. We need access to these variables to instantiate windows, work with windows, and the like. + +The next set of variables, `window`, `visual`, `x`, `y`, `width`, `height`, and `message` refer to our window, it's visual style (GrayScale, TrueColor, etc). it's location and size, and the message we intend to display. `window` is a Window, `visual` is set to CopyFromParent so that the style is inherited from the root window, x, y, width, and height are integers, and message is a string. + +The last two, `done` and `event` refer to a control variable for our loop and a structure to hold inbound events that is used for handling events in the event loop. `event` is an XEvent, a structure containing information about an event. + +We will expand the variables section along the way as we need to by adding additional declarations and definitions. + +**Xlib related additions** + +* Display - A giant struct containing information about our display +* Window - The ID of our window +* GC - A giant structure containing information about a graphics context +* Visual - a structure containing information about the color environment +* XEvent - a structure (a union of all the event types) containing information about events +* CopyFromParent - a macro + +Now that we have added a section of code, let's build and run our program to test what we have done so far. + +Build and run: + +``` +make run +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 +./hello +``` + +It didn't break, but it doesn't do much either. Let's revise it. + +##### Second revision - Open a connection ot the X Window Server + +The code we add in this revision will open the display, give us the index of our screen, give us a handle to the root window, and give us a graphic context. + +``` + /* + * 2. Connect to the X window server + */ + + display = XOpenDisplay((char*) NULL); + if(display == (Display *) NULL) { + fprintf(stderr, "Unable to connect to X server [%s]\n", + XDisplayName((char*) NULL)); + exit(1); + } + + screen = DefaultScreen(display); + root = RootWindow(display, screen); + gc = DefaultGC(display, screen); +``` + +**Xlib related additions** + +* XOpenDisplay - a function that opens the display +* XDisplayName - a macro that returns the display name +* Default Screen - a macro that returns the index of the default screen +* RootWindow - a macro that returns the id of the root window +* DefaultGC - a macro that returns the default graphic context of the screen + +Let's build it and check in on our progress towards a working client. + +Build and run: + +``` +make run +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 + +make run +./hello +``` + +Well, that's all well and good. It looks like we were able to build it and run it, so... in theory we sucessfully connected to the X server... but, we will just make sure by displaying some information about the display we got back. + +To do this, we will create a function to print information about the display to the terminal window where we run the client. + +We will first add in a prototype for our function above main: + +``` +void PrintDisplayInformation(Display* display, int screen); + +int main(int argc, char** argv) +``` + +Like most xlib calls ours will take a display and screen as arguments. Then we will add the body of our function after main returns: + +``` + return 0; +} + +void PrintDisplayInformation(Display* display, int screen) { + int screen_num, display_width, display_height, width, height; + + /* get screen size from display structure macro */ + screen_num = DefaultScreen(display); + display_width = DisplayWidth(display, screen_num); + display_height = DisplayHeight(display, screen_num); + + fprintf(stderr, "DisplayString: %s\n", DisplayString(display)); + fprintf(stderr, "default screen index: %d\n", screen_num); + fprintf(stderr, "display width: %d\n", display_width); + fprintf(stderr, "display height: %d\n", display_height); +} +``` + +The function just uses some macros from xlib to get information about the display and prints out the results. + +Next, we will make the call to our function after our previous revision's change to open a connection: + +``` + gc = DefaultGC(display, screen); // prior stuff, don't re-add + PrintDisplayInformation(display, screen); +``` + +What all of this does is pretty self evident, but we have introduced some new xlib calls. With an open display, we can see what connect string was used to connect to the X server, the screen number of the default screen, and the width and height of the display. + +**Xlib related additions** + +* DisplayWidth - a macro that returns the width of the screen +* DisplayHeight - a macro that returns the height of the screen +* DisplayString - the display string that was used to connect to the X server + + +The code now actually does something useful, let's test. + +Build and run: + +``` +make run +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 +./hello +DisplayString: /private/tmp/com.apple.launchd.HJrIk6bvEG/org.xquartz:0 +default screen index: 0 +display width: 2560 +display height: 1440 +``` +Woohoo! Some real work. + +You should notice that the display string was not specified programmatically. This is because when you don't it defaults to whatever $DISPLAY is set to by the environment. Use `echo $DISPLAY` to see its value (make sure you are either in a Terminal locally, in an xterm remotely, ssh -Y'd into an environment, etc. If you aren't the $DISPLAY variable is likely unset). + +##### Third Revision - Open a window + +Now let's get a window set up to display. The first part of setting up a window is to open it on the display (this doesn't mean that it will actually show up, but it's getting close). + +Let's create a variable to hold the width of our window's border. Add it to the `window vars` section of the code: + +``` + int border_width = 2; +``` + +Let's add some code between the `window vars` and `event loop` sections that relate to our window's background and border pixels and to the events we are interested in receiving: + +``` + // window attributes + // subscribe to events (Exposure, ButtonPress, and KeyPress), set bg and fg pixels + XSetWindowAttributes attributes; + unsigned long attribute_mask = CWEventMask | CWBackPixel | CWBorderPixel; + unsigned long event_mask = ExposureMask | ButtonPressMask | KeyPressMask; +``` + +Then, let's add code in section 3, that uses those properties and a few others to properly create a window: + +``` + /* + * 3. Open a window + */ + + // open a window in the top left corner that is 150 pixels from either edge + // that is 500x100 pixels in size + // subscribe the window to events, and set the border and background pixels + x = y = 150; + width = 500; + height = 100; + attributes.event_mask = event_mask; + attributes.border_pixel = BlackPixel(display, screen), + attributes.background_pixel = WhitePixel(display, screen); + + window = XCreateWindow( display, root, x, y, width, height, + border_width, CopyFromParent, InputOutput, + visual, attribute_mask, &attributes); +``` + +**Xlib related additions** + +* XSetWindowAttributes - a function to modify a set of window attributes +* CWEventMask - a bit mask that indicates we have set event attributes +* CWBackPixel - a bit mask that indicates we have set a background pixel +* CWBorderPixel - a bit mask that indicates we have set a border pixel +* ExposureMask - a bit mask that indicates we want to receive Exposure events +* ButtonPressMask - a bit mask that indicates we want to receive ButtonPress events +* KeyPressMask - a bit mask that indicates we want to receive KeyPress events + +It's a good time to test the build again. + +Build and run: + +``` +make run +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 +./hello +DisplayString: /private/tmp/com.apple.launchd.HJrIk6bvEG/org.xquartz:0 +default screen index: 0 +display width: 2560 +display height: 1440 +``` + +With the window created, we just need to pass some hints to the window manager and we'll be able to display the window... on the screen! + +##### Fourth Revision - Set some hints + +In this revision, we will set window manager hints so that the window manager properly sizes and displays our window. As the name suggests, these are hint and may be ignored, but we want to provide them anyway, just in case! + +To give our code access to size hint structures and such, we will need to include the xlib utilities header file `Xutil.h`. Add this to the end of the includes section. + +`#include // for XSizeHints etc.` + +Classes in X Windows parlance are used to differentiate between different kinds of applications for the purpose of allowing similar applications to share properties. There may be other uses, but I don't know what they are. In our case, we will just put our client into an `example_class`, where it won't disturb other clients. If you actually were to build a suite of related clients, you would probably want to give it a descriptive and unique name that could be shared by your clients but that wouldn't clash with others. + +Put this declaration and definition into the `window vars` section: + +` char *application_class = "example_class"; ` + +We will also add some variable related to hints, put these after the `window vars` section and before the `event loop vars`: + +``` + // window hints - size, name, class, and window manager hints + XSizeHints size_hints; + char *window_name; + XClassHint class_hints; + XWMHints window_manager_hints; +``` + +Let's set hints for the size and position of our window, the name of our window, and some window manager specif information. Put this code in the fourth section: + +``` + /* + * 4. Set some hints + */ + + size_hints.x = x; + size_hints.y = y; + size_hints.width = width; + size_hints.height = height; + size_hints.min_width = width; + size_hints.min_height = height; + size_hints.base_width = width; + size_hints.base_height = height; + size_hints.flags = USPosition | USSize | PMinSize | PBaseSize; + window_name = argv[0]; + class_hints.res_class = application_class; + class_hints.res_name = window_name; + window_manager_hints.flags = InputHint | StateHint; + window_manager_hints.initial_state = NormalState; + window_manager_hints.input = True; + + XSetWMNormalHints(display, window, &size_hints); + XStoreName(display, window, window_name); + XSetClassHint(display, window, &class_hints); + XSetWMHints(display, window, &window_manager_hints); +``` + +**Xlib related additions** + +* Xutil.h - a header file that adds some xlib utilities and defines +* XSizeHints - a struct containing size hint information for the window manager +* XClassHint - a struct containing class information for the window manager +* XWMHints - a struct containing window manager hints +* USPosition - a flag indicating that the user provided the position value +* USSize - a flag indicating that the user provided the size value +* PMinSize - a flag indicating that the program provided the minimum size value +* PBaseSize - a flag indicating that the program provided the base size value +* InputHint - a flag indicating the style of input preferred (pointer follows focus, etc) +* StateHint - a flag indicating the preferred starting style of the window (iconified, normal) +* NormalState - a flag indicating the normal window state (open not maximized) +* XSetWMNormalHints - a function to set the window manager normal hints +* XStoreName - a function to store (set) the window name +* XSetClassHint - a function to set the class hint +* XSetWMHints - a function to set the wm hints + +This gets us closer to actually seeing somethign in a window - we have one and its properties are set. It's ready to display. In the meantime, another test. + +Build and run: + +``` +make run +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 +./hello +DisplayString: /private/tmp/com.apple.launchd.HJrIk6bvEG/org.xquartz:0 +default screen index: 0 +display width: 2560 +display height: 1440 +``` + +##### Fifth revision - Display the window + +Now that the window has been opened and its hints set, it's a breeze to actually get it to appear. Add some code to section 5: + +``` + /* + * 5. Display the window (Raise it and flush the output queue) + */ + + XMapRaised(display, window); + XFlush(display); +``` + +**Xlib related additions** + +* XMapRaised - a function that maps our window to the screen and allows it to be drawn +* XFlush - a function to flush the output queue and cause our window to receive events + +This will display the window and flush the output queue so that the window gets drawn. Unfortunately it appears so quickly and disappears so quickly you likely won't see much. Let's try it anyway. + +Build and run: + +``` +make run +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 +./hello +DisplayString: /private/tmp/com.apple.launchd.HJrIk6bvEG/org.xquartz:0 +default screen index: 0 +display width: 2560 +display height: 1440 +``` + +To get it to stay longer, we will need to do some more work - the event handler, up next is just what is needed here. + +##### Sixth revision - Handle Events + +We are nearly there. Just a this revison and the next and our client will be complete. In this revision we will actually get to see our handiwork and it will seem to be complete, but the last revision will be needed so hang in there. + +We are going to be calling `strlen`, so another include is needed. Add it after the last includde: + +`#include ` + +The event loop is where all of the program action takes place. In our world, it's where the window gets populated and drawn and where we respond to events. Let's add the event handler code in section 6. + +``` + /* + * 6. Handle events + */ + + while(! done) { + XNextEvent(display, &event); + if(event.type == Expose) { + XDrawString(display, window, gc, 50, 50, message, strlen(message)); + printf("For Expose event the area is:\n"); + printf("\tAt %d, %d,", event.xexpose.x, event.xexpose.y); + printf(" %d pixels wide, %d high\n", event.xexpose.width, + event.xexpose.height); + } + else if(event.type == ButtonPress) { + printf("Button pressed\n"); + done = 1; + } + else if(event.type == KeyPress) { + printf("Key pressed\n"); + done = 1; + } + } +``` + +This code just loops until we say it's done - basically when we get a ButtonPress event, or a Keypress event. With compositing (a fancy, modern invention), we won't get a lot of Expose events, contrary to practically every book ever written on X, but will get one when we startup and resize the window, so all we do is draw our string into the window and print some information to the standard error that we can see. + +**Xlib related additions** + +* XNextEvent - a function that waits for an event to occur (yes it blocks, deal with it) +* Expose - - a flag indicating that an Expose event has been received +* XDrawString - a function that draws a string into a window +* ButtonPress - a flag indicating that a ButtonPress event has been received +* KeyPress - a flag indicating that a KeyPress event has been received + +When you run it this time, you will see the glorious window appear. You can click inside the window, or press a key when the window has the focus to exit. + +Run it and see. + +Build and run: + +``` +make run +cc -I/opt/local/include -c -o hello.o hello.c +cc -I/opt/local/include -o hello hello.o -L/opt/local/lib -lX11 +./hello +DisplayString: /private/tmp/com.apple.launchd.HJrIk6bvEG/org.xquartz:0 +default screen index: 0 +display width: 2560 +display height: 1440 +For Expose event the area is: + At 0, 0, 500 pixels wide, 100 high + For Expose event the area is: + At 0, 0, 500 pixels wide, 100 high +Button pressed +``` + +Here's what you should see: + +![one](/assets/img/xlib/01.png) + +Do what it says :). + +##### Seventh and final revision - Close the Display + +Even though the client is pretty much finished and works as advertised, the polite way of ending the life of a client is to free up any dynamic structures and close the display. In our case, we just need to close the display + +Add the code to section 7: + +``` + /* + * 7. Close the Display + */ + + XCloseDisplay(display); +``` + +**Xlib related additions** + +* XCloseDisplay - a function that closes the display + +Let's run it again and admire our work. + +Build and run: + +``` +make run +./hello +DisplayString: /private/tmp/com.apple.launchd.HJrIk6bvEG/org.xquartz:0 +default screen index: 0 +display width: 2560 +display height: 1440 +For Expose event the area is: + At 0, 0, 500 pixels wide, 100 high +For Expose event the area is: + At 0, 0, 500 pixels wide, 100 high +Key pressed +``` + +It should still look good: + +![one](/assets/img/xlib/01.png) + +Here is the result of all of our labor - 2 files, makefile and hello.c: + +**makefile** + +``` +CC = cc +CFLAGS = -I/opt/local/include +LDFLAGS = -L/opt/local/lib -lX11 +OBJFILES = hello.o +TARGET = hello + +all: $(TARGET) + +$(TARGET): $(OBJFILES) + $(CC) $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LDFLAGS) + +run: $(TARGET) + ./$(TARGET) + +clean: + rm -f $(OBJFILES) $(TARGET) *~ +``` + +**hello.c** + +``` +/* + * hello.c - a simple x window client built on xlib + * modified 20230131 wds + */ + +#include // for fprintf +#include // for exit +#include // for xlib stuff +#include // for XSizeHints etc. +#include + +void PrintDisplayInformation(Display* display, int screen); + +int main(int argc, char** argv) +{ + /* + * 1. Declare variables + */ + + // display vars + Display* display; + int screen; + Window root; + GC gc; + + // window vars + Window window; + Visual* visual = CopyFromParent; + int x, y, width, height; + char *message = "hello, world - click the mouse or press any key to exit."; + int border_width = 2; + char *application_class = "example_class"; + // window attributes + // subscribe to events (Exposure, ButtonPress, and KeyPress), set bg and fg pixels + XSetWindowAttributes attributes; + unsigned long attribute_mask = CWEventMask | CWBackPixel | CWBorderPixel; + unsigned long event_mask = ExposureMask | ButtonPressMask | KeyPressMask; + + // window hints - size, name, class, and window manager hints + XSizeHints size_hints; + char *window_name; + XClassHint class_hints; + XWMHints window_manager_hints; + + // event loop - done and event variables + int done = 0; + XEvent event; + + /* + * 2. Connect to the X window server + */ + + display = XOpenDisplay((char*) NULL); + if(display == (Display *) NULL) { + fprintf(stderr, "Unable to connect to X server [%s]\n", + XDisplayName((char*) NULL)); + exit(1); + } + + screen = DefaultScreen(display); + root = RootWindow(display, screen); + gc = DefaultGC(display, screen); + + PrintDisplayInformation(display, screen); + + /* + * 3. Open a window + */ + + // open a window in the top left corner that is 150 pixels from either edge + // that is 500x100 pixels in size + // subscribe the window to events, and set the border and background pixels + x = y = 150; + width = 500; + height = 100; + attributes.event_mask = event_mask; + attributes.border_pixel = BlackPixel(display, screen), + attributes.background_pixel = WhitePixel(display, screen); + + window = XCreateWindow( display, root, x, y, width, height, + border_width, CopyFromParent, InputOutput, + visual, attribute_mask, &attributes); + + /* + * 4. Set some hints + */ + + size_hints.x = x; + size_hints.y = y; + size_hints.width = width; + size_hints.height = height; + size_hints.min_width = width; + size_hints.min_height = height; + size_hints.base_width = width; + size_hints.base_height = height; + size_hints.flags = USPosition | USSize | PMinSize | PBaseSize; + window_name = argv[0]; + class_hints.res_class = application_class; + class_hints.res_name = window_name; + window_manager_hints.flags = InputHint | StateHint; + window_manager_hints.initial_state = NormalState; + window_manager_hints.input = True; + + XSetWMNormalHints(display, window, &size_hints); + XStoreName(display, window, window_name); + XSetClassHint(display, window, &class_hints); + XSetWMHints(display, window, &window_manager_hints); + + /* + * 5. Display the window + */ + + XMapRaised(display, window); + XFlush(display); + + /* + * 6. Handle events + */ + + while(! done) { + XNextEvent(display, &event); + if(event.type == Expose) { + XDrawString(display, window, gc, 50, 50, message, strlen(message)); + printf("For Expose event the area is:\n"); + printf("\tAt %d, %d,", event.xexpose.x, event.xexpose.y); + printf(" %d pixels wide, %d high\n", event.xexpose.width, + event.xexpose.height); + } + else if(event.type == ButtonPress) { + printf("Button pressed\n"); + done = 1; + } + else if(event.type == KeyPress) { + printf("Key pressed\n"); + done = 1; + } + } + + /* + * 7. Close the Display + */ + + XCloseDisplay(display); + + return 0; +} + +void PrintDisplayInformation(Display* display, int screen) { + int screen_num, display_width, display_height, width, height; + + + + /* get screen size from display structure macro */ + screen_num = DefaultScreen(display); + display_width = DisplayWidth(display, screen_num); + display_height = DisplayHeight(display, screen_num); + + fprintf(stderr, "DisplayString: %s\n", DisplayString(display)); + fprintf(stderr, "default screen index: %d\n", screen_num); + fprintf(stderr, "display width: %d\n", display_width); + fprintf(stderr, "display height: %d\n", display_height); +} +``` + +#### Clean up the mess + +The makefile proves to be useful in this area. Just run `make clean` to get rid of the object files an executables and temp files that may have been generated: + +``` +make clean +rm -f hello.o hello *~ + +ls +hello.c makefile +``` + +Of course, you may want to deploy your masterpiece before you go cleaning, right? If so, just copy it off into `~/bin` or something so that it will always be available to you. + +## Wrapping up + +Whew! We finished it and hopefully, you learned a lot along the way... + +* How to find X +* How to find Xlib's include files +* How to find Xlib's libraries +* How to find the right compiler flags to build an xlib client +* How to find the right linker flags to build an xlib client +* How to find out which libraries are needed to build an xlib client +* How to write a decent makefile for building, running and cleaning up afterward +* How to write a client for X that displays a message and reacts to key presses and mouse clicks +* And various other things, I'm sure :) + +Here are the Xlib things (macros, defines, functions, etc) that we used: + +**In order of presentation** + +* Xlib.h - a header file that brings in X.h and defines a bunch of things we will need for doing xlib programming - definitions and such. +* XOpenDisplay - a function that opens the display +* XDisplayName - a macro that returns the display name +* Default Screen - a macro that returns the index of the default screen +* RootWindow - a macro that returns the id of the root window +* DefaultGC - a macro that returns the default graphic context of the screen +* DisplayWidth - a macro that returns the width of the screen +* DisplayHeight - a macro that returns the height of the screen +* DisplayString - the display string that was used to connect to the X server +* XSetWindowAttributes - a function to modify a set of window attributes +* CWEventMask - a bit mask that indicates we have set event attributes +* CWBackPixel - a bit mask that indicates we have set a background pixel +* CWBorderPixel - a bit mask that indicates we have set a border pixel +* ExposureMask - a bit mask that indicates we want to receive Exposure events +* ButtonPressMask - a bit mask that indicates we want to receive ButtonPress events +* KeyPressMask - a bit mask that indicates we want to receive KeyPress events +* Xutil.h - a header file that adds some xlib utilities and defines +* XSizeHints - a struct containing size hint information for the window manager +* XClassHint - a struct containing class information for the window manager +* XWMHints - a struct containing window manager hints +* USPosition - a flag indicating that the user provided the position value +* USSize - a flag indicating that the user provided the size value +* PMinSize - a flag indicating that the program provided the minimum size value +* PBaseSize - a flag indicating that the program provided the base size value +* InputHint - a flag indicating the style of input preferred (pointer follows focus, etc) +* StateHint - a flag indicating the preferred starting style of the window (iconified, normal) +* NormalState - a flag indicating the normal window state (open not maximized) +* XSetWMNormalHints - a function to set the window manager normal hints +* XStoreName - a function to store (set) the window name +* XSetClassHint - a function to set the class hint +* XSetWMHints - a function to set the wm hints +* XMapRaised - a function that maps our window to the screen and allows it to be drawn +* XFlush - a function to flush the output queue and cause our window to receive events +* XNextEvent - a function that waits for an event to occur (yes it blocks, deal with it) +* Expose - - a flag indicating that an Expose event has been received +* XDrawString - a function that draws a string into a window +* ButtonPress - a flag indicating that a ButtonPress event has been received +* KeyPress - a flag indicating that a KeyPress event has been received +* XCloseDisplay - a function that closes the display + +**In alphabetical order** + +* ButtonPress - a flag indicating that a ButtonPress event has been received +* ButtonPressMask - a bit mask that indicates we want to receive ButtonPress events +* CWBackPixel - a bit mask that indicates we have set a background pixel +* CWBorderPixel - a bit mask that indicates we have set a border pixel +* CWEventMask - a bit mask that indicates we have set event attributes +* Default Screen - a macro that returns the index of the default screen +* DefaultGC - a macro that returns the default graphic context of the screen +* DisplayHeight - a macro that returns the height of the screen +* DisplayString - the display string that was used to connect to the X server +* DisplayWidth - a macro that returns the width of the screen +* Expose - - a flag indicating that an Expose event has been received +* ExposureMask - a bit mask that indicates we want to receive Exposure events +* InputHint - a flag indicating the style of input preferred (pointer follows focus, etc) +* KeyPress - a flag indicating that a KeyPress event has been received +* KeyPressMask - a bit mask that indicates we want to receive KeyPress events +* NormalState - a flag indicating the normal window state (open not maximized) +* PBaseSize - a flag indicating that the program provided the base size value +* PMinSize - a flag indicating that the program provided the minimum size value +* RootWindow - a macro that returns the id of the root window +* StateHint - a flag indicating the preferred starting style of the window (iconified, normal) +* USPosition - a flag indicating that the user provided the position value +* USSize - a flag indicating that the user provided the size value +* XClassHint - a struct containing class information for the window manager +* XCloseDisplay - a function that closes the display +* XDisplayName - a macro that returns the display name +* XDrawString - a function that draws a string into a window +* XFlush - a function to flush the output queue and cause our window to receive events +* Xlib.h - a header file that brings in X.h and defines a bunch of things we will need for doing xlib programming - definitions and such. +* XMapRaised - a function that maps our window to the screen and allows it to be drawn +* XNextEvent - a function that waits for an event to occur (yes it blocks, deal with it) +* XOpenDisplay - a function that opens the display +* XSetClassHint - a function to set the class hint +* XSetWindowAttributes - a function to modify a set of window attributes +* XSetWMHints - a function to set the wm hints +* XSetWMNormalHints - a function to set the window manager normal hints +* XSizeHints - a struct containing size hint information for the window manager +* XStoreName - a function to store (set) the window name +* Xutil.h - a header file that adds some xlib utilities and defines +* XWMHints - a struct containing window manager hints + +All of these are described in great detail in the Xlib Reference Manual (Vol. 2 of O'Reilly's Definitive Guides to the X Window System) cited at the top of the note. + +Here's the link to the source code for the program developed in the note. It is [available here](/assets/files/xlib/xlib-article-files.tar.gz) + +Reach out to me if you find any issues or have suggestions. + +\- will + +*post last updated 2023-01-23 12:13:00 -0600* diff --git a/_posts/2023-02-01-pdf-cleanup-workflow.markdown b/_posts/2023-02-01-pdf-cleanup-workflow.markdown new file mode 100644 index 0000000..a9462f7 --- /dev/null +++ b/_posts/2023-02-01-pdf-cleanup-workflow.markdown @@ -0,0 +1,451 @@ +--- +layout: post +title: "A Modern PDF Cleanup Workflow" +categories: pdfs +--- + +This note provides a workflow for taking a less than optimized PDF and optimizing it for viewing and printing. It isn't a cure-all for sick PDF's, but it does work for a lot of them. I've struggled with badly scanned PDF's for a long time and this workflow represents my current best approach. + +The note also provides a cookbook of solutions to problems I have run up against and the solutions that I currently use to address those problems. + + + +## Caveats + +Not many, but they're important to note + +* Every PDF is unique and no one solution fits them all +* The workflow is a MacOS workflow. It should translate to the BSD's and Linuxes without much difficulty. If you're on Windows, YMMV. + +## Packages + +A variety of tools are useful if you are going to work with scanned images and pdfs. This note uses PhotoScape X to deal with Color adjustments. Feel free to use your tool of choice. If you can achieve good results with one of the other packages, drop me a line, I'll happily change my workflow. + +* *ghostscript* - pdf tools +* *ImageMagick* - conversion tools for images +* *libtiff* - tiff tools +* *mupdf* - more pdf tools +* *poppler* - more pdf tools +* *pandoc* - coversion tools for documents +* *PhotoScape X* - app that does nice batch operations on images +* *tesseract* and *tesseract-eng* - OCR tools + +**Install Packages** + +Get PhotoScape X. It's available in the Apple App Store and the free version works great. I just downloaded it and archived off a copy of the app for later use as neeed. I am not a fan of apps, but this one is too good to ignore. + +The other packages are available via macports: + +``` +sudo port install ghostscript ImageMagick libtiff mupdf poppler pandoc tesseract tesseract-eng +``` + +## Short Version + +Here is the short version, keep reading afterward for details and the cookbook. There are lots of details to follow. This pdf stuff is tricky. Testing is very time consuming and great results are hard to obtain. This is my current workflow for taking a less than optimal pdf and improving it. Caveats apply. + +### 1. Phase One + +* Create a work area +* Copy in a pdf +* Extract tiffs + + ``` +mkdir -p ~/pdf-work/{input,output,output-photoscape,output-small,output-ocr} +cd ~/pdf-work/input +cp ~/Desktop/input.pdf . +cd ../input +pdfimages -tiff -p input.pdf ../output/output +``` +### 2. Phase Two + +* Use PhotoScape to adjust colors + * Open PhotoScape X + * Click Batch + * Drag the *output* folder into the window + * Choose Color->Grayscale + * Magic Color + * Lighten Shadows - 100 + * Darken Highlights - 50 + * Click SAVE + * Change the Image Format to TIFF + * Select DPI and change it to 150 + * Choose a custom destination to put the output (output-photoscape) + * Click OK + +### Phase Three + +* Resize and compress the tiffs +* Combine the tiffs into a single tiff +* OCR the single tiff and produce the OCR'ed PDF + + ``` +cd ../output-photoscape +for i in *.tiff; do convert $i -resize 1200x -compress zip ../output-small/$i.tiff;done +cd ../output-small +tiffcp *.tiff ../input/multi-image-input.tiff +cd ../input +tesseract multi-image-input.tiff ../output -l eng PDF +``` + +The result is found in *output.pdf* + +## The Details + +The following gets into the details about working with a not-so-great scanned pdf, trying to make it better and more useful - cleaner looking and with OCR. In the following discussion, I will be using a copy of Adrian Nye's Volume 4 of *The Definitive Guides to the X Window System* about Xt Intrinsics from [archive.org](https://archive.org/details/xtoolkitintrinsic04nyemiss). This PDF is particularly suited to being reworked. It has huge images, it's color, the color is neither needed, nor clear, it isn't OCR'ed, and it's a great book. + +**Tools provided by the packages** + +We will use a variety of tools in the exploration. Here is a summary list: + +* *convert* from the package *ImageMagick*, convert between image formats +* *gs* from the package *ghostscript*, extract images from pdf (single image tiffs) +* *mutool* from the package *mupdf* - get info about images in pdf +* *pandoc* from the package *pandoc*, convert document formats (pdf, html, markdown, latex, etc) +* *pdfimages* from the package *poppler*, extract images from pdf (multi image tiff) and get info about images in pdf +* *pdfinfo* from the package *poppler*, get info from pdf +* *pdfunite* from the package *poppler*, combine pdfs into a single pdf +* *PhotoScape X* from the app *PhotoScape X*, color adjustment +* *tesseract* from the package *tesseract*, OCR of images and creation of pdf +* *tiffcp* from the package *libtiff*, combinine single-image tiffs into a multi-image tiff +* *tiffsplit* from the package *libtiff*, split multi-image tiffs into single-image tiffs + +### 1. Setting up a work area + +Make a directory to work from (preferably on an SSD) with input and output subdirs, change into it, download our work of interest, and copy it to *input.pdf* to use as our source. + +``` +mkdir -p ~/pdf-work/{input,output,output-photoscape,output-small,output-ocr} +cd ~/pdf-work + +aria2c https://archive.org/download/xtoolkitintrinsic04nyemiss/xtoolkitintrinsic04nyemiss_200KB_jp2.pdf -o nye-vol-04.pdf + +cp nye-vol-04.pdf input/input.pdf +``` + +You might want to just use preview to drag a sampling of the pages into a pdf that you name input.pdf and work with that until you're convinced you want to work with the many, many page input.pdf :). + +### 2. Getting Information from a PDF + +Let's take a look at the meta-data about the PDF using *pdfinfo* from the *poppler* package. + +``` +pdfinfo input.pdf +... +Producer: iText 1.3 by lowagie.com (based on itext-paulo-153) +CreationDate: Sun Jan 8 00:02:44 2006 CST +ModDate: Sun Jan 8 00:02:44 2006 CST +Custom Metadata: no +Metadata Stream: no +Tagged: no +UserProperties: no +Suspects: no +Form: none +JavaScript: no +Pages: 622 +Encrypted: no +Page size: 475 x 637 pts +Page rot: 0 +File size: 127682751 bytes +Optimized: no +PDF version: 1.5 +``` + +The first things to notice are *Pages*, *Page size*, and *File size*: + +``` +Pages: 622 +Page size: 475 x 637 pts +File size: 127682751 bytes +``` + +This is one big pdf! + +Note that points are 1/72 of an inch. We can use the `units` command to find the conversion factors: + +``` +units point in + * 0.013888889 + / 72 +``` + +We can then do the math to figure out the size, in inches, of the pdf: + +``` +echo '475/72' | bc -l +6.59722222222222222222 + +echo '637/72' | bc -l +8.84722222222222222222 +``` + +So, it's a 6.5x9 pdf (I'm not convinced, but that's what the pdf thinks it is, so we'll roll with it). + +### 3. Getting information about a PDF's images + +For this, we can use *mutool* from the *mupdf* package and *pdfimages* from the *poppler* package. + +Let's start with *mutool*. this utility will display information about all of the images in a pdf, so be prepared for some lenghty output: + +``` +mutool info input.pdf +input.pdf: + +PDF-1.5 +Info object (1939 0 R): +<> +Pages: 622 + +Retrieving info from pages 1-622... +Mediaboxes (15): + 1 (4 0 R): [ 0 0 475 637 ] + 2 (7 0 R): [ 0 0 455 630 ] + 42 (131 0 R): [ 0 0 461 629 ] + 48 (149 0 R): [ 0 0 464 632 ] + 50 (155 0 R): [ 0 0 457 632 ] + 52 (162 0 R): [ 0 0 468 637 ] + 54 (168 0 R): [ 0 0 466 636 ] + 74 (230 0 R): [ 0 0 471 639 ] + 128 (397 0 R): [ 0 0 465 637 ] + 162 (503 0 R): [ 0 0 458 642 ] + 198 (614 0 R): [ 0 0 461 639 ] + 200 (620 0 R): [ 0 0 468 642 ] + 316 (980 0 R): [ 0 0 468 638 ] + 332 (1030 0 R): [ 0 0 471 638 ] + 490 (1519 0 R): [ 0 0 463 638 ] + +Images (622): + 1 (4 0 R): [ JPX ] 2644x3542 1bpc ImageMask (1 0 R) + 2 (7 0 R): [ JPX ] 2528x3502 1bpc ImageMask (5 0 R) +... +``` + +There is a lot of information being displayed. But, we're mostly concerned with the image resolutions at this point. + +Pixels are picture elements and they don't readily convert to more intuitive units like inches. But, we can do a conversion for the monitor that'll give us a hint as to the actual size. + +First, let's get the dpi information from X (go get XQuartz and install it, if you don't already have it): + +``` +xdpyinfo | grep dots +resolution: 96x96 dots per inch +``` + +and + +``` +xrandr | grep -w connected +default connected 2560x1440+0+0 0mm x 0mm +``` + +This tells us how many dots per inch our monitor has and how many dots there are both horizontally and vertically. + +Converting to inches is pretty straightforward since we now know the DPI and dots: + +``` +echo '2560/96' | bc -l +26.66666666666666666666 +(base) nebula:~ wsenn$ echo '1440/96' | bc -l +15.00000000000000000000 +``` + +This monitor is 27 x 15... get the measuring tape out... I wish, it's actually 23.5 x 13.25. Prolly some weird pixel thing... Not worth worrying about, it's close enough :). Email me if you know something useful here. + +The question is how big is that image in relation to what we know about the monitor: + +``` +echo '2600/96' | bc -l +27.08333333333333333333 +echo '3500/96' | bc -l +36.45833333333333333333 +``` + +27 in x 36.5 in + +Wow! That's huge :). It's about the same width as my monitor and more than twice as tall. Way more than we need for viewing or printing. + +Similarly, we can get image information using *pdfimages* from the *poppler* package: + +``` +pdfimages -list input.pdf +page num type width height color comp bpc enc interp object ID x-ppi y-ppi size ratio +-------------------------------------------------------------------------------------------- + 1 0 image 2644 3542 rgb 3 8 jpx no 1 0 401 400 200K 0.7% + 2 1 image 2528 3502 rgb 3 8 jpx no 5 0 400 400 200K 0.8% +``` + +*pdfimages* is a lot slower than *mutools*, but we do get some additonal information making it a good utility to have around. + +### 2. Extracting images from a PDF + +To extract images, we can use *pdfimages* from the *poppler* package: + +``` +cd ~/pdf-work/input +pdfimages -tiff -p input.pdf ../output/output +``` + +This will extract all of the images from the pdf and put them into *../output*. The images will be named 'output-XXX-YYY.tif'. If there are a lot of big images, it will take a while... and use a lot of disk space to extract them all, so be patient. + +### 3. Tweaking colors + +I'm sure there are better ways to do this, I just haven't figured them out yet. Email me with your tips. The command-line tools don't seem to know about "magic color". Twiddle as you like with Lighten/Darken, etc. + +To tweak colors, we can use *PhotoScape X* and preview our tweaks in real-time: + +* Open PhotoScape X +* Click Batch +* Drag the *output* folder into the window +* Choose Color->Grayscale +* Magic Color +* Lighten Shadows - 100 +* Darken Highlights - 50 +* Click SAVE +* Change the Image Format to TIFF +* Select DPI and change it to 150 +* Choose a custom destination to put the output (output-photoscape) +* Click OK + +Be patient. It'll work. + +### 4. Resizing images + +I am going to resize the images to 1200 pixels wide and I'm going to preserve the scaling. I am also going to compress the images. You may want to tweak the size. We will use the *convert* utility from the *ImageMagick* package: + +``` +cd ~/pdf-work/output-photoscape +for i in *.tiff; do convert $i -resize 1200x -compress zip ../output-small/$i.tiff;done +``` + +1200x might not be your speed, just change it as you see fit. I'm still trying to figure out an optimal size. + +Be patient, it'll take a bit. + +### 5. Recombining single-image tiffs + +To combine a bunch of individual tiffs into a multi-image tiff suitable for additional processing, we will use *tiffcp* from the *libtiff* package: + +``` +cd ~/pdf-work/output-small +tiffcp *.tiff ../input/multi-image-input.tiff +``` + +### 6. OCRing the images + +We will be using *tesseract* from the *tesseract* package to perform OCR on our images. *tesseract* will work with either single-image tiffs or with a multi-image tiff. I will show both options, but for the workflow, we will only be concerned with the multi-image tiff version (a single file with many images). + +**Option 1. Multi-image tiffs** + +``` +cd ~/pdf-work/input +tesseract multi-image-input.tiff ../output -l eng PDF +``` + +**Option 2. Single-image tiffs** + +**Don't do this if you did option 1!** + +``` +cd ~/pdf-work/output-small +for i in *.tiff; do tesseract $i ../output-ocr/$i -l eng PDF;done +``` + +Using option 2, there will be lots of pdfs to combine. We will use *pdfunite* from the *poppler* package to do the combination: + +``` +cd ~/pdf-work/output-ocr +pdfunite *.pdf ../output.pdf +``` + +Either option will take quite a while and both will produce an OCR'ed PDF. + +The result is a cleaner, better looking, and more functional PDF. + +That's it for the exploration! On to the cookbook! + +--- + +## Cookbook Solutions to various problems + +This section provides snippets solving specific problems arising while working with pdf's and images. + +### Extract images to single-image tiff files + +`pdfimages -tiff -p input.pdf output` + +This creates a bunch of tiff images named output-XXX-YYY.tif + +### Extract images to a multi-image tiff file + +``` +gs -q -dNOPAUSE -dBATCH -sDEVICE=tifflzw -sPAPERSIZE=letter \ + -sOutputFile=output.tiff input.pdf +``` + +This will extract all of the images in a pdf into a single .tiff + +A useful option to keep in mind is *-r* for resolution. A setting like *-r300* specifies a desired DPI. + +### Combine single-image tiffs into a multi-image tiff + +`tiffcp -c zip *.tif ../output.tiff` + +This combines all of the .tif files into a single .tiff + +### Adjust Colors of Multiple Images at Once + +* open *PhotoScape X* to batch correct the color + * click batch + * add in your image folder + * adjust colors + * save the results + +This creates a bunch of tiff images named whatever-XXX-YYY.tiff + +### OCR a .tiff file and produce a PDF + +The accuracy of tesseract rivals adobe now... finally. + +`tesseract input.tiff output -l eng PDF` + +### Split a multi-image tiff into single-image tiffs + +`tiffsplit input.tiff` + +This will extract all of the images from the tiff into multiple tiffs with funky names like *xaaa.tif* *xaab.tif* and so on, but it does what it says :). + +### Resize multiple tiffs + +`for i in *.tif; do convert $i -resize 1200x ../$i.tiff;done` + +This resizes tiffs to 1200xwhatever preserving the scale. + +### Resize multi-image tiff + +`convert input.tiff -resize 1200x output.tiff` + +This does the same thing for a multi-image tiff. + +### Join PDFs + +**Option 1 - using *pdfunit* from the *poppler* package** + +`pdfunite *.pdf ../output.pdf` + +This joins all of the pdf files in a directory into a single pdf. It presumes that the pdfs are numbered appropriately so they are in sort order. + +**Option 2 - using MacOS's delivered script** + +* deactivate any python environments you have running that aren't the system python +* run the script + +``` +conda deactivate +python '/System/Library/Automator/Combine PDF Pages.action/Contents/Resources/join.py' -o 'senn_w_database_project.pdf' [your list of pdfs] +``` + +Reach out to me if you find any issues or have suggestions. + +\- will + +*post last updated 2023-02-01 20:39:00 -0600* diff --git a/_posts/2023-02-22-slackware-15-t430-x-windows.markdown b/_posts/2023-02-22-slackware-15-t430-x-windows.markdown new file mode 100644 index 0000000..ce4c469 --- /dev/null +++ b/_posts/2023-02-22-slackware-15-t430-x-windows.markdown @@ -0,0 +1,475 @@ +--- +layout: post +title: "Setting up Slackware 15 on T430 for X Window Programming" +categories: development x-windows slackware15 +--- + +The note walks through the process of installing and configuring a working Slackware 15 64 instance with the packages mirrored locally for ease of access and eliminating the need to be online as much. When the system is up and running it provides xdm services to nearby hosts (those on the local network). This makes running and testing x window clients simpler and more interesting. You may notice that the note references other environments that you may not have or want to use (MacOS Mojave and FreeBSD 13.1). Just ignore those references as they are not strictly required. + +I chose Slackware 15 64 as the environment after trying out various flavors of Debian, Arch, Kwort and others. While these worked ok, they did not provide much of a clean, vanilla x experience. Slackware, on the other hand, provided a sane, simple, and understandable x environment that was pretty vanilla :). It feels really good to get back to Slackware and its simplicity. I don't have a gazillion processes running doing who knows what, the laptop sleeps without crazy interventions, and stuff works well. That said, Slackware is not for the faint of heart. You should be somewhat familiar with Linux and it's command line interface and be willing to do your own research before jumping into it. + +![two](/assets/img/t430/02.png) + + + +## Scenario + +The system being exercised here is a Lenovo Thinkpad T430 running Slackware 15 64 in a heterogeneous network of machines running FreeBSD 13.1, TrueNAS Core 13.0-U3.1, MacOS Mojave 10.14.6, Windows 10, Debian 11.6 Bullseye, and others. The goals are: + +* Get X, twm, and xdm running on the T430. +* Have the T430 provide xdm login capability to the Mac +* Have the T430 display clients on the Mac using `-display` option + +## Requirements + +Other than the mentioned downloads, the only hard requirement is that XQuartz be installed on the Mac and not currently running when starting X with the `-query` option. Having a FreeBSD 13.1 memstick around just makes sense, but isn't absolutely required. + +## Resources + +* Slackware website - [http://www.slackware.com](http://www.slackware.com) +* Slackware Download Mirrors - [https://mirrors.slackware.com](https://mirrors.slackware.com/) +* Slackware Documentation - [https://docs.slackware.com](https://docs.slackware.com) +* Linux Question Slackware Forum - [https://www.linuxquestions.org/questions/slackware-14](https://www.linuxquestions.org/questions/slackware-14/) + +Note: The documentation seems to be in a constant state of not-up-to-date-ness. To my eye, it looks like there was some kind of turf battle early days, now it looks like no one really maintains it. Contrast this with FreeBSD's Handbook, or Arch's wiki, and it pales by comparison. Which is sad, since Slackware, even moreso than FreeBSD is bounded and contained and doesn't try to be everything to everyone or provide 100 different ways of doing one thing. + +## Getting Ready + +### Download the ISO and verify it + +``` +mkdir -p ~/_workarea/_CD_DVD/iso/slackware-15.0 +cd ~/_workarea/_CD_DVD/iso/slackware-15.0 +aria2c https://mirrors.slackware.com/slackware/slackware-iso/slackware64-15.0-iso/slackware64-15.0-install-dvd.iso +aria2c https://mirrors.slackware.com/slackware/slackware-iso/slackware64-15.0-iso/slackware64-15.0-install-dvd.iso.asc +aria2c http://slackware.com/gpg-key +gpg --import gpg-key +gpg --verify slackware64-15.0-install-dvd.iso.asc +``` + +### Burn the ISO using balena etcher + + +### Clean up the EFI List + +This is an optional step. + +I do it because I get tired of seeing old boot entries lying around. Unfortunately, the Slackware live installer doesn't provide the needed tool `efibootmgr` in the default install mode. Send me an email, if you know how to do this from the installer without jumping through hoops. In the meantime, I just boot to a FreeBSD 13.1 memstick image I have laying around. + +### Boot the T430 using the FreeBSD 13.1 memstick on USB + +* Press F12, select USB +* Press 2 single user mode +* Press enter to execute the default shell +* List out the boot entries using `efibootmgr` +* Delete any unwanted entries using `efibootmgr -B -b 00XX` where 00XX represents the entry to delete +* Reboot and insert the Slackware USB + +### Boot the Slackware USB + +* Press F12, select USB +* Press Enter to Select Slackware 15.0 huge.s kernel + +## Installation + +### Choose keymap, login as root, prepare drives + +* Press Enter to leave US as keymap +* Login as root with no password +* Zap existing partition info (I use gdisk's expert zap function to do this on my two drives) + + ``` +gdisk /dev/sda +gdisk /dev/sdb +x, z +``` + +* Partition target disk (I put Slackware onto my ssd */dev/sdb*. Just use `fdisk /dev/sdb` + + * Create a new 1G EFI partition and mark it active + * Create a new 16G Swap partition + * Use the rest as a Linux partition + +### Run setup as root + +`setup` + +* Choose configure swap - */dev/sdb2* (with no bad block check) +* Configure / - */dev/sdb3* as ext4 on */* (quick, no bad block check) +* Configure EFI - */dev/sdb1* as the EFI partition +* Select install from a Slackware USB stick - let it detect your USB +* Unselect emacs, kde, and xfce (This system hearts `vi` :) and kde and xfce aren't needed - we'll use twm) +* Choose terse mode - lots of interesting output to ignore or read + +This will take a bit... + +* Skip making usb stick +* Skip lilo and move on to elilo +* install elilo - let it install a boot menu item +* Choose install imps2 +* Choose yes to gpm +* Configure network + * host - *astra* + * domain - *sentech.home* + * Answer no to vlan + * Answer yes to network manager +* Choose default services + * atd + * crond + * fuse + * messagebus + * syslog + * sshd +* Choose NO to trying out fonts +* Set TZ info + * utc + * us-central +* Choose vim +* Choose xinitrc.twm +* Set a root password +* reboot + +## First boot + +* Configure visudo to allow wheel users to execute without password - nuts, right? Don't do this without considering the ramifications. + + * login as root + * run `visudo` + * uncomment wheel with no password line + +* Add a wheel user + + * run `adduser` enter details, add user to *wheel* group, and enter and confirm password + * logout and back in as the user + +* Set up wifi - xref [https://www.makeuseof.com/connect-to-wifi-with-nmcli](https://www.makeuseof.com/connect-to-wifi-with-nmcli) + +``` +sudo -i +nmcli --ask dev wifi con SSID + +# disable ipv6 nonsense, or be prepared for 5 second lag on lookups +nmcli con mod SSID ipv6.dns-options single-request +nmcli dev reapply wlan0 +ping yahoo.com + +sudo -i ip addr +192.168.254.21 +``` + +* Test twm with `startx` + +* Test ssh with `ssh astra` from remote host + +* Git rid of bracketed paste (who thought bracketed paste was a good idea?) + + As both user and root + + `echo 'set enable-bracketed-paste off' >> ~/.inputrc` + +* Setup a basic vimrc + + As both user and root + + ``` +vi ~/.vimrc +set ts=4 +set ruler +syntax off +set conceallevel=0 +"filetype plugin indent on +"map q +set mouse-=a +``` + +* Update hosts file with `sudo vi /etc/hosts` + + `... list of ips and hosts` + +* Configure graphical logon (xdm) + + * Slackware goes down the list in rc.4 to choose the display manager - gdm, kdm, sddm, and xdm, to enable/disable the ones you don't want to use, either remove them or their execute permissions, e.g. `sudo chmod a-x /usr/bin/sddm` + + * edit inittab to start in graphical mode + + ``` +sudo vi /etc/inittab +# 3 - console, 4 - graphical +id:4:initdefault +``` + + * test runlevel 4 before rebooting using `sudo -i init 4` + +* Set up local mirror of Slackware 15 64 Repo (~11GB) + +``` +sudo -i + +vi /root/slackmirror +#!/bin/sh +TARGET=/ +MIRROR=rsync://slackware.uk +rsync -4 -rlpt --delete -P -H $MIRROR/slackware/slackware64-15.0 $TARGET + +chmod u+x ~/slackmirror +~/slackmirror +``` + +It will take a bit to download the repo. Have coffee. Rerun whenever you like, or when there's a security issue - [http://www.slackware.com/security](http://www.slackware.com/security) + +* Add the local mirror + +``` +vi /etc/slackpkg/mirrors +file://slackware64-15.0 +``` + +* Create a blacklist of packages not to include in updates + +``` +vi /etc/slackpkg/blacklist +# append +e/ +kde/ +xfce/ +kernel-generic.* +kernel-huge.* +kernel-modules.* +kernel-source +``` + +* Update the system from the mirror + +``` +# get the gpg key for slackware +slackpkg update gpg + +# update the package list +slackpkg update + +# check for new packages +slackpkg install-new + +# upgrade the packages +slackpkg upgrade-all +``` + +Let it overwrite the configuration files unless you've already customized them... + +* Upgrade the kernel - xref [Slackware Security Advisories](http://www.slackware.com/security) + +As of Feb 22, 2022, the available kernel is linux-5.15.94, if it's been awhile, it will change. Use the latest, if you like. To see what's been mirrored just `ls -ld /slackware64-15.0/patches/packages/linux-*` + +``` +# backup the existing kernel +cp /boot/efi/efi/Slackware/vmlinuz-huge-5.15.80 /boot/efi/efi/Slackware/vmlinuz-lkw + +cd /slackware64-15.0/patches/packages/linux-5.15.94/ + +# check sigs +for i in *.asc; do gpg --verify $i; done + +# upgrade the kernel +upgradepkg kernel-*.txz + +# generate initrd +geninitrd + +# check symlinks - they should point to 5.15.94 images. +ls -l /boot + + +# copy images from /boot /boot/efi/efi/Slackware +cp /boot/initrd.gz /boot/efi/efi/Slackware/ +cp /boot/vmlinuz /boot/efi/efi/Slackware/ +cp /boot/vmlinuz-generic /boot/efi/efi/Slackware/ + +# edit elilo.conf +vi /boot/efi/efi/Slackware/elilo.conf +prompt +timeout=30 +default=generic + +# default linux kernel +image=vmlinuz + root=/dev/sdb3 + label=vmlinuz + read-only + append="vga=normal ro" + description="Default Linux Kernel" + +# generic linux kernel +image=vmlinuz-generic + initrd=initrd.gz + root=/dev/sdb3 + label=generic + read-only + append="vga=normal ro" + description="Generic Linux Kernel" + +# last known working linux kernel +image=vmlinuz-lkw + root=/dev/sdb3 + label=lkw + read-only + append="vga=normal ro" + description="Last Known Working Linux Kernel" +``` + +* reboot + +## Second boot + +* Get rid of any leftover cruft using `slackpkg clean-system` + +* Serve up XDM to remote clients + + * Start a tail of xdm log using `tail -f /var/log/xdm.log` + * Configure XDM for remote queries + * Copy xinitrc as initial .xsession + `cp /etc/X11/xinit/xinitrc ~/.xsession` + * Edit the bits after the xmodmap + +``` +# set a black background, fix middle button issue +# so CTL-Button 2 brings up Xterm VT Options menu +xsetroot -bitmap /usr/include/X11/bitmaps/black +xinput set-prop 'TPPS/2 IBM TrackPoint' 'libinput Scroll Method Enabled' 0 0 0 + +# start some useful programs +/usr/bin/twm & +/usr/bin/xclock -geometry 100x100-1+1 & +xterm -g 96x24-0-0 & +xterm -g 80x32-140+0 & +exec /usr/bin/xterm -g 80x58+0+0 -name login +``` + +* Alternatively, create minimal .xsession as user + +``` +vi ~/.xsession +#!/bin/sh +xterm & +twm +``` + +* Give execute permission to the .xsession file using `chmod u+x .xsession` + +* Modify the Xaccess file to allow any host to query + +``` +vi /etc/X11/xdm/Xaccess +add * as last line +* +``` +* Modify the xdm-config file to allow querying + +``` +vi /etc/X11/xdm/xdm-config +!DisplayManager.requestPort: 0 +!DisplayManager.*.authName: MIT-MAGIC-COOKIE-1 +``` + +* Modify sshd_config to allow X11Forwarding + +``` +sudo vi /etc/ssh/sshd_config +X11Forwarding yes + +sudo /etc/rc.d/rc.sshd restart +``` + +* Enter runlevel 3 and reenter runlevel 4 for changes to take effect + +``` +sudo -i init 3 + +... wait a sec for it to enter the runlevel + +sudo -i init 4 +``` + +If you get respawn issues, just `reboot`. + +* Test x from remote x windows server + +``` +ssh -Y astra +xeyes +``` + +* Test xdm + +Stop any running instances of XQuartz, then set some sane preferences + + * Input->Option keys send Alt_L and Alt_R - lets your alt key be meta + * Ouput->Full-screen mode (needed for xdm and twm to treat your mac like an X display, otherwise, windows look and act like mac windows) + * Output->Auto-show menu bar in full-screen mode - just makes it easier to enter and exit the X window environment + * Pasteboard - check everything, it helps with cutting and pasting between X windows and Mac Windows + * Windows->Focus on New Windows - why not? + * Security->Authenticate connections - required for network clients + * Security->Allow connections from network clients - otherwise -display from astra won't work + +Fire up X on the mac using `X -query astra` from nebula. Switch X to full screen by pressing *Command-A* after clicking on the XQuartz icon in the dock. + +![two](/assets/img/t430/02.png) + +Note: if you see: xdm error (pid 1559): Cannot convert Internet address 192.168.254.25 to host name, it means you don't have a hosts entry for the ip, add it, if it just returns - make sure you actually typed X -query astra :) + + +## Bonus information + +xref - [https://unix.stackexchange.com/questions/736030/how-can-i-display-xeyes-on-a-remote-host-without-using-ssh](https://unix.stackexchange.com/questions/736030/how-can-i-display-xeyes-on-a-remote-host-without-using-ssh) + +This section describes how to use `-display` to get an xclient running on the Slackware machine to display on a remote system (a mac), that is get `xeyes -display nebula` working from astra. To display on nebula, the MacOS Mojave machine, from astra, the Slackware 15 machine, requires a handful of steps: + +* In XQuartz preferences, uncheck Ouput->Full-screen mode (we actually want windows, this time) +* Restart XQuartz +* Obtain the MIT-MAGIC-COOKIE-1 from nebula +* Add it to astra's xauth list +* Run the client from astra and it will display on nebula's screen + +Here are the details: + +To see how X was started, run `ps aux | grep X`: + +`user 96691 0.0 0.0 4279568 5012 ?? S 12:39PM 0:00.01 /opt/X11/bin/Xquartz :0 -nolisten tcp -iglx -auth /Users/user/.serverauth.96532` + +The key point to note, is the **-nolisten tcp** and **-auth** options. These indicate respectively, that the X server isn't listening on TCP and that connections to the X server require authentication. + +Changing the preferences in XQuartz to allow network connections and restarting it result in the following change: + +`user 97993 0.0 0.0 4279568 5004 ?? S 2:08PM 0:00.01 /opt/X11/bin/Xquartz :0 -listen tcp -iglx -auth /Users/user/.serverauth.97835` + +Now, XQuartz is listening on TCP, as indicated by `-listen tcp` + +To obtain the magic auth cookie from nebula, on nebula, or via remote login, run `xauth list` and find the correct cookie: + +`nebula:0 MIT-MAGIC-COOKIE-1 240800a1f435f70d92f8f8c706eeb547` + +On astra, add the cookie to the xauth list, using: + +`xauth add nebula:0 . 240800a1f435f70d92f8f8c706eeb547` + +If all went well, you should now be able to run xeyes from astra: + +`xeyes -display nebula:0` + +![one](/assets/img/t430/01.png) + +Things to watch out for: + +* XQuartz needs to be running :) +* The cookie needs to be up to date. It will change. +* There is a dot in the xauth add command that is required. + +Link to high res image of xdm login on the mac being served up by slackware xdm: + +* [two](/assets/img/t430/02-big.png) + + +Reach out to me if you find any issues or have suggestions. + +\- will + +*post last updated 2023-02-22 16:20:00 -0600* diff --git a/_posts/2023-06-27-ucb-stk-for-harveys-cs61a.markdown b/_posts/2023-06-27-ucb-stk-for-harveys-cs61a.markdown new file mode 100644 index 0000000..586580f --- /dev/null +++ b/_posts/2023-06-27-ucb-stk-for-harveys-cs61a.markdown @@ -0,0 +1,164 @@ +--- +layout: post +title: "UCB STk Scheme Interpreter for Working Through Brian Harvey's CS61A Course" +categories: development scheme ucb-stk +--- + +This note describes how to install the UCB STk 4.0.1 Scheme interpreter on modern 64 bit Debian based systems. It also describes a method of building the Debian Package used to install the program. This is the version of scheme used by Brian Harvey in his 2011 course, CS61A: Structure and Interpretation of Computer Programs, named after and using famed text, Structure and Interpretation of Computer Programs by Harold Abelson and Gerald Jay Sussman with Julie Sussman, a phenomenally good computer science textbook. + +Now, I'm not a package maintainer and I certainly don't know the nuances of building packages, this is just meant to document how I was able to get this working in 2023 after reading tons of "too bad, so sad, I can't get it to work posts", YMMV, but I've tested on LMDE5 (Elsie), Mint 21.1 (Vera), MX Linux 21.3 (Wildflower), and Ubuntu 22.04.2 (Jammy Jellyfish). + +Here's a screenshot of the working system running on LMDE5: + +![one](/assets/img/scheme/01.png) + + + +### Resources + +* CS561A: Structure and Interpretation of Computer Programs Video Lectures - [https://archive.org/details/ucberkeley-webcast-PL3E89002AA9B9879E](https://archive.org/details/ucberkeley-webcast-PL3E89002AA9B9879E) + +* UCB Scheme Webpage - [https://people.eecs.berkeley.edu/~bh/61a-pages/Scheme/](https://people.eecs.berkeley.edu/~bh/61a-pages/Scheme/) + +* Structure and Interpretation of Computer Programs 2nd ed. eBook - [https://web.mit.edu/6.001/6.037/sicp.pdf](https://web.mit.edu/6.001/6.037/sicp.pdf) + +* Erick Gallesio's github repo - [https://github.com/egallesio/STk](https://github.com/egallesio/STk) + +### Test Environments + +* IBM ThinkCentre M92p running Linux Mint Debian Edition 5 (Elsie) +* Virtualbox 7 running Linux Mint 21.1_64 (Vera) +* Virtualbox 7 running Ubuntu-22.04.2_64 (Jammy Jellyfish) +* Virtualbox 7 running MX-21.3_64 (Wildflower) + +### Build Environment +* Ubuntu 16.04.1 LTS 64 bit (not eol before mid 2026) - VirtualBox instance + +### Installation using the debian package + +The package requires that you have 32bit support in your environment which LMDE does. Other than this, it requires: + +* libsm6:i386 libx11-6:i386 along with their dependencies + +`sudo apt install libsm6:i386 libx11-6:i386` + +* [stk_4.0.1-1_amd64.deb](/assets/files/scheme/stk_4.0.1-1_amd64.deb) + +`sudo dpkg -i stk_4.0.1-1_amd64.deb` + +That should be all it takes, test it: + +`stk-simply` + +I usually install rlwrap so that I can get command history. If you want that then, install rlwrap: + +`sudo apt install rlwrap` + +Then add an alias or three to your .bashrc: + +``` +alias rlstk-simply='rlwrap stk-simply' +alias rlstk-explorin='rlwrap stk-explorin' +alias rlstk-grfx='rlwrap stk-grfx' +``` + +Then you can do stuff like this: + +![two](/assets/img/scheme/02.png) + +Yeah, I know. It's not all about the graphics or turtles, but hey - still kind of cool that it works. + +### Extras + +Since UCB Scheme is based on Erick Gallesio's STk, we can use the manual from STk for everything that's not a UCB Scheme extension. Here's the manual: + +[gallesio-1999-stk-4.0-manual.pdf](/assets/files/scheme/gallesio-1999-stk-4.0-manual.pdf) + +The differences between Gallesio's STk and the UCB Scheme environment are summed up in this document: + +[explorin-vs-simply.txt](/assets/files/scheme/explorin-vs-simply.txt) + +And an FAQ is also available: +[faq.html](/assets/files/scheme/faq.html) + +A quick test on my system: + +![three](/assets/img/scheme/03.png) + +### Build the Debian Package from the RPM distribution + +The first thing to do is to get the RPM. It is available here: + +[RPM distribution](http://inst.eecs.berkeley.edu/~scheme/precompiled/Linux/STk-4.0.1-ucb1.3.6.i386.rpm) + +or locally, here: + +[STk-4.0.1-ucb1.3.6.i386.rpm](/assets/files/scheme/STk-4.0.1-ucb1.3.6.i386.rpm) + + +The second thing to do is to download the Ubuntu 16.0.1 LTS 64 bit server image: + +[ubuntu-16.04.1-server-amd64.iso](https://old-releases.ubuntu.com/releases/16.04.6/ubuntu-16.04.1-server-amd64.iso) + +Create a new Virtual Box Instance and use Bridged Networking so your instance will get an IP address on your network. During installation, enable the SSH server. + +After the installation, get the IP address of the instance: + +``` +ifconfig +192.168.254.15 +``` + +From your host, scp the rpm file into the instance: + +`scp STk-4.0.1-ucb1.3.6.i386.rpm your_user@instanceip:STk-4.0.1-ucb1.3.6.i386.rpm` + +Then ssh into the instance: + +`ssh 192.168.254.15` + +Install some necessary applications and libraries: + +`sudo apt install alien libsm6:i386 libx11-6:i386 libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5 lib32z1` + +Create the debian package from the rpm: + +`fakeroot alien --target=amd64 STk-4.0.1-ucb1.3.6.i386.rpm` + +That's all there is to converting rpm to a 64 bit friendly debian package. On the host, scp the file from the instance: + +`scp your_user@instanceip:stk_4.0.1-1_amd64.deb ./stk_4.0.1-1_amd64.deb` + +Now, you have a deb file that can be saved off and reused. + +### Get a copy of the manual, build the unmodified source code + +Gallesio's STk is buildable, just realize that it isn't suitable for following the course. I include these instructions for the sake of getting the manual and for completeness. + +Get the source code and checkout the appropriate version: + +``` +cd ~/sandboxes-git +git clone https://github.com/egallesio/STk.git +cd STk +git checkout Version_4.0.1 +``` + +Convert the manual to pdf: + +`ps2pdf Doc/Reference/manual.ps ~/Desktop/gallesio-1999-stk-4.0-manual.pdf` + + +Build the source and optionally install it (don't do this if you have the modified program installed): + +``` +./configure +make +sudo make install +``` + +Reach out to me if you find any issues or have suggestions. + +\- will + +*post last updated 2023-06-27 21:24:00 -0600* diff --git a/_posts/2023-07-15-installing-and-using-research-unix-v7-in-open-simh-video.markdown b/_posts/2023-07-15-installing-and-using-research-unix-v7-in-open-simh-video.markdown new file mode 100644 index 0000000..a2b088d --- /dev/null +++ b/_posts/2023-07-15-installing-and-using-research-unix-v7-in-open-simh-video.markdown @@ -0,0 +1,16 @@ +--- +layout: post +title: Installing and Using Research Unix Version 7 on the OpenSIMH PDP-11 Emulator +date: 2023-07-14 12:34:00 -0600 +categories: unix research-unix v7 videos +--- + + + +A video walking the user through the process of installing and using Research Unix Version 7 on the Open SIMH PDP-11/45 and PDP-11/70 emulators. + +Enjoy! + + + +*post added 2023-07-15 20:34:00 -0600* diff --git a/_posts/2023-07-24-lisp-1.5.markdown b/_posts/2023-07-24-lisp-1.5.markdown new file mode 100644 index 0000000..0270e6e --- /dev/null +++ b/_posts/2023-07-24-lisp-1.5.markdown @@ -0,0 +1,251 @@ +--- +layout: post +title: LISP 1.5 running on an emulated IBM 7094 +date: 2023-07-24 12:23:00 -0600 +categories: LISP +--- +This note describes how to set up and run the oldest available ancestor of all extant LISPS and Schemes. + +LISP 1.5 was the first LISP that was made generally available. It is available to run on the OpenSIMH IBM 7094 emulator. + +![one](/assets/img/lisp/Terminal_001.png) + + + + +## Resources + +* **LISP 1.5 Programmer's Manual** [https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf) or grab a [local copy](/assets/files/lisp/LISP%201.5%20Programmers%20Manual.pdf) + +* **LISP 1.5 Primer** [https://www.softwarepreservation.org/projects/LISP/book/Weismann_LISP1.5_Primer_1967.pdf](https://www.softwarepreservation.org/projects/LISP/book/Weismann_LISP1.5_Primer_1967.pdf) or grab a [local copy](/assets/files/lisp/Weismann_LISP1.5_Primer_1967.pdf) + +* **OpenSIMH** [https://opensimh.org/](https://opensimh.org/) + +* **LISP 1.5 2023 tarball** [lisp15.2023.tar.gz](/assets/files/lisp/lisp15.2023.tar.gz) - note, this is a slightly modified version of Andre Luvisi's tarball. + +## Prerequisites + +* Linux - I'm running Debian 12 (bookworm) +* A build environement (make, cc, and ld) - build-essential package on debian systems +* OpenSIMH - any reasonably recent version should work + +## Getting Started + +* Create a workarea + +``` +mkdir -p ~/workarea/retro/lisp-1.5/{dist,work} +cd ~/workarea/retro/lisp-1.5/dist +``` + +* Download the tarball + +``` +wget https://decuser.github.io/assets/files/lisp/lisp15.2023.tar.gz +``` + +## Build the System + +* Unpack the tarball and the utils tarball inside it + +``` +cd ../work +tar xvzf ../dist/lisp15.2023.tar.gz +cd lisp15 +tar xvf utils-1.1.8.tar.gz +``` + +* Build the utils and copy txt2bcd to a directory on the path (critically important) + +``` +cd utils +make +cp ./txt2bcd ~/bin +``` + +* Test txt2bcd + +``` +txt2bcd +Usage: txt2bcd infile [outfile] [reclen, default 80 [blklen, default 84]] +``` + +* Clean up from utilts build + +``` +cd .. +rm -fr utils +``` + +* Actually build the system + +``` +make realclean; make +``` + +A successful build will result in a sysboot.tp in the current directory and a transcript similar to this: + +``` +rm -f sys.log scratch/* +(cd build; make clean) +make[1]: Entering directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build' +(cd boottape; make clean) +make[2]: Entering directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape' +rm -f syscore.tp sys.log scratch/* +make[2]: Leaving directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape' +make[1]: Leaving directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build' +rm -f sysboot.tp +(cd build; make realclean) +make[1]: Entering directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build' +(cd boottape; make clean) +make[2]: Entering directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape' +rm -f syscore.tp sys.log scratch/* +make[2]: Leaving directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape' +rm -f sysboot.tp boottape/lisp.obj +make[1]: Leaving directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build' +(cd build; make sysboot.tp) +make[1]: Entering directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build' +asm7090/asm7090 -o boottape/lisp.obj chist/lisp.job +(cd boottape; make) +make[2]: Entering directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape' +i7094 lispimg.ini library.txt + +IBM 7094 simulator Open SIMH V4.1-0 Current simh git commit id: cf47a20f +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape/lispimg.ini-13> at mta1 -r scratch/lisp.job.mt +%SIM-INFO: MTA1: unit is read only +%SIM-INFO: MTA1: Tape Image 'scratch/lisp.job.mt' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape/lispimg.ini-14> at mta2 scratch/systap.tp +%SIM-INFO: MTA2: creating new file +%SIM-INFO: MTA2: Tape Image 'scratch/systap.tp' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape/lispimg.ini-15> at mta3 syscore.tp +%SIM-INFO: MTA3: creating new file +%SIM-INFO: MTA3: Tape Image 'syscore.tp' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape/lispimg.ini-16> at mta4 scratch/syspot.tp +%SIM-INFO: MTA4: creating new file +%SIM-INFO: MTA4: Tape Image 'scratch/syspot.tp' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape/lispimg.ini-17> at mta5 scratch/sysppt.tp +%SIM-INFO: MTA5: creating new file +%SIM-INFO: MTA5: Tape Image 'scratch/sysppt.tp' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape/lispimg.ini-19> at cdr scratch/corrcards +%SIM-INFO: CDR: creating new file +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape/lispimg.ini-20> at cdp scratch/lispout.whatever +%SIM-INFO: CDP: creating new file +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape/lispimg.ini-21> at lpt sys.log +%SIM-INFO: LPT: creating new file + +HALT instruction, PC: 10524 (TRA 10523) +Goodbye +make[2]: Leaving directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build/boottape' +cp boottape/syscore.tp sysboot.tp +make[1]: Leaving directory '/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/build' +cp build/sysboot.tp sysboot.tp +``` + +## Run the system + +If you successfully built the system, you should be ready to run LISP 1.5. A few words are in order... Running LISP 1.5, so far as I can tell, consists of running the simulator against a tape image of a lisp source file. So, you type LISP 1.5 compatible code into a file and then invoke the emulator against that file. It processes your source and outputs the result. + +The tarball includes three source files that are in the correct format to be run in LISP 1.5: + +* factorial.txt - test code that will calculate the factorial of a number, in this case 10, which should result in 3,628,800. + +* funarg.txt - a function argument test + +* propcal.txt - test the Wang algorithm for propositional calculus + +To run them, invoke the emulator and provide the ini file to initialize the emulator and the text file with the source, for example, to run the factorial program type: + +``` +i7094 lisptape.ini factorial.txt +``` + +A successful run will generate a sys.log file and the output will resemble: + +``` +IBM 7094 simulator Open SIMH V4.1-0 Current simh git commit id: cf47a20f +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/lisptape.ini-12> at mta1 -r scratch/lisp.job.mt +%SIM-INFO: MTA1: unit is read only +%SIM-INFO: MTA1: Tape Image 'scratch/lisp.job.mt' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/lisptape.ini-13> at mta2 -r sysboot.tp +%SIM-INFO: MTA2: unit is read only +%SIM-INFO: MTA2: Tape Image 'sysboot.tp' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/lisptape.ini-14> at mta3 scratch/syscore.tp +%SIM-INFO: MTA3: Tape Image 'scratch/syscore.tp' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/lisptape.ini-15> at mta4 scratch/syspot.tp +%SIM-INFO: MTA4: Tape Image 'scratch/syspot.tp' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/lisptape.ini-16> at mta5 scratch/sysppt.tp +%SIM-INFO: MTA5: Tape Image 'scratch/sysppt.tp' scanned as SIMH format +/home/wsenn/workarea/retro/lisp-1.5/work/lisp15/lisptape.ini-20> at lpt sys.log +%SIM-INFO: LPT: creating new file + +HALT instruction, PC: 10524 (TRA 10523) +Goodbye +``` + +The results will be in the file sys.log: + +``` +cat sys.log + TEST FACTORIAL + + + + THE TIME ( 0/ 0 000.0) HAS COME, THE WALRUS SAID, TO TALK OF MANY THI +NGS ..... -LEWIS CARROLL- + EVALQUOTE OPERATOR AS OF 1 MARCH 1961. INPUT LISTS NOW BEING READ. + + + THE TIME ( 0/ 0 000.0) HAS COME, THE WALRUS SAID, TO TALK OF MANY THI +NGS ..... -LEWIS CARROLL- + FUNCTION EVALQUOTE HAS BEEN ENTERED, ARGUMENTS.. + DEFINE + + (((FACTORIAL (LAMBDA (X) (COND ((EQUAL X 0) 1) (T (TIMES X (FACTORIAL ( +SUB1 X))))))))) + + END OF EVALQUOTE, VALUE IS .. + *TRUE* + + FUNCTION EVALQUOTE HAS BEEN ENTERED, ARGUMENTS.. + FACTORIAL + + (10) + + + END OF EVALQUOTE, VALUE IS .. + 3628800 + + + + THE TIME ( 0/ 0 000.0) HAS COME, THE WALRUS SAID, TO TALK OF MANY THI +NGS ..... -LEWIS CARROLL- + END OF EVALQUOTE OPERATOR + FIN END OF LISP RUN +``` + +## Conclusions + +This was an interesting exploration. I enjoyed getting it up and running with a minimum of fuss. I didn't appreciate the fact that it was effectively a job submission environment and not an interactive system. + +Something to note is the use of evaluquote as the top-level, not eval... + +In the next exploration, I will investigate a system that is much more modern, yet directly descended from LISP 1.5. Rob Pike's LISP 1.5 interpreter in Go. A minimal implementation of 1.5's evalquote from pg. 13 of the Programming LISP 1.5 text. + + +### Afterthoughts + +Andre Luvisi's original work exists (for now) in Archive.org's repository of crawled pages: + +* **Luvisi's LISP 1.5 tarball** [https://web.archive.org/web/20211202101850/http://web.sonoma.edu/users/l/luvisi/lisp/lisp15.tar.gz](https://web.archive.org/web/20211202101850/http://web.sonoma.edu/users/l/luvisi/lisp/lisp15.tar.gz) + +It won't build because of duplicate names (fin and fon are defined in multiple files), but the fix is easy, just change line 19 of prsf2.c to read: + +``` +static char fin[300], fon[300]; +``` + +and it should work the same way as described above. + +Later - Will + +*post added 2023-07-24 19:28:00 -0600* diff --git a/_posts/2023-07-24-lisp-explorations.markdown b/_posts/2023-07-24-lisp-explorations.markdown new file mode 100644 index 0000000..c862526 --- /dev/null +++ b/_posts/2023-07-24-lisp-explorations.markdown @@ -0,0 +1,61 @@ +--- +layout: post +title: Schemes, LISPs, and Lambda +date: 2023-07-24 12:05:00 -0600 +categories: LISP +--- +This note sets up a series of related notes pertaining to my explorations in LISP and Scheme. I began to be interested in functional programming a few years ago and started looking around to find resources to learn it... in my limited spare time. After finding some resources, I would study it, set it aside as too esoteric, pick it up again thinking - this is it, I'm going to master this one way or another, only to set it aside as frustratingly difficult to understand and lacking in applicability. Lately though, I have found some standout resources and worked through enough of them to begin to actually get my mind wrapped around functional programming. Below you will find a brief, informal annotated bibliography of sorts and an explanation of what's coming in the further explorations into implementations. + + + +## Select Functional Programming Bibliography + +* **An Introduction to Functional Programming Through Lambda Calculus**, by Greg Michaelson, Dover, 2011 (reprint of Addison-Wesley 1989 edition). + +This text describes functional programming as it is realized in Church's Lambda Calculus. In order to "run" the programs, you need a language capable of working with lambda notation such as Standard ML (SML) [https://www.smlnj.org/](https://www.smlnj.org/). This is a very well articulated work that walks the reader through a series of discussions and exercises to illustrate the general nature of functional programming as a paradigm. + +* **Common LISP: An Interactive Approach**, by Stuart C. Shapiro, Computer Science Press, 1992. + +This book is a very easy read that teaches programming in common lisp using a set of question and answer dialogs between the author and reader. It starts off with an assumption that the reader knows nothing much more than how to start common lisp and takes the reader on a tour of the most important language features. If you want to put common lisp to use in solving problems, this is a fantastic book. It isn't really focused on teaching functional programming although its examples are functional in nature. Probably great if you are a learn by example reader. + +* **LISP: A Gentle Introduction to Symbolic Computation**, by David S. Touretzky, Harper & Row Publishers, 1984. + +This is a book targeting readers without prior programming experience. Its claims are modest, but it over delivers. The author clearly explains the basics of LISP and covers the language essentials quite completely. + +* **The Little Schemer**, 4th ed., by Daniel P. Friedman and Matthias Felleisen, MIT Press, 1996. + +This is an interesting text that could come across as cutesy and turn off the more serious minded reader. However, I enjoyed it. At first, I was annoyed that the premise being explored was not stated explicitly and up front, but after reading it more carefully, I decided that the approach was solid. Several key concepts are revealed to the reader through simple (seeming) here is some information, based on what you "know", what is the answer? here is the answer and why it is correct style dialogs that heavily leverage progressive disclosure. When you reflect on a section, you realize that you have learned an important piece of the language. + +* **Scheme and the Art of Programming**, by George Springer and Daniel P. Friedman, MIT Press, 1989. + +Daniel P. Friedman was a gifted explainer. This book is a very good explanation of how sheme works and how to put it to use. It is more traditionally presented than the Little Schemer and goes into considerably more depth. + +* **Simply Scheme: Introducing Computer Science**, 2nd ed., by Brian Harvey and Matthew Wright, MIT Press 1999. + +Harvey's book is one of my favorites. In it, the author teaches a number of Big Ideas, progressively. He starts off very simple and builds up to much more sophisticated constructions. The author chooses to use his own language, built on top of scheme and this is jarring, at first. But, if you spend any time with Scheme, you realize that all schemes are languages built on top of scheme's foundation and that this use of it is completely in line with scheme's vibe. Once you get past the language is not quite canonical scheme bit, it's actually genius how he abstracts the teaching of scheme away from the language itself and gets into the big ideas of computation as realized by the language. + +* **Structure and Interpretation of Computer Programs**, 2nd ed., by Harold Abelson, Gerald Jay Sussman, with Julie Sussman, MIT Press, 1996. + +This is a great book particularly when it is married to the author's video lectures from 1986 [https://www.youtube.com/watch?v=2Op3QLzMgSY](https://www.youtube.com/watch?v=2Op3QLzMgSY) Combined, this is top 10 CS course material. The lesson that sticks with me the most is how they distilled language down to providing three capabilities: + +1. Primitives +2. Means of combinations +3. Means of abstraction + +Just a great book, all around, but difficult in many ways. Which leads me to the point of all this discussion . Which is to say that reading books is one thing, working through them 20-30 years later, is quite another. I am a hands on learner. I get much more out of typing in programs and dealing with the errors that arise, than I do out of just reading page after page of description. + +All of the books above are available today, most are available as pdfs. + +## Exploring Implementations + +One cannot help but notice that the list of books above are Scheme or LISP books with the sole exception of the Lambda Calculus book. The question that immediately arises is, which Scheme or which LISP? As it turns out, this question is a tricky one. After having tried out every version of scheme and lisp I could get my hands on, I have come to the conclusion that Scheme and LISP are idealizations of Lambda Calculus facilitating languages - there is no true Scheme or LISP. + +There are so many variations, it is flat out ridiculous. That said, each of the books above used historically extant versions. Unfortunately, the authors of these books were not good about specificity. They usually claimed that their code would work with pretty much any reasonably complete (as of then) environment and gave appendices with their customizations that you could "port" to your environment. The good news is that folks have used these books over the decades and give us some hints as to current workable environments. + +I started exploring the environments with the intention of setting up specific environments for my work in these books, but after a bit, the exploration of environments became an interest in itself. Where did the Schemes and LISPS come from, what did those environments look like and how did they function? + +There'll be a lot less talk in the environment explorations and they will be set up as howtos. + +Thx - Will + +*post added 2023-07-24 19:28:00 -0600* diff --git a/_posts/2023-07-24-pike-lisp-1.5-in-go.markdown b/_posts/2023-07-24-pike-lisp-1.5-in-go.markdown new file mode 100644 index 0000000..73849c0 --- /dev/null +++ b/_posts/2023-07-24-pike-lisp-1.5-in-go.markdown @@ -0,0 +1,108 @@ +--- +layout: post +title: Rob Pike's LISP 1.5 in Go running on Debian 12 +date: 2023-07-24 13:35:00 -0600 +categories: LISP +--- +This note describes how to set up and run Rob Pike's LISP 1.5 in Go. + +LISP 1.5 was the first LISP that was made generally available. Rob Pike implemented a minimalist version of the EVALQUOTE function described on page 13 of the LISP 1.5 Programmer's Manual [https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf) or grab a [local copy](/assets/files/lisp/LISP%201.5%20Programmers%20Manual.pdf) + +![one](/assets/img/lisp/Terminal_002.png) + + + + +## Resources + +* **LISP 1.5 Programmer's Manual** [https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf) or grab a [local copy](/assets/files/lisp/LISP%201.5%20Programmers%20Manual.pdf) + +* **LISP 1.5 Primer** [https://www.softwarepreservation.org/projects/LISP/book/Weismann_LISP1.5_Primer_1967.pdf](https://www.softwarepreservation.org/projects/LISP/book/Weismann_LISP1.5_Primer_1967.pdf) or grab a [local copy](/assets/files/lisp/Weismann_LISP1.5_Primer_1967.pdf) + +## Prerequisites + +* Linux - I'm running Debian 12 (bookworm) + +## Getting Started + +* Get Go + +``` +cd ~/Downloads +wget https://go.dev/dl/go1.20.6.linux-amd64.tar.gz +``` + +* Install Go + +``` +sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.20.6.linux-amd64.tar.gz +``` + +* Add it to the path (logout and back in after making change) + +``` +vi ~/.bashrc +export PATH=$PATH:/usr/local/go/bin +``` + +* Create a work area + +``` +mkdir -p ~/workarea/go/pike +cd ~/workarea/go/pike +``` + +* Clone Rob Pike's repo + +``` +git clone https://github.com/robpike/lisp.git +``` + +* Initialize the module + +``` +cd lisp/ +go mod init +``` + +Should result in: + +``` +go: creating new go.mod: module robpike.io/lisp +go: to add module requirements and sums: + go mod tidy +``` + +* Tidy the module + +``` +go mod tidy +``` + +Good news is no news. + +* Build the module + +``` +go build +``` + +Again, good news is no news. + +* Run the lisp + +``` +./lisp lib.lisp +(fac gcd ack equal not negate mapcar length opN member union intersection) +> (add 1 3) +4 +> +^D +``` + +Tool around and try things out. Pretty amazing work. + + +Later - Will + +*post added 2023-07-24 19:28:00 -0600* diff --git a/_posts/2023-07-30-pdp-1-lisp.markdown b/_posts/2023-07-30-pdp-1-lisp.markdown new file mode 100644 index 0000000..4fcb020 --- /dev/null +++ b/_posts/2023-07-30-pdp-1-lisp.markdown @@ -0,0 +1,114 @@ +--- +layout: post +title: pdp1-lisp running on an emulated PDP-1 +date: 2023-07-30 12:38:00 -0600 +categories: LISP +--- +This note describes how to set up and run PDP-1 lisp. It's a pretty brief walkthrough. If you run into any issues, let me know. + + +![one](/assets/img/lisp/Terminal_003.png) + + + +PDP-1 LISP is a LISP 1.5 dialect created at BBN by L. Peter Deutsch. It was released as a DECUS tape in 1964, it currently runs on the Open SimH PDP-1 emulator. + +## Resources +* **The LISP Implementation for the PDP-1 Computer** +[https://www.computerhistory.org/pdp-1/_media/pdf/DEC.pdp_1.1964.102650371.pdf](https://www.computerhistory.org/pdp-1/_media/pdf/DEC.pdp_1.1964.102650371.pdf) + +* **OpenSIMH** [https://opensimh.org/](https://opensimh.org/) + +* **Trailing-edge Software Kits** [http://simh.trailing-edge.com/software.html](http://simh.trailing-edge.com/software.html) + +## Prerequisites + +* Linux - I'm running Debian 12 (bookworm) +* A build environement (make, cc, and ld) - build-essential package on debian systems +* OpenSIMH - any reasonably recent version should work + +## Getting Started + +* Create a workarea + +``` +mkdir -p ~/workarea/retro/pdp-1-lisp +cd ~/workarea/retro/pdp-1-lisp +``` + +* Download the pdp-1 lisp software kit and upack it + +``` +wget http://simh.trailing-edge.com/kits/lispswre.zip +unzip lispswre.zip +``` + +## Compile the macro assembler + +`cc macro1.c -o macro1` + +## Assemble the lisp interpreter + +`./macro lisp.mac` + +## Create an ini file for the PDP-1 emulator + + +``` +cat <run.ini +set cpu mdv +load lisp.rim +d extm_init 1 +run + +d tw 7777 +c + +d tw 400 +c + +d ss 2 +save lisp.sav + +echo READY +c +EOF +``` + +## Run the emulator and load the lisp binary + +``` +pdp1 run.ini + +PDP-1 simulator Open SIMH V4.1-0 Current simh git commit id: cf47a20f + +HALT instruction, PC: 002353 (CLA LAT CLI) + +HALT instruction, PC: 002357 (CLA LAT) + +HALT instruction, PC: 000005 (STF6) +READY +``` + +The system is ready to act as a repl, but it's funny, you have to end a lisp form with a space in order for the interpreter to process it! So, if you want to add two numbers, you would use +(plus 2 2) , with a trailing space - as in, (plus 2 2), replacing with the actual space character ' '. + +The system will reply with the evaluation: + +a + +To end the simulation, type CTL-e, then at the sim> prompt type q to exit. + +A full session would look like this: + +![one](/assets/img/lisp/Terminal_003.png) + + +If you encounter an interpreter error, during your session, the system will halt after displaying the error message, but can often be continued, by typing `c` at the sim> prompt. + +This is similar to modern lisps that dump you into a debugger where you can look around and then restart the interpreter, only the debugger, in this case, is simh. + + +Later - Will + +*post added 2023-07-30 20:02:00 -0600* diff --git a/_posts/2023-07-31-franz-lisp.markdown b/_posts/2023-07-31-franz-lisp.markdown new file mode 100644 index 0000000..434adbd --- /dev/null +++ b/_posts/2023-07-31-franz-lisp.markdown @@ -0,0 +1,354 @@ +--- +layout: post +title: "Franz LISP Opus 32 in 3BSD running on an emulated VAX 780" +date: 2023-07-31 07:03:00 -0600 +categories: LISP +--- +This note describes how to set up and run Franz LISP Opus 32 running on 3BSD running on an emulated VAX 780. This version of Franz LISP is Opus 32 and it is a LISP 1.5 derived LISP from 1979. + +![one](/assets/img/lisp/Terminal_004.png) + + +Wikipedia notes: + +> In computer programming, Franz Lisp is a discontinued Lisp programming language system written at the University of California, Berkeley (UC Berkeley, UCB) by Professor Richard Fateman and several students, based largely on Maclisp and distributed with the Berkeley Software Distribution (BSD) for the Digital Equipment Corporation (DEC) VAX minicomputer. Piggybacking on the popularity of the BSD package, Franz Lisp was probably the most widely distributed and used Lisp system of the 1970s and 1980s. + +> The name is a pun on the composer and pianist Franz Liszt. + +## Resources + +* **3BSD Tape File** [https://sourceforge.net/projects/bsd42/files/Install%20tapes/3%20BSD/](https://sourceforge.net/projects/bsd42/files/Install%20tapes/3%20BSD/) + +* **Franz Lisp Manual - Opus 38.69 from 1982** [https://www.softwarepreservation.org/projects/LISP/franz/Franz_Lisp_July_1983.pdf](https://www.softwarepreservation.org/projects/LISP/franz/Franz_Lisp_July_1983.pdf) + +This is the earliest manual I could find. When you're online in 3BSD, there is documentation for the Franz LISP Opus 32, in `/usr/doc/lisp`. + +* **Gunkies 3BSD Page** [https://gunkies.org/wiki/3BSD](https://gunkies.org/wiki/3BSD) + +An invaluable resource for getting things up an running with a minimum of fuss. + +* **OpenSIMH** [https://opensimh.org/](https://opensimh.org/) + +The simulator I'm using. + +## Prerequisites + +* Linux - I'm running Debian 12 (bookworm) +* A build environement (make, cc, and ld) - build-essential package on debian systems +* OpenSIMH - any reasonably recent version should work + +## Overview + +Much of this note is based on the Gunkies 3BSD page. Specifically, tboot.ini, dboot.ini, uudecode, and the 3BSD boot block are from that page [https://gunkies.org/wiki/3BSD](https://gunkies.org/wiki/3BSD). This note is just organized differently and getting 3BSD running here, is specifically for running Franz LISP. + +## Getting Started + +* Create a workarea + +``` +mkdir -p ~/workarea/retro/franz/{dist,work} +cd ~/workarea/retro/franz/dist +``` + +* Download 3BSD and a bootblock + +``` +wget https://decuser.github.io/assets/files/lisp/3bsd.tap.bz2 +wget https://decuser.github.io/assets/files/lisp/boot3bsd +``` + +* Verify you have the right files + +``` +shasum * +f8b59d933896678f04e9a0b0284466563d650c24 3bsd.tap.bz2 +482464bbd3ceb8ec9f02036ad06dbe5a181572e2 boot3bsd +``` + +* Unpack the tape file and copy the bootblock into work + +``` +cd ../work +bzcat ../dist/3bsd.tap.bz2 > 3bsd.tap +cp ../dist/boot3bsd . +``` + +* Create an ini file for booting from tape + +``` +cat <tboot.ini +set tto 7b +set rq dis +set lpt dis +set rl dis +set hk dis +set rq dis +set rqb dis +set rqc dis +set rqd dis +set ry dis +set ts dis +set tq dis +set dz lines=8 +set rp0 rp06 +at rp0 rp06.disk +set tu0 te16 +at tu0 3bsd.tap +D 50000 20009FDE +D 50004 D0512001 +D 50008 3204A101 +D 5000C C113C08F +D 50010 A1D40424 +D 50014 008FD00C +D 50018 C1800000 +D 5001C 8F320800 +D 50020 10A1FE00 +D 50024 00C139D0 +D 50028 04c1d004 +D 5002C 07e15004 +D 50030 0000f750 +go 50000 +go 0 +EOF +``` + +## Build the system + +* Boot to tape + +``` +vax780 tboot.ini +/home/wsenn/workarea/retro/franz/work/tboot.ini-15> at rp0 rp06.disk +%SIM-INFO: RP0: Creating new file: rp06.disk +/home/wsenn/workarea/retro/franz/work/tboot.ini-17> at tu0 3bsd.tap +%SIM-INFO: TU0: Tape Image '3bsd.tap' scanned as SIMH format + +HALT instruction, PC: 00050033 (HALT) += +``` + +* Restore Unix + +`=` is the tape's minimal OS prompt. From here we will make a new filesystem on the rp06 and restor unix from the tape to the disk. +``` +=mkfs +file sys size: 7942 +file system: hp(0,0) +isize = 5072 +m/n = 3 500 +=restor +Tape? ht(1,1) +Disk? hp(0,0) +Last chance before scribbling on disk. +End of tape += +``` + +Press enter after `Last chance before scribbling on disk.` to continue. + +* Restore `/usr` + +Boot Unix, make a new fileystem for /usr, and restore it from tape. + +``` +=boot + +Boot +: hp(0,0)vmunix +61856+61008+70120 start 0x4B4 +VM/UNIX (Berkeley Version 2.7) 2/10/80 +real mem = 8323072 +avail mem = 8062976 +ERASE IS CONTROL-H!!! +# /etc/mkfs /dev/rrp0g 145673 +isize = 65488 +m/n = 3 500 +# /etc/mount /dev/rp0g /usr +# cd /usr +# cp /dev/rmt5 /dev/null +# cp /dev/rmt5 /dev/null +# tar xbf 20 /dev/rmt1 +# +``` + +The restore can take a couple of minutes, be patient. The two lines: + +``` +# cp /dev/rmt5 /dev/null +# cp /dev/rmt5 /dev/null +``` + +Are just a way to get the tape device to fast forward to the tape file we want. + +* Cleanly shut unix down + +First we will sync and unmount any mounted devices, then we will sync our system. This is the "normal" way to shut down the unix environment in simh + +``` +# sync +# sync +# sync +# cd / +# /etc/umount /dev/rp0g +# sync +# sync +# sync +# ^E +Simulation stopped, PC: 8000085F (BLBC 80010FA0,8000085F) +sim> q +Goodbye +$ +``` + +* Backup the baseline system + +`tar cvzf rp06-baseline.tar.gz rp06.disk` + +## Boot the system and run Franz LISP + +* Create a disk boot ini + +``` +cat <dboot.ini +set tto 7b +set rq dis +set lpt dis +set rl dis +set hk dis +set rq dis +set rqb dis +set rqc dis +set rqd dis +set ry dis +set ts dis +set tq dis +set dz lines=8 +set rp0 rp06 +at rp0 rp06.disk +set tu0 te16 +load -o boot3bsd 0 +go 2 +EOF +``` + +* Boot to disk + +``` +$ vax780 dboot.ini + +VAX 11/780 simulator Open SIMH V4.1-0 Current simh git commit id: cf47a20f + +Boot +: +``` + +At the `:` prompt, provide the location of the kernel, `hp(0,0)vmunix` + +``` +: hp(0,0)vmunix +61856+61008+70120 start 0x4B4 +VM/UNIX (Berkeley Version 2.7) 2/10/80 +real mem = 8323072 +avail mem = 8062976 +ERASE IS CONTROL-H!!! +# +``` + +Change the root password. It needs to be at least 6 characters long. + +``` +# passwd root +New password: +Retype new password: +# +``` + +To go into multi-user mode, press `^d`. this will allow you to login. Login as root with the new password. + +``` +#^D +Sat Aug 30 06:40:18 PDT 1980 +entering rc +clearing mtab +mounting /usr on /dev/rp0g +preserving Ex temps and clearing /tmp +starting update +starting cron +leaving rc + + +Virtual VAX/UNIX (Ernie Co-vax) + +login: root +Password: + +Welcome to Virtual Vax/UNIX. +ERASE IS CONTROL-H!!! +# +``` + +* Run Franz LISP Opus 32 + +Run Franz in all of its 1979 glory! Type `(exit)` at the `->` prompt when you are ready to leave the lisp environment. + +``` +# lisp +Franz Lisp, Opus 32 +-> (+ 4 4) +8 +-> (car (cdr '(Hi there))) +there +->(exit) +# +``` + +* Celebrate by backing up the working instance + +``` +# sync +# sync +# sync +# ^E +Simulation stopped, PC: 8000085F (BLBC 80010FA0,8000085F) +sim> q +Goodbye +$ tar cvzf rp06-working.tar.gz rp06.disk +rp06.disk +$ +``` + +Now, anytime you want to run franz lisp, just reenter the directory with your dboot.ini and rp06.disk and type `vax780 dboot.ini`, boot the unix kernel, hit ^d at the prompt, and login as root with your new password! + +Here's a typical session: + +![one](/assets/img/lisp/Terminal_004.png) + +## Creating the bootblock from uuencoded sources + +boot3bsd, the bootblock was created from Gunkies uuencoded source [http://gunkies.org/wiki/3BSD_bootsector](http://gunkies.org/wiki/3BSD_bootsector), using Gunkies uudecode program [http://gunkies.org/wiki/Uudecode](http://gunkies.org/wiki/Uudecode). Here is the process I followed to create the bootblock: + +* Download uudecode source from above and save it as `uudecode.c``. + +* Download uuencoded bootblock from above and save it as `boot3bsd.uu` + +* Compile uudecode and use it to unencode the bootblock. + +``` +cc -o uudecode uudecode.c +./uudecode boot3bsd.uu +``` +Ignore the warnings, they're irrevant to this process. + + +* Confirm the result + +``` +shasum boot3bsd +482464bbd3ceb8ec9f02036ad06dbe5a181572e2 boot3bsd +``` + +That's it. + +Later - Will + +*post added 2023-07-31 11:55:00 -0600* diff --git a/_posts/2023-07-31-maclisp.markdown b/_posts/2023-07-31-maclisp.markdown new file mode 100644 index 0000000..99faeda --- /dev/null +++ b/_posts/2023-07-31-maclisp.markdown @@ -0,0 +1,522 @@ +--- +layout: post +title: "MACLISP in ITS running on an emulated PDP-10" +date: 2023-07-31 09:03:00 -0600 +categories: LISP +--- +This is a longer note that describes the process of getting ITS (Incompatible Timesharing System) up and running in order to run MACLISP. ITS is quite a large system and it has many different programming languages and programs available. In this note, we will only be using lisp and emacs, but future notes will explore logo, and perhaps other languages found in the distribution. + +![one](/assets/img/lisp/Terminal_006.png) + + + + +## Resources + +* **The ITS operating system github repo** [https://github.com/PDP-10/its](https://github.com/PDP-10/its) + +* **The MACLISP manual** [http://www.maclisp.info/pitmanual](http://www.maclisp.info/pitmanual) + +* **OpenSIMH** [https://opensimh.org/](https://opensimh.org/) + +## Prerequisites + +* Linux - I'm running Debian 12 (bookworm) +* A build environement (make, cc, and ld) - build-essential package on debian systems +* OpenSIMH - any reasonably recent version should work + +## Getting Started + +* Install some dependencies + +The pdp10-ka emulator requires - git, c compiler, make, expect, curses, autoconf, sdl2, sdl2-image, sdl2-net, gtk3. You will also need telnet and some network dependencies. Generally, whenever something complains about a missing dependency, google it and then `sudo apt install whatever`. + +My own incanation was: + +``` +sudo apt install -y bridge-utils build-essential expect gawk git libgtk-3-dev libpcap-dev libpcre3-dev ncurses-base ncurses-bin libncurses5-dev libpcap-dev libsdl2-2.0-0 libsdl2-dev libsdl2-image-dev libsdl2-net-dev make net-tools telnet uml-utilities +``` + +* Create a Workarea + +``` +mkdir -p ~/workarea/retro/its/{dist,work} +cd ~/workarea/retro/its/dist +``` + +* Clone the ITS repository + +``` +git clone https://github.com/PDP-10/its.git +``` + +* Download a working system + +This will just take a few minutes. The repo can also be completely built from source, but that takes a long time (an hour or more). + +``` +cd its +make download EMULATOR=pdp10-ka +``` + +## Prepare the sytem to be run + +* Backup the original run file, so we can edit it + +``` +cp out/pdp10-ka/run out/pdp10-ka/run.original +``` + +* Edit the run file for no network to start + +``` +vi out/pdp10-ka/run +# comment out lines dealing with imp +# set imp enabled +# set imp mac=e2:6c:84:1d:34:a3 +# set imp ip=192.168.2.101/24 +# set imp gw=172.31.1.100 +# set imp host=10.3.0.6 +# at imp tap:tap0 +``` + +* Create a back up of the untested baseline + +This is a good starting point. If you run into problems, you can revert to this baseline without having to redownload stuff. + +``` +cd .. +tar cvjf untested-baseline.tar.bz2 its/build/pdp10-ka its/start its/out its/tools/sims/BIN/pdp10-ka +``` + +* Unpack the basline into work + +``` +cd ../work +tar xvf ../dist/untested-baseline.tar.bz2 +cd its +``` + +## Run ITS the first time + +* Start the simulator + +``` +./start +KA-10 simulator V4.0-0 Current git commit id: 48186c90 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-22> at -u tk 10000 speed=300 +%SIM-INFO: Listening on port 10000 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-25> at -u dpk 10002 speed=4800 +%SIM-INFO: Listening on port 10002 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-26> at -u dpk line=11,10019 speed=4800 +%SIM-INFO: Line 11 Listening on port 10019 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-27> at -u dpk line=15,10020 speed=4800 +%SIM-INFO: Line 15 Listening on port 10020 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-29> at -u mty 10003 speed=50000 +%SIM-INFO: Listening on port 10003 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-30> at -u mty line=9,10018 speed=9600 +%SIM-INFO: Line 9 Listening on port 10018 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-31> at -u mty line=8,10017 speed=9600 +%SIM-INFO: Line 8 Listening on port 10017 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-32> at -u mty line=7,10016;notelnet speed=50000 +%SIM-INFO: Line 7 Listening on port 10016 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-33> at -u mty line=6,10015 speed=9600 +%SIM-INFO: Line 6 Listening on port 10015 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-35> at ten11 10011 +%SIM-INFO: Listening on port 10011 +/home/wsenn/workarea/retro/its/work/its/out/pdp10-ka/run-37> at auxcpu 10006 +%SIM-INFO: Listening on port 10006 + + DSKDMP +``` + +If all went well, nothing failed and you ITS prints DSKDMP in the terminal window. + +* Start ITS + +When DSKDMP is displayed, you can start ITS by typing `itsg` and it will start working. Ignore the NET message. We haven't provided a working network, and won't in this note. It isn't needed. + +``` +DSKDMP +its +$G +SALVAGER.317 + + +IT IS NOW 3:25:48 PM EDT, MONDAY, JUL 31, 2023 + +KA ITS 1651 IN OPERATION AT 15:25:48 +KA ITS 1651 SYSTEM JOB USING THIS CONSOLE. +TV 11 WENT DOWN -- 15:25:48 + LOGIN TARAKA 0 15:25:49 +TOP LEVEL INTERRUPT 200 DETACHED JOB # 4, USR:TARAKA CNAVRL 15:25:50 +NET: TIMED OUT TRYING TO COME UP 15:25:58 +IT IS NOW 3:26:17 PM EDT, MONDAY, JUL 31, 2023 + LOGIN .BATCH 0 15:26:50 + LOGIN GUNNER 0 15:27:50 +``` + +## Login to ITS over telnet (locally) + +* Determine the port + +After the time is displayed, you can connect via telnet or login at the console itself. Let's connect via telnet. Look up above to where the dpk is attached: + +``` +...> at -u dpk 10002 speed=4800 +%SIM-INFO: Listening on port 10002 +``` + +* Connect to the ITS sever using telnet + +That's our telnet port, fire up telnet and connect: + +``` +$ telnet localhost 10002 +Trying ::1... +Connected to localhost. +Escape character is '^]'. + + +Connected to the KA-10 simulator DPK device, line 0 +``` + +* Initiate a session + +To begin a session with ITS, press `C-z`, that is press and hold Ctrl and z at the same time. In this note anytime you see C-char, this is a control chord and works this way. If you see M-char, it means press Esc, let it go, then press the char. The ordinary Meta-char chord where you press Alt and char at the same time doesn't seem to work. Alternatively and in the output a control chord may appear as ^char. + +``` +^Z +KA ITS.1651. DDT.1548. +TTY 21 +You're all alone, Fair share = 99% +Welcome to ITS! + +For brief information, type ? +For a list of colon commands, type :? and press Enter. +For the full info system, type :INFO and Enter. + +Happy hacking! +``` + +* Actually login to ITS + +And it's ready for you to login. The system is not secure, which is a good thing. Sorta like when you live somewhere where you don't have to lock the doors - hint, move outta the city... but still, lock the doors :). + +So, to login we will use a : command, that is a command that begins with a colon. The command to login is `:login loginname`. Initials were in vogue back when, so I will use my initials: + +``` +:login wds +``` + +The system will respond with: + +`KA: WDS; WDS MAIL - NON-EXISTENT DIRECTORY` + +No worries, even though it complains about a non-existent directory, it'll log you in anyway. + +## First Steps + +In this section we will set the terminal type, create a user directory and log out and back in so that ITS knows about the directory going forward. Otherwise, ITS will occasionally refuse to acknowledge the existence of the directory, usually at inopportune moments like when you are trying to save a ledit session. + +* Set the terminal type + +We need to tell ITS about our terminal (it may think we're a line printer terminal ATM). The command needed here is `:tctyp AAA`: + +``` +:tctyp AAA +:KILL +* +``` + +* Create the user directory + +This is a little tricky and a lot weird, but what we are going to do is type `wds; ..new. (udir).` where is an actual carriage return. This will create a new directory named `wds`: + +``` +^R wds; ..new. (udir). +DSK: WDS; ..NEW. (UDIR) - FILE NOT FOUND +``` + +Ignore the FILE NOT FOUND error, it created the directory. To see this, change into the directory and type `C-f` to see the files, or just type `:listf wds;`. I'll stop saying `` after : commands from this point forward, just know you need to end : commands with ``. + +``` +:cwd wds +^F +KA WDS +FREE BLOCKS #2=784 #3=1523 #0=568 #1=1541 +* +``` + +* Create a file in the directory to keep the salvager happy + +Apparently, there is a salvager that will get rid of empty directories. Let's create a file in the directory. Let's use emacs (this is a VERY early version, but should be quite familiar to any current emacs user). This version is a set of macros running in TECO, after RMS renamed it to EMACS, but before it became a standalone editor: + +``` +:emacs --read-- --me-- +``` + +Yup, that's exactly as typed, files have two names (somebody smarter than me knows why, just trust me for now). This file is called "--read--" and "--me--". For me it's easier to just think of it as a name and extension separated by a space instead of a ., but ymmv. + +The screen should clear and emacs should fire up in all it's ancient glory: + +![two](/assets/img/lisp/Terminal_005.png) + + +Let's enter `This file is to prevent directory salvage.`, Then type `C-x C-s` to save and `C-x C-c` to exit emacs. See, familiar, and easy right (says the :wq vi guy)? Then to list the file in the directory, type `C-f`: + +``` +*^F +KA WDS +FREE BLOCKS #2=784 #3=1523 #0=568 #1=1540 + 2 --READ --ME-- 1 ! 7/31/2023 15:57:23 +* +``` + +yay? I think so, and hopefully, you feel the same way. + +* Logout and back in again + +Let's quickly logout and back in to get ITS to recognize our user directory properly: + +``` +:logout +KA ITS 1651 Console 21 Free. 16:32:00 +``` + +and back in with `C-z`: + +``` +^Z +KA ITS.1651. DDT.1548. +TTY 21 +You're all alone, Fair share = 99% +Welcome to ITS! + +For brief information, type ? +For a list of colon commands, type :? and press Enter. +For the full info system, type :INFO and Enter. + +Happy hacking! +:login wds + +To see system messages, do ":MSGS" +``` + +and set the terminal type: + +``` +tctyp AAA +:KILL +* +``` + +## Program in MACLISP + +Let's create some lisp and run MACLISP. This example uses emacs initially to create a lisp source file, then we run lisp standalone, load the file we created and use it's function in our interpreter session. Then we will use ledit, a special mode of MACLISP using emacs from MACLISP on a special buffer. + +* Use emacs to create the file `addtwo lisp`: + +``` +:EMACS addtwo lisp + +(defun addtwo (x y) + (+ x y)) +``` + +If you've been cutting and pasting as you followed along with the note, you might find that doesn't work so great with emacs, so be careful. You may need to do it a line at a time. Anyway, enter the text, then `C-x C-s` and `C-x C-c`. + +* Run MACLISP + +``` +*:LISP +LISP 2156 +Alloc? n +* +``` + +We're in! Let's load our lisp file: + +``` +(LOAD "addtwo lisp") +T +``` + +Lisp responds T if it was able to load. Let's use it in our session: + +``` +(addtwo 5 3) +10 +``` + +Sure 5+3 is 8, right? Ha, it's base 8 (octal). Yes, you can change it, but it is running on a dec vm, so base 8 is just, right, right? + +That's it for this first session, let's quit: + +``` +(quit) +:KILL EMACS0$J +* +``` + +![one](/assets/img/lisp/Terminal_006.png) + +yay again! + + +* Use LEDIT in MACLISP + +Let's use ledit now. Start lisp up again, and invoke (ledit) straightaway: + +``` +*:LISP +LISP 2156 +Alloc? n +* +(ledit) +``` + +As soon as you type the closing parenthesis, emacs ledit will start up and your cursor will be top-left. The status line will display: `EMACS LEDIT (LISP) Main: *`: + +![three](/assets/img/lisp/Terminal_007.png) + +In ledit, let's create the timestwo function: + +``` +(defun timestwo (x y) + (* x y)) +``` + +This time, we will use some ledit magic and not treat it as a normal emacs session. To push the defined funtion to the environment, press `M-z` ( let go, then 'z'), then to exit ledit and return to lisp, type `C-x z`. + +``` +;Reading from LEDIT +TIMESTWO +;Edit Completed + +* +``` + +Let's try it out in our lisp environment: + +``` +(timestwo 5 2) +12 +``` + +Nice, and correct! + +We can still load the existing lisp file and use it too: + +``` +(load "addtwo lisp") +(addtwo (timestwo 2 3) (timestwo 3 7)) +33 +``` + +Cool. + +* Exit LISP + +Let's exit lisp: + +``` +(quit) +:KILL LEDIT$J +* +``` + +![four](/assets/img/lisp/Terminal_008.png) + +## Shutdown the system + +To bring the system down, we will first logout out of our user account with `:logout`. Then we will `:login` with no user and proceed with a normal shutdown (if you don't logout of the user account first, the shutdown will take 5 minutes). + +* Logout of the user account + +``` +* :logout + +KA ITS 1651 Console 21 Free. 16:42:56 +``` + +* Login as an unnamed user + +``` +^Z +KA ITS.1651. DDT.1548. +TTY 21 +You're all alone, Fair share = 99% +Welcome to ITS! + +For brief information, type ? +For a list of colon commands, type :? and press Enter. +For the full info system, type :INFO and Enter. + +Happy hacking! +``` + +* Initiate the shutdown + +First we initiate lock with `:lock`, then initiate the shutdown with `5down`, we will answer `Y` and `byeC-c`, to the prompts: + +``` +:lock +(Please Log In) + LOCK.156 +_5down +DO YOU REALLY WANT THE SYSTEM TO GO DOWN? +Y +___002 LOCK SYS DOWN MAIL WRITE + +PLEASE ENTER A BRIEF MESSAGE TO USERS, ENDED BY ^C +bye^C + +KA ITS 1651 NOT IN OPERATION 16:45:23 +``` + +Since we are running in a telnet session, we can just end it. To exit telnet, press `^]` and at the telnet> prompt, type `q`: + +``` +^] +telnet> q +Connection closed. +$ +``` + +You can close the terminal and switch to the other terminal with our console session. You will see some console messages that are new and the last few should look like: + +``` +SHUTDOWN COMPLETE +PI LEVEL 7 BUGDDT. TYPE P TO CONTINUE. +YOU ARE NOW IN DDT. +BUGPC/ CAI COFFI4+1 $Q-2/ JRST COFFI7 +``` + +At this point ITS is shut down. To exit, we will type `^\` to suspend the emulator and return to the sim> prompt, then type `q` to exit the sim: + +``` +^\ +Simulation stopped, PC: 773121 (CONSO 120,40) +sim> q +Goodbye +$ +``` + +## Back up the working system + +It is a really good idea to back up the tested working system. This way, you can always get back to what worked with minimal fuss: + +``` +cd ../../dist +tar cvjf tested-working.tar.bz2 its/build/pdp10-ka its/start its/out its/tools/sims/BIN/pdp10-ka +``` + +That's it for now. In another note, I will walk through setting up networking and using LOGO in ITS with a graphical terminal and turtle. + +Let me know if you run into any issues. + +Later, Will + + +*post added 2023-07-31 18:07:00 -0600* diff --git a/_posts/2023-12-19-geometry-explorations.markdown b/_posts/2023-12-19-geometry-explorations.markdown new file mode 100644 index 0000000..7091175 --- /dev/null +++ b/_posts/2023-12-19-geometry-explorations.markdown @@ -0,0 +1,27 @@ +--- +layout: post +title: Geometry Explorations +date: 2023-12-19 05:05:00 -0600 +categories: GEOMETRY +--- +This note sets up a series of related notes pertaining to my explorations in Geometry and by extension, Maths. + +The explorations are my work in trying to make sense of the world through math. They are presented here, in part, to motivate me to express my thoughts in a more organized fashion than I might otherwise, and in part to share in the hopes that some small few might benefit or wish to chat about things. + +So, enjoy and if you do, feel free to email me about it. + + + +The notes to come are not mathematical treatises, they are mostly me trying to figure stuff out. I expect they will be superseded with more intelligible writings as I learn more, but they are not definitive. They are more like a journal where I lay out my thoughts of the moment. + +I have always found math confusing and so much of it lacking comprehensibility or cohesion. When I came across Geometry, as part of my personal remediation plan doing Saxon Math, begun about 7 years ago. I was stunned to find something that actually made sense, was coherent and cohesive. It turns out that Euclid, writer of the Elements of Geometry, established by example, one of the greatest models of thought that the world has ever known. I dug in to his subject, Geometry, and I dug in hard. I worked through propositions referenced by Saxon, in the Elements. I was mesmerized, but not at first. At first, it seemed incredibly difficult to understand, but after many, many hours of work and contemplation, it clicked and I got it... even if I couldn't apply it in novel circumstances without great difficulty on the drop of a dime. But, I felt like I could see where it was coming from and where it was going. Thank you Euclid and thank you John Saxon for introducing me to the subject in such an accessible way. + +Before I dive into the explorations, I feel compelled to defend Euclid, who while appreciated by many, is mocked unfairly at times by folks. Euclid's postulates are not complete. He made some assumptions that people eventually decided were unwarranted. He didn't prove every case of every postulate. Other geometries are possible and valid. So what? Euclid wrote a work of mathematics that lives as the finest example of mathematics ever written (to date). He didn't write a book on how to write axiomatically, or how to write with rigor. If he had, things would have been quite different. Rather, he showed the world, by example, how to write a book with axioms and rigor, that would stand as the eminent example of how to do so, for the better part of two and a half millennia. + +I find it amusing and bemusing that folks spend vast amounts of time and energy learning Euclid's work, only to turn around and smugly criticize its flaws. To my mind they are like children who want to show their independence from their parents - meanwhile, everyone can see by looking that they are their parent's children. In a similar vein, modernists from David Hilbert to Bertrand Russell, while widely criticizing Euclid, so clearly resemble their forbear, that it beggars belief. Its shocking to me that they wouldn't simply correct the flaws inherent in his work (as an exemplar of a mindset) and extend it, without bad-mouthing it. These geniuses, and geniuses they so clearly are, have not, with all there labor achieved a work as influential as the work attributed to Euclid. + +Anyway, enough ranting, off to explore :). + +-- will + +*post added 2023-12-19 12:27:00 -0600* diff --git a/_posts/2023-12-19-wills-geometry.markdown b/_posts/2023-12-19-wills-geometry.markdown new file mode 100644 index 0000000..ff87002 --- /dev/null +++ b/_posts/2023-12-19-wills-geometry.markdown @@ -0,0 +1,90 @@ +--- +layout: post +title: Will's Geometry - A Setting Out. +date: 2023-12-19 06:05:00 -0600 +categories: GEOMETRY +--- + +This is a note where I begin to develop my own geometry based on the example of Euclid, but with an eye towards addressing its shortcomings - what hubris?! But seriously, I'm pretty sure my geometry will pale in comparison. The purpose of the exploration is not to show off, but to learn more about the world and in this regard, will be interesting and educational. + + + +Gotta start somewhere! + +Start from first principles - the evidents. + +Shapes exist and are perceived. That is, we see and describe the world around us in abstract terms and shapes are abstract. As we abstract away details and try to describe things that exist, we highlight some things / aspects of things, and disregard others. We strive to arrive at useful ways of referring to groups of / sets of objects. Geometry, which started as a way of measuring land, has evolved into an ever-abstracting study of shape. What is shape? Wow, so hard to establish the bare necessities. Maybe a shape is a collection of points? What is a collection and what is a point? + +Let's just say (posit) that a collection is just what it sounds like, one or more than one of something, or nothing at all (for convenience, later). In this case, a collection of points. A point being the idea of the smallest thing (or not thing), imaginable. We represent this idea generally with a dot drawn on a page. Keep in mind that a point is an idea and doesn't have width, height, or any physical measure, whereas the dot does. + +Maybe think of the dot as a graph (physical representative) of the point and imagine zooming in on the dot, imagine it never changing in appearance, whereas the area around it expands, endlessly. + +We have our first postulates: + +* a point is an idea that can be represented by a dot. It has no measure. +* a collection (set) is a collection of zero or more points. + +What can we do with our postulates? Not much, at this "point" :). We can put points into a collection and take them out again. We can imagine that our collection, thus created, refers to different points. But, if a point has no measure, or other attribute, how can two be different? + +Now we can posit something new about points, relationship. Points can be different. If they are different, they cannot be the same point :). This is an intuition related to the nature of information - any difference that makes a difference to a knowing subject. But again, how are they different? We are in desperate need of a property or aspect of points with which to differentiate them. Naming them provides one basis - we can call our points by name. Let's say A is one of our imaginary points and B is another - difference! But, that's of limited utility in the context of shapes, so we look for another. How about location. Wow! That "maps" to our intuition pretty well, points are located. What this means will be expanded on, but for now, just know that location simply means that point A is not in the same place as B, there is difference. In space, this would mean that points A and B do not occupy the same space, and that's reasonable and seems consistent with reality, but in this case we are only suggesting that A and B are different and that difference is location. + +This brings us to our next postulate: + +* location - objects (in our world, there are collections and points only) have difference. + +Location is tricky to describe, but I mean that points are located (have difference) somewhere, even if its only in our mental world. We will represent our idea by referring to the idea of physical space, in the real world, that is the 3 dimensions we normally consider space. + +How are points related locationally (is that even a word)? Suppose that points can be next to each other. Indeed, if two points exist (even in the mind), in order for them to be different, by definition (see above), they have different locations and one is next to the other (if is isn't clear, then here they are so defined, as being next to each other). + +The hard part comes when we add a third point. Where are the points in relation to each other. If points have no measure, then why can't they all be next to each other? If they are all next to each other, then they can't not be next to each other, right? But, we know this isn't how the real world works, things can be between each other... ick, so hard to explain betweeness. Why? Well, if a point has no measure, then it can't be put between two points. Unless, perhaps, we establish the idea that there is order on the universe. Let's do that. The universe is ordered, so mote it be. If that's the case, then we have another postulate: + +* order - the universe has order + +That is, one thing can be said to be ordered (precede, or follow) with respect to another. Order is imposed, so, without knowing the established order, one can only detect it and not know what the origin or orientation of that order is in its entirety. + +Now, betweeness becomes evident as the established order of three objects (points). We say, determine, decree, demand, etc. that a point is between two others. This may sound silly and needlessly complex, but it is what it is and betweeness is our next postulate: + +* betweeness - the property of a point that indicates it precedes a particular point and follows another particular point + +Now we can speak about dimensionality. We can define dimensions thusly, a single dimension exists when a point is brought into existence. Another, the second dimension, when three points are realized. Why three and not two, well, I'm not sure, with two points we can speak about the relationship between the points, A is not B, B is not A, A exists, B exists, A and B exist, but that's pretty much it. In order to go further, we really need at least 3 points (this is an exploration of the mind, not definitive). With three points, we can say much, much more. We can say is everything we can say about two, plus some more. + +Let's say that A and B and C are points in our universe. A is next to B and B is next to C, but C is not next to A. Then, B is between A and C. + +Here's a thought exercise to be integrated into the discussion as it is determined where it should go... + + Think of a light filled universe. + + Bring a point, A, into existence. If the point had measure, and the light had a source, this would change the universe in a measurable way, as it stands this is not the case. It just is. + + Bring another point B, into existence. No change... or is there? There is difference, but not measurable. + + Bring a third point C, into existence, such that we say B is between A and C. Again, difference, but not measurable. Why not? Because points have no measure! + + But when we bring our points into the real world, and of necessity given them measure, voila! There's going to be measurable differences. But, very local. Perspective is hinted at here - we need it in order to appreciate our new universe. If we were to place our consciousness at a point and look, as it were, around, what would we "see". If we were at A, we would see B, if we were at C, we could also see B, but from A, we could not see C and from C we could not see A. Wow! + +But, for now, we're sticking with betweeness being nothing more than established by fiat and being definitional in nature. B is between A and C because I say it is and beyond establishing order between A, B, C, has no material effect on anything. + +Ah, but let's give another name to that order of points and introduce another postulate: + +* line - a line is an ordered set of points + +But, it's tricky again, the line may be a set of points, but surely, we can't refer to a line by it's points, that's nuts. So, we'll say that a line can be named by any two points, belonging to the set, where the set established the order. Line AB therefore is part of ABC. As is AC and BC. + +Let's say that the order we write the points matches their ordering, this means AB is not the same ordering as BA, and ABC means that B is between A and C, with A preceding and C following. + +To recap what we have so far: + +* point +* collection +* location (difference) +* order +* betweeness +* line + +The point is fairly standard to think about in this way, collection or set is what we would expect, location is a bit different :),, order is meta, betweeness is necessary, but I'm no geometry expert, so I could be naive on this. Line is way different from what it is usually described as, but this is because I'm working through it from the ground up. + +... enough for today. Too many gaps, too many doubts, need to consider for a bit :). + +-- will + +*post edited 2023-12-19 13:58:00 -0600* diff --git a/_posts/2024-05-23-research-unix-v7-3.2.markdown b/_posts/2024-05-23-research-unix-v7-3.2.markdown new file mode 100644 index 0000000..f20d4e6 --- /dev/null +++ b/_posts/2024-05-23-research-unix-v7-3.2.markdown @@ -0,0 +1,29 @@ +--- +layout: post +title: Research Unix Version 7 - 3.2 +date: 2024-05-23 08:00:00 -0600 +categories: unix research-unix v7 +--- +This is an updated note that covers building a working v7 instance from tape files that will run in the OpenSImH emulator. First, the reader is led through the restoration of a pristine v7 instance from tape to disk. Next, the reader is led through adding a regular user and making the system multi-user capable. Then, the reader is shown how to make the system multi-session cable to allow multiple simultaneous sessions. Finally, the system is put to use with hello world, DMR style, and the learn system is enabled. + +The note explains each step of the process in detail. + + + +Last Updated May 23, 2024 + +### Changes since revision 3.1 + +Revision 3.2 - minor revision: + +* Tape format issue fixed in mktape.pl and mktape.py, resulted in updated image on tuhs. +* Updated note for Linux Mint 21.3 "Virginia" host and latest Open-SIMH + +Here's the note, as a pdf: + + + +Local copy here: [research-unix-7-pdp11-45-3.2.pdf](/assets/pdf/unix/research-unix-7-pdp11-45-3.2.pdf) + + +*post added 2024-05-23 08:00:00 -0600* \ No newline at end of file diff --git a/_posts/2024-08-16-thunderbird-hangs-indexing.markdown b/_posts/2024-08-16-thunderbird-hangs-indexing.markdown new file mode 100644 index 0000000..84dfafe --- /dev/null +++ b/_posts/2024-08-16-thunderbird-hangs-indexing.markdown @@ -0,0 +1,52 @@ +--- +layout: post +title: Fix for Thunderbird hangs while indexing messages +date: 2024-08-16 05:05:00 -0600 +categories: unix +--- +This note describes a method for fixing Thunderbird when it hangs while indexing. + + +I'm posting this in case it's useful to folks and for my own reference. It took me a quite a while to figure it out. + +So you have been using Thunderbird for your email for a while, on Windows, Linux, Mac, FreeBSD, and so on, for let's say a couple of decades. If you copy your profile around much, you are bound to hit an indexing issue where Thunderbird is unable to index your archives. You open up Activity Manager and it helpfully reports: + +Indexing 32 of 14243 messages in Archives/2002-2020/2016 + +Read on for the fix. + + +You watch the Activity Manager for a while, mesmerized perhaps by it's stolid refusal to progress or go away. Then you fire up your favorite search engine and start looking for answers. If you're lucky, this page pops up, otherwise you read drivel like "try again", "delete your index and rebuild it", or even reinstall. + +If you're on linux, or another unix that has similar functionality, you can do this! + +In a terminal: + +``` +strace thunderbird +``` + +In thunderbird: +open Tools->Activity Manager + +When it gets to the place where it hangs, in the terminal, press CTRL-C to end the session. Capture the output from the terminal window into a text editor and search from the bottom up for the directory it's complaining about. In the above example, look for the last occurance of 2016/. The trailing slash is important to include in your search to find the correct information. + +In my strace output, the last occurance(s) are: + +``` +access("/home/wsenn/Thunderbird/Mail/Local Folders-maildir/Archives.sbd/2002-2020.sbd/2016/cur", F_OK) = 0 +openat(AT_FDCWD, "/home/wsenn/Thunderbird/Mail/Local Folders-maildir/Archives.sbd/2002-2020.sbd/2016/cur/1723773452464.eml", O_RDONLY) = 147 +``` + +This is likely (so far, it's always, but time may tell if there are exceptions) the file that's breaking the indexing. Move it off somewhere to review: + +``` +mkdir -p ~/Desktop/2016 +mv "/home/wsenn/Thunderbird/Mail/Local Folders-maildir/Archives.sbd/2002-2020.sbd/2016/cur/1723773452464.eml" ~/Desktop/2016/ +``` + +Restart thunderbird without strace and pull up activity manager to see if it continues. If so, rinse and repeat as needed. + +-- will + +*post added 2024-08-16 10:27:00 -0600* diff --git a/about.markdown b/about.markdown index 04d3431..65ccba8 100644 --- a/about.markdown +++ b/about.markdown @@ -1,6 +1,6 @@ --- layout: page -title: About +title: about permalink: /about/ --- diff --git a/assets/files/lisp/LISP 1.5 Programmers Manual.pdf b/assets/files/lisp/LISP 1.5 Programmers Manual.pdf new file mode 100644 index 0000000..02ce7e3 Binary files /dev/null and b/assets/files/lisp/LISP 1.5 Programmers Manual.pdf differ diff --git a/assets/files/lisp/Weismann_LISP1.5_Primer_1967.pdf b/assets/files/lisp/Weismann_LISP1.5_Primer_1967.pdf new file mode 100644 index 0000000..f987291 Binary files /dev/null and b/assets/files/lisp/Weismann_LISP1.5_Primer_1967.pdf differ diff --git a/assets/files/lisp/lisp15.2023.tar.gz b/assets/files/lisp/lisp15.2023.tar.gz new file mode 100644 index 0000000..28c734e Binary files /dev/null and b/assets/files/lisp/lisp15.2023.tar.gz differ diff --git a/assets/files/scheme/STk-4.0.1-ucb1.3.6.i386.rpm b/assets/files/scheme/STk-4.0.1-ucb1.3.6.i386.rpm new file mode 100644 index 0000000..42dd8b9 Binary files /dev/null and b/assets/files/scheme/STk-4.0.1-ucb1.3.6.i386.rpm differ diff --git a/assets/files/scheme/explorin-vs-simply.txt b/assets/files/scheme/explorin-vs-simply.txt new file mode 100644 index 0000000..cf8432b --- /dev/null +++ b/assets/files/scheme/explorin-vs-simply.txt @@ -0,0 +1,164 @@ + Aug 25, 2006 + March 1, 2010 +README-explorin-vs-simply.txt + + +For CS61A/SICP, use stk-simply in the instructions below. + + +*stk-explorin and stk-simply*: +--------------------------- + + UCB Scheme includes several load modules that define the functions that + make up the Berkeley extensions for UCB CS classes. + + The UCB Scheme package now installs these options for starting scheme: + + "stk-simply" loads UCB procedures for CS3 and CS61A + "stk-explorin" loads UCB procedures for CS3S + "stk-grfx" loads UCB procedures for CS9D and CS47B (not on InstCD) + "stk" loads no UCB procedures + + (Prior to 2004, there were stk-cs3, stk-cs3s, stk-cs61a, stk-cs61a-2, + stk-cs9, etc. Those versions are now obsolete.) + + "stk-simply" loads the procedures as defined in these texts: + + "Simply Scheme - Introducing Computer Science" (Harvey and Wright) + "Structure and Interpretation of Computer Programs" (Abelson and Sussman) + + "stk-explorin" load the procedures as defined in this text: + + "Exploring Computer Science with Scheme" (Grillmeyer) + + Each program loads ALL of the UCB-defined procedures but, in the case of + conflicting definitions, favors the definition from the text book after + which it is named: "simply" or "explorin". ("explorin" omits the "g" for + historical reasons: MS-DOS required 8-character file names!) + + In these texts, there are 7 procedures that conflict because they use the + same names and arguments but behave differently. The conflicting + definitions are: + + count + first + every + accumulate + reduce + remove! + atom? (an STk primitive that is refined in Exploring) + + The 7 procedures are defined one way in simply.scm and another way in + explorin.scm. To load all the UCB procedures and resolve the conflicts: + + stk-simply loads everything else, then simply.scm + stk-explorin loads everything else, then explorin.scm + + This causes the desired definitions to replace the undesired ones. + + Here is how stk-simply and stk-explorin load on Windows (for example): + + The file "stk-simply" contains + stk -load "C:/Program Files/STk/site-scheme/load-simply" + + The file "load-simply" contains + ;; simply.scm must be loaded after explorin.scm + ;; modeler.stk must be loaded after simply.scm + (load "C:/Program Files/STk/site-scheme/berkeley.scm") + (load "C:/Program Files/STk/site-scheme/explorin.scm") + (load "C:/Program Files/STk/site-scheme/simply.scm") + (load "C:/Program Files/STk/site-scheme/modeler.stk") + (load "C:/Program Files/STk/site-scheme/obj.scm") + (load "C:/Program Files/STk/site-scheme/turtle-grfx.scm") + (load "C:/Program Files/STk/site-scheme/which-modeler.scm") + + The file "stk-explorin" contains + stk -load "C:/Program Files/STk/site-scheme/load-explorin" + + The file "load-explorin" contains + ;; explorin.scm must be loaded after simply.scm + ;; modeler.stk must be loaded after simply.scm + (load "C:/Program Files/STk/site-scheme/berkeley.scm") + (load "C:/Program Files/STk/site-scheme/simply.scm") + (load "C:/Program Files/STk/site-scheme/explorin.scm") + (load "C:/Program Files/STk/site-scheme/modeler.stk") + (load "C:/Program Files/STk/site-scheme/obj.scm") + (load "C:/Program Files/STk/site-scheme/turtle-grfx.scm") + (load "C:/Program Files/STk/site-scheme/which-modeler.scm") + + The (atom? '()) function is an STk primitive that is defined in the STk + sources as returning #t. It is redefined in explorin.scm to return #f. + To compensate for that, the original definition is copied to berkeley.scm + to ensure that it is set properly for those users. + + +*"(explorinOrSimply)" procedure* +------------------------------ + + If you are running stk-explorin, invoking the function (explorinOrSimply) + will return the string "explorin", but if you are running stk-simply, + invoking (explorinOrSimply) will return the string "simply". This can + be used within user scheme code to determine which version has been + loaded. + + +*Replacement Modeler* +------------------- + + The Replacement Modeler is a separate window that is invoked in stk by a + command such as (model (map odd? '(1 2 3 4))) + + The Modeler procedures are defined in the file "modeler.stk". The file + "which-modeler.stk" defines flags that are used to distinguish behaviors + for CS3 vs CS3S students. The flags are: + + (using-berkeley-scm?) (false for "explorin" users, true for others) + *harvey+wright* (false for "explorin" users, true for others) + *grillmeyer* (true for "explorin" users, false for others) + *they-know-lambda* (false for everyone) + + which-modeler.stk replaces the older cs3-modeler.stk and cs3s-modeler.stk. + + +*stk-grfx* +-------- + + 'stk-grfx' loads the Berkeley extensions in obj.scm and turtle-grfx.scm. + It is a new variant that was added to for cs9d and cs47b in Spring 2005. + It can be run as + + ~scheme/bin/stk-grfx + ~cs9d/bin/stk-grfx + ~cs47b/bin/stk-grfx + + It is only available on the computers in the EECS Instructional labs. It is + not available on the pre-packaged versions of Berkeley Scheme for Windows, + MacOSX or Linux. + + To test that turtle graphics is installed: + + STk> (cs) ;; TurtleGraphics X window pops up + STk> (ht) ;; the turtle pointer disappears + STk> (st) ;; the turtle pointer reappears + + +*STKDB Debugger* +-------------- + The STKDB Debugger was developed by Prof Hilfinger in 2003. It is + documented in https://people.cs.berkeley.edu/~bh/Scheme/stkdb.pdf. + + The debugger module is loaded into the scheme interpreter after you + start it. The debugger files are included in the UCB Scheme + distribution. The required files are: + + stk VERSION 4.0.1-ucb1.16 or newer + $DIR/stkdb/*.scm + $DIR/stk/slib + $DIR/emacs/lisp/stkdb.el + + $DIR is usually '/usr/local/lib' on your home computer, which is the + same as C:\cygwin\usr\local\lib on a Windows computer that is using + Cygwin with the latest version (Feb 2006) of UCB Scheme on Windows. + + + diff --git a/assets/files/scheme/faq.html b/assets/files/scheme/faq.html new file mode 100644 index 0000000..d445b5e --- /dev/null +++ b/assets/files/scheme/faq.html @@ -0,0 +1,71 @@ + + +UCB Scheme - Frequently Asked Questions + + + +

UCB Scheme - Frequently Asked Questions

+

+Nov 21, 2005 +

    +
  1. "The arrow keys output certain escape sequences (^[]A to ^[]D) + instead of moving the cursor." +

    STk does not support arrow keys. You can run STk from within Emacs (using, + e.g., M-x shell or M-x run-scheme) if you want to use arrow keys.

  2. + +
  3. "I'm trying to install the STk rpm on redhat linux 7.3 but + when I type in the command 'rpm -i STk-4.0.1-UCB6.i386.rpm' or + 'rpm -Uvh STk-4.0.1-UCB6.i386.rpm', an error message tells me that + there is a failed dependency because my system doesn't have the korn + shell running." +

    You can go ahead and run the command   + 'rpm --nodeps -i STk-4.0.1-UCB6.i386.rpm'.   + Or you could install ksh, with the command:   + 'rpm -i ftp://ftp.redhat.com/pub/redhat/linux/7.3/en/os/i386/RedHat/RPMS/pdksh-5.2.14-16.i386.rpm'

  4. + +
  5. " The 'File Save' window and the 'envdraw' command don't work.   + I'm using the STk version of scm on a Windows 9x system." +

    This is a known bug that we cannot fix. The Tk calls that are + needed for the 'File Save' window and the 'envdraw' command do not + work on Windows9x.   They do work on WindowsNT/2000/XP.

  6. + +
  7. " I can't get STK to load onto my laptop with Windows Me. +   I follow the instructions, add it to the start menu, but when I + click on the program to load it, it doesn't do anything:   the cursor + goes to an hourglass to indicate action, but no window opens. What do I + do?" +

    The problem was that when you unzipped the file, it automatically saved + as C:\Program Files\STkWin32, so when you'd click on stk.exe, it would not + execute because the path was incorrect.   To solve this, you just had + to drag the STk folder within STkWin32 to the Program Files folder.

  8. + +
  9. " I'm logged into an Instructional UNIX system from a Mac [or Linux]. +   I type 'stk' and I get an error that starts with:

      + X Error of failed request: BadAtom (invalid Atom parameter) +
    +

    To correct this, use the "-Y" option with ssh, for example: + ssh -l cs3 solar -X -Y.   This is not an bug in stk; it is + related to how openssh sends certain X calls over the encrypted channel. + +

+
+

To Instructional Support:

+The source for this faq.html file is +/home/aa/projects/scheme/public_html/faq.html. +To make it accessible from ~scheme and ~instcd, there is a hard link between +
    +
  • /home/aa/projects/scheme/public_html/faq.html
  • +
  • /home/aa/projects/instcd/public_html/inst-cd/source/stk/faq.html
  • +
+References to it from the ~scheme and ~instcd WEB pages are relative to +one of those, ie +
    + +
  • &lt;A HREF="../../faq.html"&gt; under ~scheme
  • +
  • &lt;A HREF="../../source/stk/faq.html"&gt; under ~instcd
  • +
+This is to ensure that a single, current version is always accessible from +both WEB sites, and that a copy of it will always be burned into the ~instcd +ISO file when we make one. + + diff --git a/assets/files/scheme/gallesio-1999-stk-4.0-manual.pdf b/assets/files/scheme/gallesio-1999-stk-4.0-manual.pdf new file mode 100644 index 0000000..4eb3b5c Binary files /dev/null and b/assets/files/scheme/gallesio-1999-stk-4.0-manual.pdf differ diff --git a/assets/files/scheme/stk_4.0.1-1_amd64.deb b/assets/files/scheme/stk_4.0.1-1_amd64.deb new file mode 100644 index 0000000..ffa93aa Binary files /dev/null and b/assets/files/scheme/stk_4.0.1-1_amd64.deb differ diff --git a/assets/files/tops10/enscript-command.txt b/assets/files/tops10/enscript-command.txt new file mode 100644 index 0000000..41d0f46 --- /dev/null +++ b/assets/files/tops10/enscript-command.txt @@ -0,0 +1 @@ +enscript -B -L70 -f Courier9 --margins=96::: -o mig603.ps mig603.txt && ps2pdf mig603.ps && open mig603.pdf diff --git a/assets/files/tops10/mig603.mem b/assets/files/tops10/mig603.mem new file mode 100644 index 0000000..a81397f --- /dev/null +++ b/assets/files/tops10/mig603.mem @@ -0,0 +1,11545 @@ + + + + + + + + + + + + + + DECsystem-10 + + + + Monitor Installation Guide + + + + 6.03 Monitor + June 1977 + + + + This manual describes the steps you must + take to install the 6.03 monitor. + + + + + + + + + + + Digital Equipment Corporation. Maynard, Massachusetts + Page 2 + + + Revision: June 1977 + + +The information in this document is subject to change without notice +and should not be construed as a commitment by Digital Equipment +Corporation. Digital Equipment Corporation assumes no responsibility +for any errors that may appear in this manual. + +The software described in this document is furnished under a license +and may be used or copied only in accordance with the terms of such +license. + +Digital Equipment Corporation assumes no responsibility for the use or +reliability of its software on equipment that is not supplied by +DIGITAL. + + + +Copyright (C) 1973, 1977 by Digital Equipment Corporation + + +The postage prepaid READER'S COMMENTS form on the last page of this +document requests the user's critical evaluation to assist us in +preparing future documentation. + + +The following are trademarks of Digital Equipment Corporation: + + DIGITAL UNIBUS + DEC DECsystem-10 + PDP DECtape + DECUS DDT + KA10 KL10 + KI10 + Page 3 + + + + + + + + + + CONTENTS + + + + Page + +PREFACE + +CHAPTER 1 BUILDING THE FRONT-END FILE SYSTEM + (KL ONLY) 1-1 + +CHAPTER 2 READIN BOOTM 2-1 + +CHAPTER 3 START THE MONITOR 3-1 + +CHAPTER 4 RESTORE SELECTED FILES 4-1 + +CHAPTER 5 COPY MONITOR SUPPORT PROGRAMS 5-1 + +CHAPTER 6 WRITE BOOTS 6-1 + +CHAPTER 7 MERGE MODIFICATIONS 7-1 + +CHAPTER 8 CREATE A MONITOR WITH MONGEN 8-1 + + 8.1 INTRODUCTION 8-1 + 8.2 MONGEN ORGANIZATION 8-1 + 8.3 EXECUTING MONGEN 8-2 + 8.3.1 Mongen Dialogue Format 8-3 + 8.3.2 Generating a New Monitor 8-4 + 8.4 HDWGEN 8-4 + 8.5 TTYGEN + 8.6 NETGEN + 8.7 FGEN + 8.8 PRODUCING RELOCATABLE BINARY FILES + COMMON.REL, COMMOD.REL, AND COMDEV.REL + 8.8.1 Assembling the Configuration Files + 8.8.2 Assembly Error Messages from + COMMON + 8.9 DESCRIPTION OF CONFIGURATION FILES + 8.9.1 Description of COMMON.MAC + 8.9.2 Description of COMMOD.MAC + 8.9.3 Description of COMDEV.MAC + 8.10 HDWGEN EXAMPLE + 8.11 TTYGEN EXAMPLE + 8.12 NETGEN EXAMPLE + 8.13 FGEN EXAMPLE + 8.14 DECIMAL DEFAULT VALUES + Page 4 + + + 8.14.1 Symbols Defined in COMMON + 8.14.2 Symbols Defined in COMDEV + 8.14.3 Symbols Defined in COMMOD + 8.15 OCTAL DEFAULT VALUES + 8.15.1 Symbols Defined in COMMON + 8.15.2 Symbols Defined in COMMOD + 8.15.3 Symbols Defined in COMDEV + 8.16 SIXBIT DEFAULT VALUES + 8.17 NON-STANDARD DEVICE PI ASSIGNMENT + 8.18 TERMINAL INTERFACE LINE NUMBERS + 8.19 MONGEN ERROR MESSAGES + +CHAPTER 9 ASSEMBLE MACRO FILES + +CHAPTER 10 LOAD AND SAVE THE MONITOR + +CHAPTER 11 MAKE A COPY OF NEW MONITOR + +CHAPTER 12 COMMUNICATION SYSTEMS + +CHAPTER 13 UPDATE ACCOUNTING FILES + +CHAPTER 14 GET NEW MONITOR + +CHAPTER 15 COPY NEW MONITOR TO SYS + +CHAPTER 16 ONCE DIALOGUE + + 16.1 INTRODUCTION + 16.1.1 Summary of STARTUP Options + 16.1.2 Special Considerations + 16.1.3 Special Multiprocessing Considerations + 16.1.4 Conventions Used in this Chapter + 16.2 STARTUP OPTION: QUICK AND NOINITIA + 16.3 STARTUP OPTION: GO + 16.4 STARTUP OPTION: DESTROY + 16.5 STARTUP OPTION: REFRESH + 16.6 STARTUP OPTION: UNITID + 16.7 STARTUP OPTION: CHANGE + 16.8 STARTUP OPTION: LONG + 16.9 WHY RELOAD QUESTION + 16.10 ERROR MESSAGES + +CHAPTER 17 BACKUP + + 17.1 INTRODUCTION + 17.2 FEATURES + 17.3 OVERVIEW OF COMMAND FUNCTIONS + 17.4 EXAMPLES + 17.5 OPERATOR USES + 17.6 RESTORING FROM A DISTRIBUTION TAPE + 17.7 OBTAINING DIRECTORIES OF BACKUP TAPES + 17.8 COMPARING TAPE AND DISK FILES + 17.9 CHECKPOINTING LARGE FILES + 17.10 BACKUP MESSAGES + Page 5 + + + 17.11 CAPACITIES OF DISK MEDIA VERSUS + MAGNETIC TAPE + 17.12 BACKUP TAPE FORMAT + +CHAPTER 18 BOOTM + Page 6 + + + + + + + + + + + + + + + PREFACE _______ + + + +This manual describes the steps you must take to install the 6.03 +monitor. This manual should be used in conjunction with the +DECsystem-10 Operator's Guide. Formerly, some of the information in +this manual was found in various specifications within the +DECsystem-10 Software Notebooks. For example, MONGEN is now Chapter 8 +of this manual instead of being a separate specification. + +When you receive your DECsystem-10, you will receive a Manufacturing +tape labeled YURMON and the name of your installation. When you +receive your 6.03 monitor, you will receive one 6.03 monitor tape and +one CUSP tape. You also may receive tapes associated with unbundled +products. + +The files that make up the 6.03 monitor are listed below. + +*.MAC New monitor source files (complete except for unbundled + files). + +603.MCO A description of the changes made to the monitor since + the 6.02 monitor release. + +603.DDT A DDT patch file that can be applied to the monitor + using the $Y feature of FILDDT to fix problems + concerning 6.03. This file contains those patches + listed in BWR603.RNO. + +TOPA10.REL The combined .REL files needed for loading a regular + KA10 monitor. + +TOPG10.REL The combined .REL files needed for loading a KALUG + monitor. + +TOPI10.REL The combined .REL files needed for loading a regular + KI10 monitor. + +TOPH10.REL The combined .REL files needed for loading a KILUG + monitor. + +MONGEN.EXE Version 50(135) of the Monitor Generation Program, + Page 7 + + + which is described in Chapter 8. + +FGEN.HLP Version 075 of FGEN.HLP, which lists and explains all + the feature test switches that can be set via MONGEN. + +CON???.CMD The COMPIL command files that are needed for assembling + monitors. + +CMB???.CCL The PIP indirect files needed for making TOP?10.REL. + +BWR603.RNO The BEWARE file for the 6.03 monitor, which contains + information needed to load and use the 6.03 monitor. + Read this file before you install the monitor. + +BWR603.603 The RUNOFF output from BWR603.RNO. + +The above files constitute the standard 6.03 monitor release. In +addition to the above, an installation will also receive any files +associated with the unbundled portions of 6.03 that that installation +is licensed to use. + +The following are the unbundled portions of the 6.03 monitor, which +are shipped only to properly licensed installations. + + Virtual Memory + DAS78 + DA28 + DC44 + Task to Task Communication + +The installation procedures you use are basically the same regardless +of which type of processor your system has (e.g., KA, KI, KL). Any +differences in the installation procedure because of processor type +are indicated within the text of this manual. Read the list below to +determine which classification your installation is; then, start +reading at the chapter number indicated. + + Chapter Classification + + 1 Generating a 6.03 monitor for a KL10 system at a + new installation. + + 2 Generating a 6.03 monitor for a KA10 or KI10 + system at a new installation. + + 4 Generating a 6.03 monitor for a KA, KI, or KL + system with a currently running 6-series monitor. + + + + + + + + + + + + + CHAPTER 1 + + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) ________ ___ _________ ____ ______ _____ _____ + + + +The steps described in this chapter copy the front-end software from +the RSX20-F DECtape to the front-end file space on the public disk. +In performing the steps, you will be using the following front-end +programs. These programs are on the RSX20-F DECtape that you will be +copying onto the disk. + + KLI This program loads the KL10 microcode, initializes + the KL10 caches, configures the KL10 memories, and + loads a bootstrap program. + + MOU (MOUNT) This program adds (MOUnts) a device to the list of + on-line front-end devices. + + UFD This program creates a directory in the front-end + file system on the disk. This program does not + respond with a prompt after you issue a command to + it. Therefore, you must type a CTRL/backslash + after typing the carriage return. Note that the + CTRL/backslash does not echo. + + INI This program initializes the front-end file + system. This program does not respond with a + prompt after you issue a command to it. + Therefore, you must type a CTRL/backslash after + typing the carriage return. Note that the + CTRL/backslash does not echo. + + PIP This program is a PDP-11 program that copies files + from the DECtape to the disk. The PIP described + in other chapters of this manual is the + DECsystem-10 PIP. + + RED (REDIRECT) This program redefines the front-end logical name + SY0: from the DECtape to the disk. This program + does not respond with a prompt after you issue a + command to it. Therefore, you must type a + CTRL/backslash after typing the carriage return. + Note that the CTRL/backslash does not echo. + + SAV (SAVE) This program saves the front-end monitor. + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) Page 1-2 ________ ___ _________ ____ ______ _____ _____ + + +Device names used in this section are PDP-11 formatted device names. +Table 1-1 lists the PDP-11 device names. + + + Table 1-1 + PDP-11 Device Names + + + PDP-11 Name Device + + + TT Terminal + DT DECtape + MT Magtape + SY DB0:[5,5], which is the + PDP-11 system area that is + used in the same way + as DSKB:[1,4]. + RF Fixed-Head Disk + RP Disk Pack + RK Disk Cartridge + PR Paper-tape Reader + PP Paper-tape Punch + CD Card Reader + LP Line Printer + XY Plotter + + +In addition to initially installing the front-end file system, you +must install the front-end file system using the steps outlined in +this Chapter if you ever do any of the following: + + 1. Reinitialize the front-end file system. + + 2. Change the front-end hardware. + + 3. Destroy the front-end file system. + +The first step is to mount the DECtape labeled RSX20-F. Place the +RSX20-F tape (version 0005J) on one of the front-end (PDP-11) DECtape +drives. Make sure that the Unit Selector Switch is set to 0. This +DECtape drive is called DT0 when you specify it by name. + +On the right side of the Unit Selector Switch, set the rightmost +button to REMOTE. Set the leftmost button (on the left side of the +Unit Selector Switch that is set to 0) to WRITE ENABLE. + +On the other DECtape drive, set the Unit Selector Switch to 1; mount +the RSX20-F Auxiliary Files DECtape; set the switches for this drive +(DT1) the same as you did for DT0. + +Mount the manufacturing tape (labeled YURMON and your installation's +name) on MTA0 (-10 device). If you are not a new installation and +would like to create your own Manufacturing tape, follow the procedure +listed below. + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) Page 1-3 ________ ___ _________ ____ ______ _____ _____ + + + .GET SYS:BACKUP + .SAVE MTA0:BACKUP + .SAVE MTA0:BACKUP + .START + /TAPE MTA0: + /SAVE DSKB:[1,4]=DSKB:*.*[1,4] + +The above procedure saves two copies of BACKUP and the [1,4] disk area +(SYS:). + +You can mount this magnetic tape on another magtape drive (other than +MTA0); however, MTA0 is assumed in the following example. Mount a +recently formatted disk pack on RPA0 (or another drive, but RPA0 is +assumed). Whichever drive you choose, it must be dual-ported with the +RH11. + +To refer to the "-11" disk pack, you specify a device name in the +following format: + + DB unit-number: + +where unit-number is 0-7. For example, RPA0 is the equivalent of DB0, +RPA1 is the equivalent of DB1, an RPC3 is the equivalent of DB3. + +Set the data switches on the -11 front panel to 000001. Make sure the +ENABLE switch is on; then, push the SW/REG switch. The tape will +begin loading. Refer to Table 14-1 for a description of what occurs +when you press the SW/REG switch. + +The following 'dialogue' takes place at the operator terminal between +you, the front-end installer, and the system. Your responses are +those underlined. Press the RETURN key after each response. + + RSX-20F V005J 0:06 21-JUN-76 + + [SY0: REDIRECTED TO DT0:] + [DT0: MOUNTED] + KLI -- VERSION V002Q RUNNING + + KLI -- MICROCODE VERSION 131 LOADED + KLI -- % NO FILE - ALL CACHE BEING CONFIGURED + KLI -- ALL CACHES ENABLED + KLI -- % NO FILE - ALL MEMORY BEING CONFIGURED + LOGICAL MEMORY CONFIGURATION: + CONTROLLER + ADDRESS SIZE RQ0 RQ1 RQ2 RQ3 CONTYPE INT + 00000000 256K 04 FOR ALL DMA20 4 + KLI -- ? FILE 'DT0:BOOT.EXB;0'NOT FOUND + KLI -- ? BOOTSTRAP LOAD FAILED + KLI -- ENTER DIALOGUE [NO,YES,EXIT,BOOT]? + KLI> YES + KLI -- RELOAD MICROCODE [YES,VERIFY,NO]? + KLI> NO + KLI -- RECONFIGURE CACHE [FILE,ALL,YES,NO]? + KLI> NO + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) Page 1-4 ________ ___ _________ ____ ______ _____ _____ + + + KLI -- CONFIGURE KL MEMORY [FILE,ALL,YES,NO]? + KLI> NO + KLI -- LOAD KL BOOTSTRAP [YES,NO,FILENAME]? + KLI> BOOTM + +This example assumes you are booting from magtape. + +The following is then printed at the operator terminal. + + KLI -- BOOTSTRAP LOADED AND STARTED ;-10 BOOTSTRAP + BOOTM V4(16) + + BTM> + +After the BTM> prompt, type in a command string terminated by a +carriage return. After performing the command, the bootstrap loader +either restarts itself or transfers to a newly loaded program, +depending on the command you type. You can type either /TM02 or +/TX01, depending on the tape drive used (e.g., for TU70s, type /TX01). +Or, you could type a command in the following format: + + structure:file.ext[project,prog] /TM02 + /TX01 + +If you do not specify either /TM02 or /TX01, TM10 is assumed by +default. + +In this example /TM02 was typed. + + BTM>/TM02 + +This response begins the loading of the default monitor (i.e., +DSKB:SYSTEM.EXE[1,4] from drive 0 (MTA0) on the /TM02 magtape +controller). (For more information on BOOTM refer to Chapter 18.) The +following dialogue is then printed on the operator's terminal. You +should type everything that is underlined. Refer to Chapter 3 for a +more detailed description of this dialogue. + + RK275A KL10 SYS#1026 01-19-77 + WHY RELOAD: SA ;System is stand-alone; refer to Section 16.9 + DATE: 21-JAN-77 ;Enter the current date + TIME: 710 ;Type the current time of day, using + ;a 24-hour clock. + STARTUP OPTION: REFRESH + ;Specify the LONG startup + ;option if your installation is a new + ;installation or you are + ;using blank disk packs. + TYPE STR NAME TO BE REFRESHED (CR IF NONE, ALL IF ALL) + DSKB ;The structure on which the front-end + ;file system is to be created. + ;Refer to Section 16.8 for + ;a description of the LONG + ;dialogue. + TO AUTOMATICALLY LOG-IN UNDER [1,2] TYPE "LOGIN" + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) Page 1-5 ________ ___ _________ ____ ______ _____ _____ + + + .LOGIN + .RUN MTA0:BACKUP ;This executes the BACKUP + /TAPE MTA0: ;program found on the manufacturing + ;tape. Refer to Chapter 17. + /RESTORE ;Move files to SYSB + ! ;BACKUP's indication that it is busy. + "DONE + ?BKPHSG CANNOT GET HIGH SEGMENT BACK ;Ignore this + ;error message. + +Executing the following procedure creates a file called FE.SYS on RPA0 +(DSKB) that will be used by the front-end for its file system. + + .R FEFILE + DISK UNIT NAME:RPA0 ;UNIT WHERE DSKB is mounted. + SIZE OF FILE IN BLOCKS ( GIVES DEFAULT OF 2000): + + [2008 DATA BLOCKS ALLOCATED TO FE.SYS] + [FE.SYS AREA STARTS AT LOGICAL BLOCK 33041.] + [FRONT END FILE CREATED, HOM BLOCKS WRITTEN] + + .K/F ;To stop the -10 because the KL10 + ;must NOT be running + ;while installing the + ;front-end software. + + + + NOTE + + From now on, until you read otherwise, + you are 'talking' only to the -11 + front-end, using the -11 command + language and -11 programs. The -10 is + not involved in this communication + process. The RESET command (in the + example below) ensures that the -10 is + not running. + + +To being communicating with the front-end command parser, type a +CTRL/backslash (which does not echo). If at any time you type an +incorrect response to the parser (i.e., after the prompt PAR%), type a +CTRL/Z followed by a CTRL/backslash. The system retypes the prompt, +after which you can retype your response. Note that some times a +CTRL/backslash takes a few moments to respond. + + ^\ ;Type a CTRL/backslash. + PAR>SHUT + DECSYSTEM-10 NOT RUNNING + ;K/F above kills your job. + ;The SHUT command stops + ;the -10. + ^\ ;Type a CTRL/backslash. + PAR>SET CONSOLE MAINTENANCE + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) Page 1-6 ________ ___ _________ ____ ______ _____ _____ + + + CONSOLE MODE: MAINTENANCE + PAR%RESET ;KL10 must not be running while installing + ;front-end software. + PAR#ST MICROCODE ;Start microcode. + PAR%MCR MOU ;Start the MOUNT program in the front-end. + ;MCR is the front-end + ;command decoder. + MOU>DT1: ;Mount the tape labeled RSX20-F + ;Auxiliary files. + MOU -- MOUNT COMPLETE + MOU>^Z ;Type a CTRL/Z. + ^\ ;Type a CTRL/backslash + PAR%MCR PIP ;START PIP. + + PIP>TT:=DT0:/LI ;Directory of DT0 + + + DIRECTORY DT0:[5,5] + 20-MAR-77 14:28 + + F11ACP.TSK;41 77. C 21-JUN-76 00:50 + PARSER.TSK;37 39. C 21-JUN-76 00:50 + TKTN.TSK;45 6. C 21-JUN-76 00:51 + MOU.TSK;37 5. C 21-JUN-76 00:51 + SETSPD.TSK;41 4. C 21-JUN-76 00:51 + KLR.TSK;37 5. C 21-JUN-76 00:52 + KLE.TSK;37 23. C 21-JUN-76 00:52 + KLX.TSK;43 5. C 21-JUN-76 00:53 + KLI.TSK;46 33. C 21-JUN-76 00:53 + UA.MCB;150 35. 21-JUN-76 00:53 + UB.MCB;150 35. 21-JUN-76 00:54 + BT128K.EXB;1 12. 16-MAR-77 10:09 + BT256K.EXB;1 12. 16-MAR-77 10:10 + BOOTM.EXB;2 34. 16-MAR-77 10:16 + + TOTAL OF 325. BLOCKS IN 14. FILES + +PIP>TT:=DT1:/LI + + + +DIRECTORY DT1:[5,5] +20-MAR-77 14:31 + +RED.TSK;41 6. C 21-JUN-76 00:07 +SAV.TSK;40 12. C 21-JUN-76 00:07 +DMO.TSK;37 5. C 21-JUN-76 00:08 +T20ACP.TSK;37 8. C 21-JUN-76 00:08 +UFD.TSK;37 9. C 21-JUN-76 00:08 +INI.TSK;37 23. C 21-JUN-76 00:08 +PIP.TSK;1321 56. C 21-JUN-76 00:09 +COP.TSK;2 8. C 21-JUN-76 00:09 + + TOTAL OF 161. BLOCKS IN 9. FILES + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) Page 1-7 ________ ___ _________ ____ ______ _____ _____ + + + PIP>^Z + ^\ ;Type a CTRL/backslash. + PAR%MCR INI + INI>DB0: ;Initialize the front-end file system on DB0. + ^\ ;Type a CTRL/backslash. + PAR%MCR MOU ;Start MOUNT program. + MOU>DB0: ;Mount the disk unit. + MOU -- MOUNT COMPLETE + MOU>^Z ;Type a CTRL/Z. + ^\ ;Type a CTRL/backslash. + PAR%MCR UFD ;Start the UFD program. + UFD>DB0:[5,5] ;Creating the UFD called [5,5] on the + ;-11 disk area (FE.SYS); + ;see note below. + ^\ ;Type a CTRL/backslash. + PAR%MCR PIP ;Start PIP. + PIP>DB0:=DT0:*.*,DT1:*.* ;To copy all files from the + ;DECtape to the front-end file + ;system [5,5] on the disk pack on RPA0. + ;After approximately 35 minutes, + ;the system prints the PIP prompt. + + PIP>DB0:BOOT.EXB=DT0: BT128K.EXB + BT256K.EXB + ;This copies the BOOTS that + ;fits your + ;configuration. + PIP>^Z ;Type a CTRL/Z. + ^\ ;Type a CTRL/backslash. + PAR% + + + + NOTE + + FE.SYS is the logical -11 disk space + area residing on the -10 disk + (DSKB:[1,4],RPA0). FE.SYS contains -11 + directory areas and files within these + areas. Note that [5,5] is a directory + area in FE.SYS. + + + +You now reboot the front-end. Set the data switches on the -11 front +panel to 000003. (Refer to Table 14-1.) Make sure the ENABLE switch +is ON; then, push the SW/REG switch. + + RSX-20F V00SJ 0:06 21-JUN-76 + + [SY0: REDIRECTED TO DT0:] + [DT0: MOUNTED] + + ^\ ;Type a CTRL/backslash to start the parser. + PAR%MCR MOU ;Start the MOUNT program. + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) Page 1-8 ________ ___ _________ ____ ______ _____ _____ + + + MOU> DB0: ;Mount the disk unit that the -11 + ;front-end file system (that you just + ;installed) resides on (DB0:). + MOU -- MOUNT COMPLETE + MOU>^Z ;Type a CTRL/Z. + ^\ ;Type a CTRL/backslash + PAR%MCR RED ;Start the REDIRECT program. + RED>DB0:=SY: ;Make SY: be DB0: instead of DT0:. + ;This causes the KL10 to be rebooted from disk + ;instead of DECtape (-11 devices). + ^\ ;Type a CTRL/backslash. + PAR%MCR SAV ;Start the SAVE program. + SAV>SY:/WB ;Save the front-end monitor on + ;SY:(DB0:[5,5]). + ;The front-end can now use the files from + ;the TOPS-10 disk pack instead of the + ;PDP-11 DECtapes. + [DB0: DISMOUNTED] + [DT0: DISMOUNTED] + + + RSX-20F V005J 2:00 21-JUN-76 ;Messages from the SAVE program + [SY0: REDIRECTED TO DB0:] ;to enable you to bootstrap + [DB0: MOUNTED] ;from DB0: [5,5]. + ^\ ;Type a CTRL/backslash. + PAR%MCR PIP ;Start PIP. + PIP>TT:=DB0:/LI + + + DIRECTORY DB0:[5,5] + 21-JUN-76 01:05 + + + F11ACP.TSK;41 77. C 21-JUN-76 00:30 + PARSER.TSK;37 39. C 21-JUN-76 00:31 + TKTN.TSK;45 6. C 21-JUN-76 00:32 + MOU.TSK;37 5. C 21-JUN-76 00:33 + SETSPD.TSK;41 4. C 21-JUN-76 00:35 + KLR.TSK;37 5. C 21-JUN-76 00:36 + KLE.RSK;37 23. C 21-JUN-76 00:37 + KLX.TSK;43 5. C 21-JUN-76 00:38 + KLI.TSK;46 33. C 21-JUN-76 00:39 + UA.MCB;150 35. 21-JUN-76 00:41 + UB.MCB;150 35. 21-JUN-76 00:43 + BT128K.EXB;1 12. 21-JUN-76 00:44 + BT256K.EXB;1 12. 21-JUN-76 00:46 + BOOTM.EXB;2 34. 21-JUN-76 00:48 + KL.CFG;1 1. 21-JUN-76 00:50 + RED.TSK;41 6. C 21-JUN-76 00:54 + SAV.TSK;40 12. C 21-JUN-76 00:55 + DMO.TSK;37 5. C 21-JUN-76 00:56 + T20ACP.TSK;37 8. C 21-JUN-76 00:57 + UFD.TSK;37 9. C 21-JUN-76 00:58 + INI.TSK;37 23. C 21-JUN-76 00:59 + PIP.TSK;1321 56. C 21-JUN-76 01:00 + BUILDING THE FRONT-END FILE SYSTEM (KL10 ONLY) Page 1-9 ________ ___ _________ ____ ______ _____ _____ + + + COP.TSK;2 8. C 21-JUN-76 01:01 + + + TOTAL OF 453. BLOCKS IN 23. FILES + + PIP>^Z ;Type a CTRL/Z. + +At this point, RSX20-F can be bootstrapped from the disk by depressing +the switch labeled DISK or, if the front-end disk pack is on a drive +other than RPA0, depress the SW/REG switch. Refer to Chapter 2. + +From now on devices and directories specified are DECsystem-10 devices +and directories; unless specified otherwise. + + + + + + + + + + + + + CHAPTER 2 + + READIN BOOTM ______ _____ + + + +READIN the BOOTM bootstrap and your 6.03 monitor from the new ______ ___ _____ _________ ___ ____ ____ _______ ____ ___ ___ +installation bootstrap tape. ____________ _________ _____ + +If you have a KL10 system, read Steps 1 and 2. If you have a KA or KI +system, read Steps 3 through 7. + +STEP 1 (KL10 only) ____ _ + +Set the ENABLE/DISABLE load switch to ENABLE. This will enable the +other three load switches. + +STEP 2 (KL10 only) ____ _ + +Press the upper half of the switch labeled DISK on the KL10 front +panel. This will cause the front-end processor to access the disk on +drive 0 and load the RSX20-F monitor. + +The KL10 initialization program (KLINIT) is automatically loaded, and +the default hardware configuration of cache and external memory are +also automatically set up. The bootstrap program (BOOTS) for the +TOPS-10 monitor is then automatically loaded into the central +processor and started. The following is an example of the output you +will receive on the console terminal. You type everything that is +underlined. + + RSX-20F V005J 0:16 21-JUN-76 + + [SY0: REDIRECTED TO DB0:] + [DB0: MOUNTED] + KLI -- VERSION V002J RUNNING + KLI -- MICROCODE VERSION 131 LOADED + KLI -- ALL CACHES ENABLED + LOGICAL MEMORY CONFIGURATION + CONTROLLER + ADDRESS SIZE RQ0 RQ1 RQ2 RQ3 CONTYPE INT + 00000000 256 04 FOR ALL DMA20 4 + KLI -- BOOTSTRAP LOADED AND STARTED + BOOTS V22(103) + BTS> + ^\ ;Type a CTRL/backslash. + READIN BOOTM Page 2-2 ______ _____ + + + PAR>MCR KLI + KLI -- VERSION V0002J RUNNING + KLI -- ENTER DIALOGUE [NO,YES,EXIT,BOOT]? + KLI -- YES + KLI -- RELOAD MICROCODE [YES,VERIFY,NO]? + KLI> NO + KLI> RECONFIGURE CACHE [FILE,ALL,YES,NO]? + KLI> NO + KLI -- CONFIGURE KL MEMORY [FILE,ALL,YES,NO]? + KLI> NO + KLI -- BOOTSTRAP [YES,NO,FILENAME]? + KLI> BOOTM + KLI -- ALL CACHES ENABLED + KLI -- BOOTSTRAP LOADED AND STARTED + BOOTS V4(16) + BTS> + +If an error occurs during the KL initialization program, you will +receive an error message preceded by KLI --?. At that point, you are +placed in KLINIT dialogue mode which is described in Appendix A of the +KL Series Operator's Guide. BOOTS outputs the prompt BTS>. After +BOOTS prints its prompt, you must type a file specification, +indicating the monitor you want to read from the BACKUP save set on +the Manufacturing Bootstrap Tape. Type the following command line: + + DSKB: YURMON.EXE[1,4] + +This response begins the loading of the monitor from the Manufacturing +BOOTSTRAP tape. Then, the ONCE-Only Dialogue starts. Turn to Chapter +4. + +STEP 3 (KA/KI Only) ____ _ + + Mount a recently formatted disk pack on a disk drive. +For example, RPA0. + +STEP 4 (KA/KI only) ____ _ + +Mount the 6.03 Manufacturing Bootstrap tape containing your monitor on +MTA0, which is write-locked. Drive 0 is required for READIN with TM10 +controllers. On TU70's the tape must be mounted on the lowest +numbered ready drive. + +If you are not a new installation and you would like to create your +own manufacturing tape, follow the procedure listed below. + + .GET SYS:BACKUP + .SAVE MTA0:BACKUP + .SAVE MTA0:BACKUP + .START + /TAPE MTA0: + /SAVE DSKB:[1,4]=DSKB:*.*[1,4] + +The above procedure saves two copies of BACKUP and the [1,4] disk area +(SYS:). + READIN BOOTM Page 2-3 ______ _____ + + +STEP 5 (KA/KI only) ____ _ + +For a TM10 controlled magtape set the READIN switches to 340. For a +TU70, set the READIN switches to 220. + +STEP 6 (KA/KI only) ____ _ + +In order, press the STOP and RESET switches and set the NXM switch +off; then, press READIN. The tape rewinds and reads in the BOOTM +bootstrap, which then allows you to specify and start the 6.03 +monitor. + +STEP 7 (KA/KI Only) ____ _ + +BOOTM outputs the prompt characters BTM>. After BOOTM prints its +prompt, you must type a file specification, indicating the monitor you +want to read from the BACKUP save set on the 6.03 Manufacturing +Bootstrap tape. Type the following command line: + + DSKB: yurmon.EXE[1,4] /TM02 ______ + /TX01 + +where: yurmon is the name given to your monitor. ______ + +You must specify the tape control unit: either TM02 or TX01. The +default, if you do not specify a unit, is TM10. + +The command line format to be typed to BOOTM is described in Chapter +19. + +This response begins the loading of the default monitor on the 6.03 +Manufacturing Bootstrap tape. The following dialogue is then printed +on the operator's terminal. You should type everything that is +underlined. Refer to Chapter 3 for a more detailed description of +this dialogue. + + + RK277 KI10 SYS#514 2-15-77 + WHY RELOAD:SA ;System is stand-alone; refer to Section + ;16.9. + DATE: 21-FEB-77 ;Enter the current date + TIME: 7:10 ;Type the current + ;time of day, using a 24-hr. clock. + STARTUP OPTION:REFRESH ;Specify the LONG startup + ;option if your + ;installation is a + ;new installation or + ;you are using blank + ;disk packs. + TYPE STR NAME TO BE REFRESHED (CR IF NONE, ALL IF ALL) + DSKB ;The structure on + ;which the monitor + ;is to reside. + ;Refer to Section 16.8 + ;for a description of the + READIN BOOTM Page 2-4 ______ _____ + + + ;LONG Dialogue. + + TO AUTOMATICALLY LOG-IN UNDER [1,2] TYPE "LOGIN" + .LOGIN + .RUN MTA0: BACKUP ;This executes the BACKUP + ;program found on the + ;manufacturing + ;magtape. Refer to + ;Chapter 17. + + /TAPE MTA0: + /RESTORE ;Move files to DSKB[1,4] + ! ;BACKUP's indication + ;that it is busy. + "DONE + ?BKPHSG CANNOT GET HIGH SEGMENT BACK + + ;Ignore this error + ;message. + +Now, turn to Chapter 4. + + + + + + + + + + + + + CHAPTER 3 + + START THE MONITOR _____ ___ _______ + + + +This chapter briefly describes the system start-up dialogue, which +appeared in the examples in Chapters 1 and 2. + +You can start your monitor with the LONG startup option and refresh +the disks. If your disks have already been formatted and refreshed, +respond with the NOINITIA startup option. Note that disk packs must +be formatted by a Field Service formatting program, before you can +attempt to use them with a monitor. + +The LONG START-UP Option is not described in this chapter. The +Start-Up Options are a portion of the ONCE-Only dialogue, which is +completely described in Chapter 16. + +STEP 1 ____ _ + +The ONCE-Only dialogue begins between you and the system. ONCE types: + + SYSCHK (Y,N): + +If you type Y in response, the system will run a 5-second diagnostic +program that ensures the accessibility of all configured memory and +system devices. A reply of N or a carriage return skips the execution +of the diagnostic program. + +STEP 2 ____ _ + +ONCE then types the system name (which was specified in MONGEN refer +to Section 8.4, question number 4) followed by the monitor creation +date. For example: + + LOAD 3 SYS#10 KL 02-1-77 + +When ONCE prints the following: + + WHY RELOAD: + +reply with NEW and press the carriage return. Instead of responding +with NEW, you can respond with one of the below: + + OPR NXM CM + START THE MONITOR Page 3-2 _____ ___ _______ + + + PARITY HALT SA + POWER LOOP SCHED + STATIC HUNG OTHER + HARDWARE PM + +If you do not reply within 60 seconds, OTHER is assumed. + +STEP 3 ____ _ + +ONCE prompts with: + + DATE: + +after which you type the current date; for example: 1-MAR-77. ONCE +then prompts with: + + TIME: + +after which you type a 4-digit number indicating the current time, +using a 24-hour clock. For example: 2015, indicating 8:15 PM. + +STEP 4 ____ _ + +ONCE prompts with: + + STARTUP OPTION: + +after which you respond with LONG if your disks have not been +refreshed. Otherwise, respond with NOINITIA. The NOINITIA option +responds with a . and you must LOGIN as a [1,2] job. + +The LONG startup option allows you to explicitly set all system +parameters and to refresh and restructure the file system in a +non-standard way. + +The ONCE dialogue, including the LONG startup dialogue is described in +Chapter 16. + + + + + + + + + + + + + CHAPTER 4 + + RESTORE SELECTED FILES _______ ________ _____ + + + +Before reading this chapter, make sure you are using the latest field +image version of BACKUP. If you are a new installation and you have +just gotten BACKUP from the Manufacturing Bootstrap tape, you should +have the correct BACKUP version. If you have been running a TOPS-10 +monitor, be sure you have the proper version of BACKUP on SYS:. +Verify that the version number is the latest by checking it against +the software version number in the most recent DECsystem-10 +DISPATCH/BULLETIN. + +To install a 6.03 monitor, certain monitor files must be restored at +800 bits/inch from the standard distribution tapes and from the +unbundled distribution tapes. The [10,7] area is used in these +instructions to designate the restore area. But, another +project-programmer number can be substituted for [10,7]. Normally, +these files are restored to the structure DSKB. However, if your +system does not have a DSKB, BACKUP can be restored to any designated +file structure. (Refer to Chapter 17.) + +To simplify the restore process, you should restore files on the +monitor tape in the order they appear on the distribution tape. Files +on the monitor tape are normally in alphabetical order. To find out +the appropriate order, print a directory of the tape on the line +printer. To do so, type the following command lines. + + .START + /REWIND + /DENSITY 800 + /PRINT LPT + +The number of files you should restore from the monitor distribution +tape to the disk is determined by the amount of disk space you have +available. The instructions for three different situations are given +below: + + 1. If your installation has slightly more than 20,000 free disk + blocks + + 2. If your installation has about 10,000 free disk blocks + + 3. If your installation has very few free disk blocks. + +If you have enough disk space available, you should also restore all +the files from other distribution tapes using the appropriate +project-programmer number. Otherwise, you may need to selectively +restore certain files, because you may need some unbundled files for +your monitor. Also, some of the utility programs, assumed to be on +the monitor distribution tape in the instructions below, may be on the +language distribution tape because of changes in the packaging +procedure. + RESTORE SELECTED FILES Page 4-2 _______ ________ _____ + + + 1. If your installation has slightly more than 20,000 free + blocks of disk space, you can restore all files on the 6.03 + monitor distribution tape. In this case, the latest versions + of all files are available for use, and you need not worry + about selectively restoring individual files. + + The procedure below should be followed, first for the CUSP + tape, then for the 6.03 monitor distribution tape, and last + for each of your unbundled tapes, if you have any. + + To restore all files, ensure that the tape is mounted + properly and type to BACKUP: + + .R BACKUP + /REWIND + /INTERCHANGE + /DENSITY 800 + /RESTORE[10,7]*.*=PIP.EXE + "DONE + /REWIND + /SUPERSEDE ALWAYS + /INTERCHANGE + /RESTORE[10,7]*.*=*.* + "DONE + + The purpose of restoring PIP.EXE separately is to protect + yourself. If the disk fills up, you will need PIP to delete + files and then continue restoring. Because all of the + installation batch control files assume that the field image + files are in [10,7], we recommend your using that + project-programmer number. + + If you attempt to restore all files and receive the error + message + + ?LOOKUP/ENTER FAILURE (14) + + indicating that the disk storage capacity has been exceeded, + you must restore only selected files as described in + situation 2, which follows. + + After restoring all the files, you should print the .DOC + .MAN, .RND, .RNH and .RNO files. They contain useful program + documentation. The .RND, RNH, and .RNO files must first be + expanded with RUNOFF by typing: + + .RUN DSK:RUNOFF[10,7] + + *filename + + *^C + + All .RND files become .DOC files, all .RNH files become .HLP + files, and all .RNO files become .MEM files after they have + been through RUNOFF. + + 2. If your installation has about 10,000 free blocks of disk + space, you can restore all monitor-related files to the disk. + These files enable you to build and start the monitor, to + assemble all monitor source files, to make modifications with + SOUP, and to obtain monitor listings. + + To build the monitor you must determine which type of monitor + is best for your configuration and then choose the + RESTORE SELECTED FILES Page 4-3 _______ ________ _____ + + + appropriate .CMD file for your system. (See Chapter + 10.) After selecting the file, you should restore it and + PIP.EXE using BACKUP. In the example below, the .CMD file + for the standard KI configuration is used. Type to BACKUP: + + /REWIND + /INTERCHANGE + /DENSITY 800 + /SUPERSEDE ALWAYS + /RESTORE[10,7]*.*=CONKI.CMD,PIP.EXE + "DONE + /^C + + Then, list the contents of CONKI on your terminal using PIP. + + Type: + + .RUN PIP[10,7] + + *TTY:=CONKI.CMD[10,7] + *^C + + The monitor related files are printed on your terminal. + + Then restore all files printed on your terminal with the + extension .MAC, excluding F???.MAC, HDW???.MAC, TTY???.MAC, + and NET???.MAC, because you must generate these files with + MONGEN, which is described in Chapter 8. There is no need to + repeat files that are duplicated on the TTY listing. Also, + in lines containing an equal sign, only files to the right of + the equal sign need to be restored. For example, for the + line, + + COMDEV.RLI=HDWKI.MAC+TTYKI.MAC+NETKI.MAC+COMDEV.MAC + + restore only COMDEV.MAC. These files are for the standard KI + monitor, determined by the imbedded 'KI.' + + The procedure below should be repeated for the CUSP tape, + then for the 6.03 monitor distribution tape, and last for + each of your unbundled tapes, if you have any. + + To restore the necessary files, type: + + .RUN DSK:BACKUP[10,7] + + /REWIND + /INTERCHANGE + /DENSITY 800 + /SUPERSEDE ALL + /RESTORE[10,7]*.*= filenames (separated by commas) + + where filenames include BWR603.RNO, COMDEV.MAC, COMMOD.MAC, + COMMON.MAC, MONGEN.EXE, S.MAC, WBOOT.EXE, the appropriate + TOP?10.REL file, and necessary .MAC files from the .CMD file. + Note that these files are distributed on the 6.03 monitor + distribution tapes. + + where filenames include COMPIL.EXE, FGEN.HLP, FILEX.EXE, + LINK.EXE, LNKSCN.EXE, LNKLOD.EXE, LNKMAP.EXE, LNKXIT.EXE, + LNKERR.EXE, LNK999.EXE, MACRO.EXE, and RUNOFF.EXE. Note that + these files are on the CUSP tape. + + If you are building a monitor from scratch, also restore the + RESTORE SELECTED FILES Page 4-4 _______ ________ _____ + + + following files. + + /RESTORE[10,7]*.*=LOGIN.EXE,LOGOUT.EXE,REACT.EXE + + If you have any unbundled distribution tapes (e.g., virtual + memory), these tapes must be restored at this time. Refer to + Chapter 10 for a list of the file names contained on the + unbundled distribution tapes. + + It is recommended that you restore and print copies of .DOC, + .MAN, .RND, .RNH, and .RNO files if there is sufficient + space. They contain useful program documentation. The .RN? + files must be expanded with RUNOFF by typing: + + .R RUNOFF + + *filename + + *^C + + All .RND files become .DOC files, all .RNH files become .HLP + files, and all .RNO files become .MEM files after they have + been run through RUNOFF. + + 3. If your installation has very few free disk blocks, + selectively restore only essential monitor building files. + With the minimum number of files, you can only build and + start the monitor. You cannot assemble all monitor source + files and you cannot merge your modifications with SOUP. You + may want to free additional disk space to perform these + functions. + + To restore only the essential files, mount the 6.03 monitor + tape and follow the procedure below to restore the necessary + files: + + .R BACKUP + /REWIND + /INTERCHANGE + /DENSITY 800 + /RESTORE[10,7]*.*=BEWARE.603,COMMOD.MAC + /RESTORE[10,7]*.*=COMMON.MAC,COMDEV.MAC,COMPIL.EXE + /RESTORE[10,7]*.*=FGEN.HLP,BACKUP.EXE, MONGEN.EXE + /RESTORE[10,7]*.*=PIP.EXE,S.MAC,TOP?10.REL,W?BOOT.EXE + "DONE + /^C + + Then mount the CUSP tape and follow the procedure below to + restore the necessary files: + + .START + /REWIND + /INTERCHANGE + /DENSITY 800 + /RESTORE[10,7]*.*=BACKUP.EXE,FILEX.EXE + /RESTORE[10,7]*.*=LINK.EXE,LNKSCN.EXE + /RESTORE[10,7]*.*=LNKLOD.EXE,LNKMAP.EXE + /RESTORE[10,7]*.*=LNKXIT.EXE,LNKERR.EXE + /RESTORE[10,7]*.*=LNK999.EXE,MACRO.EXE + /RESTORE[10,7]*.*=PIP.EXE + "DONE + /^C + + where TOP?10.REL is the specific .REL file needed for your + RESTORE SELECTED FILES Page 4-5 _______ ________ _____ + + + configuration. (See Chapter 9.) + + If you are building a 6.03 monitor from scratch, also restore + the following files: + + /RESTORE[10,7]*.*=LOGIN.EXE,LOGOUT.EXE,REACT.EXE + +If you have any unbundled distribution tapes (e.g., virtual memory), +these tapes must be restored at this time. Refer to Chapter 10 for a +list of the file names contained on the unbundled distribution tapes. + +It is very important that you print and read the last minute +documentation file. You can simply list or print BEWARE.603 or, +assuming the files BWR603.RNO and RUNOFF.EXE have been restored from +the tape, expand the RUNOFF file and then print it. + +Expand the file with RUNOFF by typing: + + .RUN DSK:RUNOFF[10,7] + + *filename + + *^C + +All .RNO files become .MEM files after they have been run through +RUNOFF. + + + + + + + + + + + + + CHAPTER 5 + + COPY MONITOR SUPPORT PROGRAMS ____ _______ _______ ________ + + + +If your installation is running a current monitor, you should install +monitor support programs prior to building the 6.03 monitor. If you +have not previously installed the latest versions of monitor-related +programs, or you are building the 6.03 monitor from scratch, you must +now copy monitor support programs to SYS with PIP. Note that ACCT.SYS +must be on SYS or you will not be allowed to LOGIN. You should log in +under [1,2] and type: + + .RUN DSK:PIP[10,7] + + *SYS:<155>/X=DSK:[10,7]filename,... + +where filenames include: + + DDT.REL,JOBDAT.REL,*.EXE,*.ATO + *.VMX (for virtual memory monitors only; it is on the VM + unbundled tape) + +Some of the files may also have to be copied from [10,6]. + +Also, if you do not have your system accounting files built, copy +*.SYS specifying protection <157>. + +If your installation has file structures of different speeds, put the +following files on the fastest structure (DSKA): + + DDT.REL,FORLIB.REL,BASIC.EXE,LIBOL.REL (if using + nonreentrant COBOL) + +You may want to put the following files on every file structure: + + SYSTAT.EXE,REDALL.EXE,DSKRAT.EXE,DSKLST.EXE, + BACKUP.EXE + +because they are needed to track down possible disk hardware problems. + + + + + + + + + + + + + CHAPTER 6 + + WRITE BOOTS _____ _____ + + + +You now must write BOOTS on disk packs with WTBOOT. WTBOOT is a +generic name for WABOOT, WIBOOT, and WLBOOT, where the second letter +(A,I,L) corresponds to your system processor (KA,KI,KL). + +This step is required on all systems to write the latest version of +BOOTS onto the disk packs. + +WTBOOT can write BOOTS, a disk bootstrap loader program, on blocks 0 +and 4 through 7 of all disk packs in the system. Run WTBOOT, WABOOT, +WIBOOT, or WLBOOT once, the first time a new 6-series monitor is +built. It is necessary to run WTBOOT again only if the disks are +reformatted or if there is a new BOOTS. BOOTS should be written on +each disk pack so that the crash procedure works. + +When writing BOOTS on disk packs for a KL10 system with 6.03, it is +important that you use the WLBOOT distributed with the 6.03 monitor. +This is important because previous versions of WLBOOT wrote in block 0 +of the disk pack, which contains the front-end file system. Writing +in block 0 wipes out the front-end bootstrap. + +To run WTBOOT log in to [1,2] and type: + + .R W?BOOT + +W?BOOT responds with: + + SELECT UNITS? + +where you respond with NO or YES. If you respond with NO, the default +BOOTs will be written on all disk packs. If you are using a KL10, +W?BOOT will not write the READIN loaders. If not using a KL10, W?BOOT +will write the default READIN loader on all RS04s and RP0xs. Note +that RP0x indicates RP04, RP05, or RP06. + +If you respond with YES, W?BOOT responds with: + + UNIT unit-name + +You are to respond with the type of BOOTs you want written on each +type of unit in the system. You respond with DP, RP, R2, ZERO, or +SKIP. + +DP writes RP02/RP03 BOOTS on the pack mounted on that unit. + +RP writes RH10/RP0x BOOTS on the pack mounted on that unit. + +R2 writes RH20/RP0x BOOTS on the pack mounted on that unit. + +ZERO prevents the monitor from reading BOOTS from the pack + WRITE BOOTS Page 6-2 _____ _____ + + + mounted on that unit. + +SKIP prevents W?BOOT from changing the pack mounted on that unit. + +If you respond with a carriage return, W?BOOT writes the default +BOOTS. The default is RP02/RP03 BOOTS on RP02/RP03 packs, RH10/RP0x +BOOTS on RP0x packs (i.e., RH10s), RH20/RP0x BOOTS on RH20 packs. For +each RS04 or RP0x, W?BOOT asks you if the READIN loader should be +written in 18- or 22-bit mode format. You respond with NONE, 18, 22, +or carriage return. + +NONE if no READIN loader should be written on block 0 (KL10). + +22 if the DF10C is normally in 22-bit mode format. + +18 if the unit is not on a controller connected to a DF10C, or + if the DF10C is normally in 18-bit mode format. + +CR for the default response, which is 18-bit mode on even units + and 22-bit mode on odd units. + +When the procedure is completed, the system responds: + + EXIT + +Note that WTBOOT writes BOOTS only on disk packs that are on line and +not write locked. (For more information on BOOTS, or on loading BOOTS +with a paper tape, refer to the DECsystem-10 Operator's Guide in the +DECsystem-10 Software Notebooks.) + + + + + + + + + + + + + CHAPTER 7 + + MERGE MODIFICATIONS _____ _____________ + + + +Omit this step if you are building an unmodified DEC monitor and do +not intend to merge any modifications developed at your installation. + +SOUP (Software Updating Package) is a set of programs used to update +source files. It is designed to simplify the merging of customer +modifications with DEC-supplied files. + +The DECsystem-10 Software Updating Package Programmer's Reference +Manual in the DECsystem-10 Software Notebooks describes in detail the +set of programs in the SOUP package and explains how to use them. If +you have several modifications to be merged with many source files, +you may use the DECsystem-10 Software Notebook document entitled +SOUPing Parallel Monitor Developments Together (MULTI) as a guide. + + + NOTE + + Use of SOUP requires that the + appropriate source (.MAC) files have + been restored from the distribution + tape. + + Be very familiar with SOUP before + attempting to use it. + + + + + + + + + + + + + + + CHAPTER 8 + + GENERATE A MONITOR WITH MONGEN ________ _ _______ ____ ______ + + + +8.1 INTRODUCTION ____________ + +The Monitor Generator (MONGEN) is a dialogue program enabling you to +choose the software most appropriate for your installation and to +define your hardware configuration. + +The dialogue produces the files needed to build the monitor, and it +then tailors them to your system configuration. Parameter assignments +within these files determine how the monitor data base modules are +assembled. The dialogue consists of questions typed by MONGEN on your +terminal and your answers followed by a carriage return. + +Before running MONGEN, you should + + 1. Become acquainted with the current version of the MONGEN + dialogue. + + 2. Be thoroughly familiar with your system configuration. + + 3. Know what changes you wish to make to the monitor currently + running. + + + + +8.2 MONGEN ORGANIZATION ______ ____________ + +The MONGEN dialogue is divided into four sections, each asking +questions about a specific aspect of the system configuration. The +four sections are: + + HDWGEN which defines the system hardware configuration + (Section 8.4) + + TTYGEN which defines the system terminal configuration + (Section 8.5) + + NETGEN which defines the system network configuration (refer + to Section 8.6) + + FGEN which defines the system software features and options + (Section 8.7) + +The first time you generate the files for a new monitor, you should +answer the questions in each of the four sections. On subsequent +occasions, you can change only one, two, or three of the four +sections. The number of sections you change depends on where your +changes are and which section(s) your changes affect. You need only +answer the questions in the section you are changing. + GENERATE A MONITOR WITH MONGEN Page 8-2 ________ _ _______ ____ ______ + + +After you answer the questions for the four sections of MONGEN, four +files will be generated - - HDWCNF.MAC, TTYCNF.MAC, NETCNF.MAC, and +F.MAC. These are the default names of the files containing your +MONGEN dialogue. You may change these file names by responding to +question number 2 in HDWGEN, TTYGEN, NETGEN, and/or FGEN. + +If, after generating the four files, you wish to redefine one of them, +you can reanswer the questions for that section. Then,you can +assemble this new file along with the other three. + +In this chapter, each MONGEN question is described within its +appropriate section. + + + +8.3 EXECUTING MONGEN _________ ______ + +To execute the version of MONGEN on SYS:, type the following command: + + R MONGEN + +To execute the version of MONGEN on your disk area, type the following +command: + + RUN MONGEN + +MONGEN will respond with + + MONGEN FOR 603 MONITORS + /HELP(PROMPT,SHORT,LONG): + +MONGEN wishes you to indicate which one of the three following +dialogue modes you wish to use. + + MODE EFFECT + + SHORT MONGEN types only abbreviated questions on your + terminal. This mode assumes that you need no + explanation of the question and that you are familiar + with the choice of answers. SHORT mode is recommended + only for experienced users of this version of MONGEN. + + PROMPT MONGEN types the same abbreviated question as in SHORT + mode, but adds, within parentheses, a choice of + answers. (Note that the first item within the + parentheses is the default answer.) This mode is + recommended for users familiar with the MONGEN + dialogue, but who would prefer to have the choice of + answers typed with each question. + + LONG MONGEN types the question, the choice of answers within + parentheses, and an explanation of the question within + square brackets. This mode is recommended for all + first time users of this version of MONGEN. + +The mode you choose will be used throughout the dialogue. To change +modes during a MONGEN dialogue, answer a question by typing + + /HELP + +This answer will change the mode to the next longest, but only for the +current question. To change modes for the rest of the dialogue, type + + /HELP:x + GENERATE A MONITOR WITH MONGEN Page 8-3 ________ _ _______ ____ ______ + + +where x is either SHORT, PROMPT, or LONG (abbreviated S, P, or L). + + + +8.3.1 MONGEN Dialogue Format ______ ________ ______ + +MONGEN questions and responses are in the form: + + question(possible answers) [explanation]:answer + +The possible answer portion of this format description is usually in +one of the following forms: + + (min-max) Legal range + + (default,min-max) Default response followed by legal range + + (Y,N) Yes or No + + (a,b,c, ... z) Multiple choice + +Type your response directly after the colon. When you finish press +the RETURN key. If you want the default response, press the RETURN +key immediately after the colon. Because of the nature of some MONGEN +questions, possible answers are not offered. + +Answers to questions requesting consecutive TTY line number +identification can be typed on one line. For example: + + 1-10 specifies TTY line numbers 1 through 10. + + 13 specifies TTY line number 13. + + 22-24 specifies TTY line numbers 22 through 24. + +If you type an illegal or inappropriate response, MONGEN will type an +error message after which you may respond to the question again. The +possible error messages are listed in Section 8.19. + + + +8.3.2 Generating a New Monitor __________ _ ___ _______ + +After typing the command R MONGEN and after you respond to the /HELP +question, MONGEN will type + + 1^1 WHICH GEN (HDW, TTY, NET, F): + +Respond with either HDW, TTY, NET, or F to indicate which section you +wish to configure. For example, if you respond with HDW, MONGEN will +start typing the HDWGEN questions. When the HDWGEN MONGEN dialogue +has been completed, question number one will be retyped requesting you +to type another section name. + + + + + + + + +------------------ +1. Note that all questions within this document are preceded with a +number. These numbers are used for reference only; they are not +printed by MONGEN. + GENERATE A MONITOR WITH MONGEN Page 8-4 ________ _ _______ ____ ______ + + +8.4 HDWGEN ______ + +HDWGEN is the section containing questions about the central +processor(s), disklike storage devices, real-time devices, and +peripheral devices. + +2 OUTPUT (DSK:HDWCNF.MAC): + + If you accept the file HDWCNF.MAC and device DSK: + as the media for storing your answers to MONGEN, + press the return key. If you do not accept them, + type your preferred device name, file name, and + project/programmer number. + + +3 DECSYSTEM10 (1040,1050,1055,1070,1077,1080,1088): + + Respond with the type of system you are + configuring. + + Type of System Response + + KA10 CPU (small) 1040 + KA10 CPU (large) 1050 + dual-KA10 CPUs 1055 + KI10 CPU 1070 + dual-KI10 CPUs 1077 + KL10 CPU 1080 + dual-KL10 CPUs 1088 + + +4 SYSTEM NAME: + + Respond to this question with your system name in + 24 characters or less. This system name is the + 'banner' printed when you issue the INITIA + command. For example, KG77A KL10 #1026. + + +5 CPU0 SERIAL # (1-10000): + + Respond with CPU0's serial number, which falls + into the range 1 to 10000. MONGEN will repeat + this question once for each processor in your + system. + + +5A CPU1 SERIAL #(1-10000): + + Respond with CPU1's serial number, which falls + into the range 1 to 10000. (This question is + typed only if you specified in question 3 that you + have a dual-processor system.) + + +6 # DK10'S ON CPU0 (1,0-2): + + If your processor is a KL10, this question will + not be typed unless you answer N to question 8. + Respond with the number of DK10 real-time clocks + for CPU0. The default number is one; the maximum + is two. (The DK10 real-time clock keeps time in + units of 10 microseconds.) If you have a dual + processor system, this question will be repeated. + GENERATE A MONITOR WITH MONGEN Page 8-5 ________ _ _______ ____ ______ + + +6A # DK10'S ON CPU1 (1,0-2): + + Respond with the number of DK10 real-time clocks + for CPU1. (This question is typed only if you + specified in question 3 that you have a + dual-processor system.) + + +7 EXCLUDE MONITOR OVERHEAD FROM USER RUN TIME (Y,N): + + Answer Y (Yes) or N (No). The answer to this + question is independent of whether time accounting + is performed with the line frequency clock (50 or + 60 Hertz) or the real-time clock (100000 Hertz). + If you respond with Y, users will receive a more + accurate accounting of their processor usage, + because user runtime is reported independent of + system loading. However, all installations that + charge their customers for processor usage should + be aware that the exclusion of monitor overhead + will decrease the reported user runtime by 10 to + 30 percent. + + If you respond with N, monitor overhead will be + included in run-time statistics. Whether you + respond with Y or N to this question, monitor + overhead will be reported as a separate statistic + that may be used by the system manager in + determining the amount of CPUtime spent for + overhead. + + With EBOX/MBOX accounting (KL10 systems only), + meters are turned off at the beginning of the + overhead period and turned on again at the end. + If your system is not a KL10 (1080 series), jump + to question number 10. + + +8 EBOX/MBOX TIME ACCOUNTING (Y,N): + + This question is typed only if you responded to + question number 3 with 1080 (1088, 1090, 1099). + Answer Y or N. If you respond with Y, run-time + accounting will be computed using the KL10 + internal clocks and question number 9 will be + typed. If you respond with N, the next question + typed will be question number 6. For maximum user + run-time reproducibility, you should answer Y to + both this question and question number 9. + + +9 EXCLUDE PI TIME FROM USER RUN TIME (Y,N): + + This question is typed only if you responded with + 1080 to question number 3 and Y to question number + 7. Answer Y or N. If your response is Y, the + EBOX and the MBOX accounting clocks will be + stopped whenever a Priority Interrupt is in + progress. For maximum user run-time + reproducibility, you should answer Y to both this + question and question number 8. + + +10 HIGH PRECISION TIME ACCOUNTING (Y,N): + GENERATE A MONITOR WITH MONGEN Page 8-6 ________ _ _______ ____ ______ + + + This question is typed only if you responded to + question 6 and/or question 6A with a value equal + to or greater than 1. Answer Y or N to this + question. If Y, more precise run-time + measurements will be given because the system will + use 10-microsecond time accounting. This will + more accurately reflect real CPU-time, independent + of context switching. (Therefore, a compute-bound + job is not charged for a whole 60th of a second, + even though an I/O-bound job ran during that time + interval.) If N, question number 11 will be typed. + + +11 DK10 SOFTWARE (Y,N): + + This question is typed only if you responded with + N in response to question number 10 and a value + greater than or equal to 1 in response to question + number 6 and/or question number 6A. To include + the real-time clock service routine, answer Y; to + omit it, answer N. This device is not available + to a user program unless it issues an RTTRP + monitor call. The service routine is used only + for high-precision time accounting. + + +12 # DATA CHANNELS (2,1-8): + + Respond with the number of data channels in your + system (DF10s, DF10Cs, DX10s, or RH20s for disk or + tape). The default is 2; the maximum is 8. + + + NOTE + + Questions 13 through 23 are repeated once + for each data channel you specified in + response to question 12. + + +13 CHANNEL n TYPE (DF10,DF10C,DX10,RH20): + + Respond with the type of channel n (DF10,DF10C or + DX10). This question is asked once for each data + channel that you specified in response to question + number 12. If you respond with DF10 or DF10C, + read questions 14 through 20B. If you respond + with DX10, read questions 21 and 21A. If you + respond with RH20, read questions 22 through 23B. + + Note that channel n corresponds to the first, + second, third ... channel you configure. The n + does not necessarily correspond to a hardwired + channel number. + + +14 # RC10S (0-2): + + Respond with the number of controllers for the + RD10 Burroughs disk and RM10B Bryant drums on + channel number n. If you respond with 0, question + number 14A will not be printed. + GENERATE A MONITOR WITH MONGEN Page 8-7 ________ _ _______ ____ ______ + + +14A # UNITS ON FHx (1-4): + + This question is repeated n times (where n is your + response to question number 14.) Each time the + question is typed, x will be incremented to the + next alphabetic in sequence starting with A (e.g., + FHA, FHB,...). Respond with the number of disks + and/or drums associated with controller FHx. + + +15 # RH10S FOR RS04'S (0-3): + + Respond with the number of controllers for the + RS04 swapping disks on channel number n. If you + respond with 0, question number 15A will not be + typed. Both RS04 and RP04 disk units have RH10 + controllers; RS04s have the lower device codes + between the two. + + +15A # UNITS ON FSx (1-8): + + This question is repeated n times (where n is your + response to question number 15). Each time the + question is typed, x will be incremented to the + next alphabetic in sequence starting with A (e.g., + FSA, FSB,...). Respond with the number of + swapping disks associated with controller FSx on + channel n. + + +16 # RH10S FOR RP04'S (0-3): + + Respond with the number of controllers for RP04 + and RP06 disk pack units on channel number n. If + you respond with 0, question number 16A will not + be typed. Both RS04 and RP04 disk units have RH10 + controllers; RS04s have the lower device codes of + the two. + + +16A # UNITS ON RPx (1-8): + + This question is repeated n times (where n is your + response to question number 16). Each time the + question is typed, x will be incremented to the + next alphabetic in sequence starting with A (e.g., + RPA, RPB,...). Respond with the number of disk + packs associated with controller RPx. + + +17 # RP10S(0-3): + + Respond with the number of controllers that are in + the system for RP02 and RP03 disk pack units on + channel number n. If you respond with 0, question + number 17A will not be typed. + + +17A # UNITS ON DPx (1-8). + + This question is repeated n times (where n is your + response to question number 17). Each time the + question is typed, x is incremented to the next + GENERATE A MONITOR WITH MONGEN Page 8-8 ________ _ _______ ____ ______ + + + alphabetic in sequence starting with A (e.g., DPA, + DPB,...). Respond with the number of disk pack + units associated with controller DPx. + + +18 # TM10BS (0-2): + + Respond with the number of controllers that are in + the system for NRZI-only drives on channel n. If + you respond with 0, question number 18A will not + be typed. + + +18A # UNITS ON MTx (1-8): + + This question is repeated n times (where n is your + response to question number 18). Each time this + question is typed, x is incremented to the next + alphabetic in sequence starting with A (e.g., MTA, + MTB,...). Respond with the number of magtape + units associated with controller MTx. + + +19 # TC10CS (0-1): + + Respond with the number of special systems tape + controllers for TU42s and TU43s on channel n. If + you respond with 0, question number 19A will not + be typed. + + +19A # UNITS ON MTx (1-8): + + This question is repeated n times (where n is your + response to question number 19). Each time this + question is typed, x is incremented to the next + alphabetic in sequence. Respond with the number + of TU42s and TU43s associated with controller MTx. + + +20 # RH10'S FOR TM02'S (0-2) + + Respond with the number of mass-bus tape + controllers for TU16s and TU45s on channel n. If + you respond with 1 or 2, questions 20A and 20B + will be typed. + + +20A HOW MANY TM02'S ON RH10 #n (1-8) + + Respond with the number of subunits (tape drives) + on each unit. This question is repeated once for + each RH10 specified in question 20. + + +20B HOW MANY DRIVES ON TM02 n (1-8) + + Respond with the number of drives on the specified + TM02. + +If you have more data channels to configure, refer to question 13, +otherwise, refer to question 24. Questions 14 through 20B will be +repeated if you have to configure more DF10 or DF10C channels. + GENERATE A MONITOR WITH MONGEN Page 8-9 ________ _ _______ ____ ______ + + +21 # CONTROLLERS (0-1): + + Respond with the number of TX01 or TX02 + controllers for TU70 tape drives. This question + is typed only when you have configured a DX10 data + channel. If you respond with 1, question 21A is + typed. + + +21A # UNITS ON MTx (1-8): + + Respond with the number of units on TU70 tape + drive. + +If you have more data channels to configure, refer to question 13. +Otherwise, refer to question 24. Questions 21 and 21A will be +repeated if you have more DX10 channels to configure. + + +22 # RH20S for RP04'S, RP06'S (0-1): + + Respond with the number of RH20 controllers for + RP04 and RP06 disk pack units on channel n. This + question is typed only if you configure an RH20 + channel. If you respond with 1, question 22A is + typed. + + +22A # UNITS ON RPx (1-8): + + Respond with the number of units associated with + controller RPx. + + +23 # RH20'S FOR TM02'S (0-1): + + Respond with the number mass-bus controllers for + TU16s and TU45s on channel n. If you respond with + 1, questions 23A and 23B will be typed. + + +23A HOW MANY TM02'S ON RH20 # x (1-8): + + Respond with the number of tape drives (subunits) + associated with RH20 number x. + +23B HOW MANY DRIVES ON TM02 x (1-8): + + This question is repeated once for each TM02 you + specified in response to question 23A. + +If you have more data channels to configure, refer to question 13. +Otherwise, refer to question 24. Questions 22 through 23B will be +repeated if you have more RH20 channels to configure. + + +24 # TM10AS (0,0-2): + + Respond with the number of I/O Bus-type + controllers for NRZI-only drives. If you respond + with 0, question 24A will not be typed. + + +24A #UNITS ON MTx (1-8): + GENERATE A MONITOR WITH MONGEN Page 8-10 ________ _ _______ ____ ______ + + + This question is repeated n times (where n is your + response to question 24). Each time this question + is typed, x is incremented to the next alphabetic + in sequence. Respond with the number of magtape + units associated with MTx. + +For each magnetic tape you have configured, MONGEN asks if it is a +7-track unit and if it is capable of 6250 bits/inch density. + + First, MONGEN prints the following: + + SPECIFY WHICH DRIVES (M-N) ARE 7-TRACK DRIVES. [TYPE ONE + NUMBER (M) OR ONE RANGE (M-N) OR ALL ON SEPARATE LINES. + TYPE AN EXTRA CARRIAGE RETURN WHEN THROUGH.] + + FOR CONTROLLER MTA + . + . + . + + FOR CONTROLLER MTB + . + . + . + + After MONGEN has asked the above question for each magnetic tape + drive, it then asks the following question for each tape drive: + + SPECIFY WHICH TAPE DRIVES (M-N) ARE CAPABLE OF 6250 BPI + DENSITIES. [TYPE ONE NUMBER (M) OR ONE RANGE (M-N) OR ALL + ON SEPARATE LINES. TYPE AN EXTRA CARRIAGE RETURN WHEN + THROUGH.] + + FOR CONTROLLER MTA + . + . + . + + FOR CONTROLLER MTB + . + . + . + + +25 # JOBS (1-n): + + Respond with the maximum number of jobs attached + and/or detached. Do not include the null job. + Each job requires approximately 1/4 of 1K core, so + specify only the number of jobs needed. + + +26 MAX. K OF CORE FOR EACH JOB (0, 0-n): + + This question is typed only for KA10-based + systems; question 26A is typed for KI10 and + KL10-based systems. Respond with the maximum + amount of core that any one job may use. This + value is specified in number of 1K core blocks. A + response of 0 indicates all of core. + + +26A MAX. P OF CORE FOR EACH JOB (256-512): + GENERATE A MONITOR WITH MONGEN Page 8-11 ________ _ _______ ____ ______ + + + This question is typed only for KI10/KL10 systems. + Respond with the maximum amount of core which any + one job may use. This value is specified in + number of 512-word pages. A response of 0 + indicates all of core. + + +27 # K TOTAL SYSTEM CORE (32-4096): + + This question is typed only for KA10-based + systems. Respond with the amount of memory the + system is expected to use. At monitor + initialization time, the operator will be asked if + the actual amount of memory is less than your + response to this question. You should, therefore, + specify the correct amount. If this value is + smaller than the amount of memory you want to put + on line, the monitor will not allow the operator + to put it on line. If more than 256K is desired, + you must set the feature test switch FT22BIT to + -1. + + +27A #P TOTAL SYSTEM CORE (256-4095): + + This question is typed only for KI10/KL10-based + systems. Respond with the amount of memory the + system is expected to use. At monitor + initialization time, the operator will be asked if + the actual amount of memory is less than your + response to this question. You should, therefore, + specify the correct amount. If this value is + smaller than the amount of memory you want to put + on line, the monitor will not allow the operator + to put it on line. + + +28 CLOCK TICKS PER SECOND (60,50): + + Respond with the number of clock ticks per second + (power line frequency). In the U.S., the response + should be 60; in most other countries, the + response should be 50. If your system has a KL10 + processor, you may specify either 50 or 60; your + response will determine the frequency of clock + interrupts, which are generated by the KL10 + interrupt timer. In KA10- and KI10-based systems, + your response must conform to the actual frequency + of the system power supply. + + +29 # REAL-TIME DEVICES (0,0-77): + + Respond with the number of real-time devices that + can be put on a priority interrupt channel + simultaneously. The default is zero; the maximum + is 77. If your response is 0, question 29A will + be typed. + + +29A ALLOW JOBS TO BE LOCKED IN CORE (Y,N): + + Answer Y or N. A response of Y will allow jobs to + be locked in core; N will not allow jobs to be + GENERATE A MONITOR WITH MONGEN Page 8-12 ________ _ _______ ____ ______ + + + locked in core and question 30 or 30A will not be + typed. + + +30 # K MIN GUARANTEED AMONG JOBS NOT LOCKED IN CORE (0, 0-256): + + This question is typed only for KA10-based + systems. Respond with a value indicating the + amount of core guaranteed among all jobs that are + not locked in core. The default is 0, which + indicates all of core. If you respond with 0 and + answer Y to question 29A, no jobs will be allowed + to lock in core. The value you specify in + question 30 can be overridden by a SET CORMIN + command. + + +30A # P MIN GUARANTEED AMONG JOBS NOT LOCKED IN CORE (0,0 - max): + + This question is typed only for KI10/KL10-based + systems. Respond with a value indicating the + amount of core guaranteed among all jobs that are + not locked in core. The default is 0, which + indicates all of core. If you respond with 0 and + answer Y to question 29A, no jobs will be allowed + to lock in core. The value you specify in + question 30A can be overridden by a SET CORMIN + command. + + +31 # HIGH PRIORITY QUEUES (0,0-15): + + Respond with the number of high priority queues in + your system. The default is 0; the maximum is + 15. + + +32 CCL COMMANDS TO STAY IN CORE (Y,N): + + Answer Y or N. Y allows system programs to pass + commands to one another via core (TMPCOR monitor + call) rather than disk. The preferred answer to + this question is Y. + + +33 METER (Y,N): + + Answer Y or N. Y includes the METER monitor call + software in your system, which enables performance + analysis metering. N omits the METER monitor call + software from your system. + + +34 SYSCHK (Y,N): + + Answer Y or N. Y will allow an initial hardware + integrity check to be performed at monitor + initialization time. N makes it impossible for + this check to be performed. + + +32 MSGSER (Y,N): + + Answer Y or N. Y causes the multiplexed-channel + GENERATE A MONITOR WITH MONGEN Page 8-13 ________ _ _______ ____ ______ + + + (MPX) software to be loaded. MPX allows more than + one device to be associated with a given I/O + channel. (This feature is required for operation + of TYPESET-10 and/or MCS-10.) N prevents the + loading of the MPX software. + + +36 PSISER (Y,N): + + Answer Y or N. Y causes the PSISER program to be + loaded. PSISER provides the software interrupt + system, which enables users to specify conditions + for which an interrupt is to occur. PSISER is + required for the operation of MCS-10, GALAXY, + and/or TYPESET-10. N prevents the loading of + PSISER. + + +37 IPCF (Y,N): + + Answer Y or N. Y causes IPCF (Inter-Process + Communication Facility) to be loaded. IPCF allows + jobs and/or system processes to communicate with + each other. IPCF is required for the operation of + MCS-10, GALAXY, and/or TYPESET-10. N prevents the + loading of the IPCF software. + + +38 ENQ/DEQ (Y,N): + + Answer Y or N. Y causes the ENQ/DEQ software to + be loaded. This software provides synchronization + primitives used by COBOL and for simultaneous file + updates. N prevents the loading of the ENQ/DEQ + software. + + +39 # CDRS (1,0-2): + + Respond with the number of card readers to be + configured. The default is 1; the maximum is 2. + + +40 CDP (Y,N): + + Respond Y or N. Y will provide software for a + card punch; N will not. + + +41 DIS (Y,N): + + Answer Y or N. Y provides software for a display + device (e.g., VP10, 340, 30, VB10C); N will not. + The display device asked about here is not to be + confused with a display terminal. If you answer + Y, question number 41A will be typed. Question + number 41A will not be typed if you answer with N. + + +41A TYPE (VP10,340,VB10C): + + Respond with the type of display device you have + (VP10, 340, or VB10C). If you have type 30, + answer VP10. + GENERATE A MONITOR WITH MONGEN Page 8-14 ________ _ _______ ____ ______ + + +42 # TD10S (1,0-2): + + Respond with the number of DECtape controllers. + The default is 1; the maximum is 2. If your + response is 0, question 42A will not be typed. + + +42A # UNITS ON DTx (1-8): + + This question will be repeated n times (where n is + your response to question number 39). Each time + this question is typed, x will be incremented to + the next alphabetic in sequence beginning with A + (e.g., DTA, DTB,...). Respond with the number of + DECtape units associated with controller DTx. + + +43 LPTS (1,0-3): + + Respond with the number of line printers supported + by your system. The default number is 1. If you + respond with 0, question 43A will not be typed. + + +43A LPTn LOWER CASE (Y,N): + + Answer Y or N. Y indicates that LPTn has + lower-case capability. N indicates that the line + printer is upper-case only. This question is + repeated n times (where n is your response to + question number 40). + + +44 PLTS (0,0-2): + + Respond with the number of incremental plotters + supported by your system. The default is 0; the + maximum is 2. + + +45 PTP (Y,N): + + Answer Y or N. Y indicates that your system + includes a paper tape punch. The inclusion of a + paper tape punch is standard for KA10/KI10-based + systems, but normally excluded on KL10-based + systems. + + +46 PTR (Y,N): + + Answer Y or N. Y indicates that your system + includes a paper tape reader. + + +47 # PTYS (20,0-510): + + Respond with the number of pseudo-terminals. + (Each operator service routine and batch stream + needs one.) This response will usually equal your + response for question number 25, which asks for + the number of jobs to be attached and/or detached + at one time. If your response is greater than + zero, FTPTYUUO must be set in F.GEN to -1. Refer + GENERATE A MONITOR WITH MONGEN Page 8-15 ________ _ _______ ____ ______ + + + to Chapter 8. + + +48 DC44 (Y,N): + + Answer Y or N. Y indicates that your system + includes a DC44 front-end. DC44 is a TYPESET-10 + front-end that supports a high-speed paper-tape + reader and punch, and an on-line photocomposition + machine. If you answer N, question numbers 48A, + B, C, and D, and E will not be typed. If you + respond with Y, you must set the FTTYPE feature + test switch to -1. + + +48A DL10 PORT NUMBER FOR DC44 (0,0-7): + + Respond with the DC44 channel number (port + number). The default is 0; the maximum is 3. + DL10 port numbers for DC44s should be numbered + sequentially, beginning with 0. + + +48B # OF PA611RS (0,0-32): + + Respond with the number of high-speed paper tape + readers to be supported with the DC44. The + default is 0; the maximum is 32. + + +48C # OF PA611PS (0,0-32): + + Respond with the number of high-speed paper-tape + punches to be supported with the DC44. The + default is 0; the maximum is 32. + + +48D # OF LPC11S (0,0-6): + + Respond with the number of on-line + photocomposition machines to be supported with the + DC44. The default is 0; the maximum is 6. + + +48E PC11 (Y,N): + + Answer Y or N. Y indicates that there is a paper + tape reader and a paper tape punch on the DC44. + + +49 # OF DA28S (1,0-4): + + Respond with the number of inter-processor data + channels for the PDP-8/11/15. The default is 1; + the maximum is 4. If your response is 1 or + greater and the feature test switch FTXTC equals + 0, MONGEN assumes that you do not want any DA28s + supported. + + +49A # OF LINES FOR TTY POOL (8,0-512): + + Respond with the number of terminal lines reserved + for use on DA28 channels. The default is 8; the + GENERATE A MONITOR WITH MONGEN Page 8-16 ________ _ _______ ____ ______ + + + maximum is 512. + + +50 # DAS78'S (0,0-8): + + Respond with the number of DAS78s (bisynchronous + support as used by IBM 360s, 370s, and/or 2780s). + If you respond with a value greater than 0, you + must set the FTDAS78 feature switch to -1. + + +50A WHICH DL10 PORT IS THE DAS78 CONNECTED TO (0,0-7): + + Each DAS78 PDP-11 is connected to a DL10 port. + Respond with the number of the DL10 port. + + +50B DECIMAL LINES ON THE DAS78 (1-16): + + Each DAS78 can support up to 16 bisynchronous + lines for IBM 360s, 370s, and/or 2760s; respond + with the number of lines (in decimal) on this + DAS78. + + +51 DECIMAL "SYMBOL,VALUE" + + +52 OCTAL "SYMBOL,VALUE" + + +53 SIXBIT "SYMBOL,VALUE" + + In response to questions 51, 52, and 53, type the + constants at your installation that deviate from + the standard. Unless you specify otherwise, + HDWGEN will define each symbol in accordance with + predefined standard values. A list and an + explanation of the standard symbols and decimal + default values appear in Sections 8.14.1, 8.14.2 + and 8.14.3. For example, you could specify 1760 + as the number of nanoseconds per memory cycle + (instead of 1000) by typing: + + NSPMEM,1760 + + If you want to respond with more than one entry, + you must type each "symbol, value" on a separate + line, and end each line with a carriage return. + When you finish typing responses to question 51, + type an extra carriage return to force MONGEN to + type question 52. If all the standard values are + acceptable, type only a carriage return in + response to this question. + + HDWGEN next types the questions + + OCTAL "SYMBOL, VALUE" + + and + + SIXBIT "SYMBOL, VALUE" + + requesting the OCTAL and SIXBIT values that are to + GENERATE A MONITOR WITH MONGEN Page 8-17 ________ _ _______ ____ ______ + + + be changed from the standard settings. The answer + format is identical to that for the previous + question. Deviations from the list of default + values are the only responses required. If no + changes to the standard are required, you should + press the RETURN key in response to each of the + questions. + + Sections 8.15.1 and 8.15.2 list and explain the + standard symbols and octal values; Section 8.16 + lists and explains the standard symbols and SIXBIT + values. + + +54 TYPE "DEVICE-MNEMONIC,PI-CHANNEL,HIGHEST-AC-TO-SAVE" + + +55 TYPE "DEVICE-MNEMONIC, PI-CHANNEL" FOR SPECIAL DEVICES + + +56 TYPE "DEVICE-MNEMONIC, PI-CHANNEL, NO-OF-DEVICES" + + Questions 54, 55, and 56 request special + information about non-standard peripheral devices + and their associated priority interrupt (PI) + channels. If your installation has no special + devices, answer the three questions with a + carriage return. If your installation has a + special device, turn to Section 8.17. + +FILE DSK:HDW04D.MAC CLOSED [HDWGEN FINISHED] + + + +8.5 TTYGEN ______ + +MONGEN's TTYGEN section allows you to define your system terminal +configuration. All possible questions are listed below and on +following pages. In order to start the TTYGEN dialogue, you must +respond with TTY to question number 1 described in Section 8.3.2. + + +2 OUTPUT(DSK:TTYCNF.MAC): + + If you accept TTYCNF.MAC and the device DSK: as + the media for storing your answers to MONGEN, + press the RETURN key for your response. If you do + not accept them, type your preferred disk name, + file name, and project/programmer number. + + +3 HOW MANY DC10S (1,0-2): + + Respond with the number of data line scanners to + be supported by your system. The default 1; the + maximum is 2. If you respond with 0, question + numbers 6 and 7 will not be typed. (Refer to + Section 8.18 for a further discussion of DC10s.) + + +4 HOW MANY DC68S (1,0-2): + + Respond with the number of DC68s supported by your + system. The default is 1; the maximum is 2. The + GENERATE A MONITOR WITH MONGEN Page 8-18 ________ _ _______ ____ ______ + + + DC68 is a PDP-8 680 or 680I communications system. + If you respond with 0, question number 8 will not + be typed. + + +5 HOW MANY DC76S (1,0-8): + + Respond with the number of DC76s supported by your + system. The default is 1; the maximum is 8. The + DC76 is a PDP-11 communications system. If you + respond with 0, question number 9 will not be + typed. This is an unbundled product; therefore, + before typing a carriage return, make sure your + system includes a DC76. + + + NOTE + + For DC68s and DC76s, the monitor does not + need to know the specific type of dataset + control hardware, because correspondence + of terminal lines to dataset controller is + performed within the hardware. When + laying out the terminal line configuration + in TTYGEN, you must specify the total + number of lines available through the DC68 + and the total number of lines available + through each DC76. DC76 lines that + require dataset control must be defined as + dataset lines (via question 13). + + +6 # DC10B [OR 632] 8 LINE DATA GROUPS (1-8): + + Respond with a value in the range 1 to 8, where: + + 1 indicates TTY0-7 + 2 indicates TTY0-17 + 3 indicates TTY0-27 + 4 indicates TTY0-37 + 5 indicates TTY0-47 + 6 indicates TTY0-57 + 7 indicates TTY0-67 + 8 indicates TTY0-77 + + + NOTE + + DC10Cs, DC10Ds, and DC10Hs should be + treated as DC10Bs. Line numbers for + DC10Bs and DC10Es must be dense or + the message SPECIFICATION + ERROR-DSCTAB will be printed at the + terminal when an attempt is made to + assemble the monitor. + + +7 DC10E DATA SET CONTROL GROUPS (0-7): + + Respond with a value in the range 0 to 7. + + +8 CORRESPONDENCE OF DC10E LINES TO THE DC10B LINES (M-N,P) + GENERATE A MONITOR WITH MONGEN Page 8-19 ________ _ _______ ____ ______ + + + Respond with m,p for one pair and m-n,p for a + range of pairs (where m is an octal DC10E line, + m-n is the octal range of DC10E lines, and p is + the octal DC10B line). + + +9 # OCTAL LINES ON DC68, INCLUDING ITS CONSOLE TTY (1-144): + + Respond with the total number of lines available + under your system in the range 1 to 144. + + +10 WHICH DL10 PORT IS THE DC76 CONNECTED TO (0,1-7): + + Each PDP-10 is connected to a DL10 port. If there + is only one PDP-11, it is always connected to port + number 0. If there are two PDP-11s, one is + connected to port 0 and the other to port 1. + + +11 DECIMAL LINES ON DC76 (1-129): + + Respond with the number of lines (in decimal) on + the DC76. Each DC76F has 16 lines, and the + console terminal has one line. A DC76 with two + DC76Fs has 33 lines. + + +12 OPR OCTAL LINE # (CTY,0-n): + + Respond with the octal number of device OPR + (operator privileged terminal). The default is + CTY. + +Answer the following questions about your terminal lines (m-n). Type +one octal line number (m), one range (m-n), or CTY on separate lines. +Type an extra carriage return when you are finished. + + +13 DATA SET LINES + + Respond with the line numbers of those lines that + are data set lines. Data set lines are a class of + terminals recognized by LOGIN. LOGIN will reset + the lines to computer echoing and hardware tabs. + DC76 lines that require dataset control must be + defined as dataset lines. + + +14 LINES WITH HARDWARE TABS + + Respond with the line numbers of those terminals + with hardware generated tab settings. Most TTY + model 35s and 37s have hardware TABs, and most + model 33s do not. However, since the variety of + features found on model 33, 35, and 37 TTYs is so + great, every system administrator must determine + the physical characteristics of their installation + terminals. It is possible to override MONGEN TAB + settings with the SET TTY TAB and SET TTY NO TAB + commands. + + +15 REMOTE LINES + GENERATE A MONITOR WITH MONGEN Page 8-20 ________ _ _______ ____ ______ + + + Respond with the line number of those lines which + are to be considered remote. All data sets are + implicitly remote; however, the installation may + give REMOTE status to any terminal, even those + that are hardwired. In this context, remote is a + software characteristic of the terminal that + imposes certain restrictions. For example, some + project/programmer numbers may not be allowed to + LOGIN at remote terminals. (These terminals are + not to be confused with those terminals located at + a remote station.) + + +16 LOCAL COPY LINES + + Respond with the line numbers of those lines which + are to be considered local copy lines (full + duplex). With local copy lines, echoing is + provided by the terminal instead of by the + computer. + + +17 HALF DUPLEX LINES + + Respond with the line numbers of those lines that + transmit in half-duplex mode. Half-duplex lines + provide two-way, alternate, independent + transmission over the same pair of wires. + + + NOTE + + The term half-duplex is occasionally used + incorrectly. True half-duplex lines are + relatively rare. They include TWX data + sets and some local terminals connected by + DC10C interfaces. Some lines which are + loosely called half-duplex are actually + local copy full-duplex. Question number + 15 asks for the identification of local + copy lines. (If you are interested in + reading more about these terms, refer to + Section 8.3 of the specification entitled + SCNSER, Level D Scanner Service in the + DECsystem-10 System Notebooks.) + + +18 SLAVES + + Respond with the line numbers of those lines which + can be classified as slaves. Slave is a software + classification for terminals that cannot LOGIN or + control jobs. These terminals are generally used + to provide I/O for jobs that are controlled from + other terminals. A terminal can be classified as + a slave by any user, but it can be restored to + normal status only by the operator. + + +19 LINES WITH HARDWARE FORM FEED + + Respond with the line numbers of those terminals + which are to have hardware-generated form feeds. + Most model 35 TTYs have hardware-generated form + GENERATE A MONITOR WITH MONGEN Page 8-21 ________ _ _______ ____ ______ + + + feeds, and most model 33s do not. Since the + variety of features found in terminals is so + great, every system administrator must determine + the hardware characteristics of their installation + terminals. You may assume that no terminals have + hardware-generated form feeds, so that the scanner + service will always output five lines to simulate + form feeds. This can be changed by any user at a + terminal via the SET TTY FORM or SET TTY NO FORM + commands. + + +20 LINES WHICH RUN INITIA AT STARTUP + + Respond with the line numbers of those terminals + that are to run INITIA at start up. INITIA is a + program that performs job initialization + functions. When the monitor starts up, INITIA is + run automatically for those lines specified in + your response to this question. Device OPR should + be specified in your response; remote terminals, + dataset terminals, and remote station terminals + should not be specified to run INITIA. There is a + file read by INITIA, called TTY.INI, which + contains a complete set of parameters for setting + up the teletype configurations. The advantage of + having TTY.INI is that TTY parameters can be + changed without rerunning MONGEN. The INITIA + specification in the DECsystem-10 Software + Notebooks provides further details about TTY.INI. + + +21 FILLER CLASS CODES (M-N,P): + + Respond with the line numbers of those terminals + that require filler characters to standardize + output. P is the filler class code. (Refer to + the description of the SET TTY FILL command in the + DECsystem-10 Operating System Commands Manual for + an explanation of the filler class codes.) + + + +8.6 NETGEN ______ + +NETGEN is the MONGEN section which defines your system network +configuration. All possible questions are listed below and on +following pages. In order to start the NETGEN dialogue, you must +respond with NET to question number 1, which is described in Section +8.3.2. + + +2 OUTPUT (DSK:NETCNF.MAC): + + Respond with a carriage return if the file name + NETCNF.MAC and the device DSK: are acceptable to + store your NETGEN dialogue. If they are not + acceptable, respond with the desired file name, + device and/or project/ programmer number. + + +3 NETWORK SOFTWARE (Y,N): + + Answer Y or N. Y indicates that your installation + GENERATE A MONITOR WITH MONGEN Page 8-22 ________ _ _______ ____ ______ + + + desires the software for remote computers: + DECsystem-10s, PDP-11s, and PDP-15s. A response + of N indicates that the installation does not + desire network capabilities and, therefore, does + not require the associated software. The file + NETCNF.MAC will be closed; NETGEN is finished and + question number 1 will be typed again, allowing + you to configure FGEN. If you respond with Y, you + must also set the FTNET feature test switch to -1. + + +4 HOW MANY NODES DO YOU WISH TO SUPPORT (3,0-n) + + Respond with the number of nodes/stations you wish + to be supported by your system. If you respond + with 0, NETGEN dialogue will terminate and + question number 1 will be printed. + + +5 HOW MANY DC75NP'S OR DN-87'S ON SYSTEM (1,1-8) + + Respond with the number of synchronous front-ends + that are to be supported for networks on your + system. The default response is 1; the maximum + response is 8. + + +6 TO WHICH DL10 PORT IS THE DC75 or DN87 CONNECTED (0,0-8) + + This question is repeated once for each front-end + you specified in question 5. Respond with the + DL10 port number connected to this DC75/DAS85. + The default response is 0; the maximum response + is 8. + + +7 HOW MANY DN87S's ON THE SYSTEM (1, 0-3): + + Respond with the number of DN87S network + front-ends that are connected to DTE20s. + + +7A TO WHICH DTE20 IS THE DN87S CONNECTED (1, 1-3): + + This question is typed once for each DN87S + specified in response to question 7. + + +8 NODE NUMBER OF CENTRAL SITE (1-77) + + Respond with the node number to be associated with + the DECsystem-10 at the central site. + + +9 NAME OF CENTRAL SITE + + Respond with the name of the central site in six + characters or less. + + +10 # OF REMOTE TTYS (0,0-512) + + Respond with the maximum number of TTYs on network + nodes to be handled at any given moment. + GENERATE A MONITOR WITH MONGEN Page 8-23 ________ _ _______ ____ ______ + + +11 # OF REMOTE CDRS (0,0-n) + + Where n is the maximum response to question number + 4 above. Respond with the maximum number of card + readers on network nodes to be handled at any + given time. + +12 # OF REMOTE LPT'S (0,0-n) + + Respond with the maximum number of line printers + on network nodes to be handled at any given time. + + +13 # OF REMOTE PTR'S (0,0-0) + + +14 # OF REMOTE PTP'S (0,0-0) + + Respond with the maximum number of remote + paper-tape punches on network nodes to be handled + at one time. + + +15 # OF MTA'S (0,0-0) + + +17 # OF REMOTE PROCESSES (0,0-n) + + Respond with the maximum number of remote + processes that can be connected at any given time. + To answer this question with a value greater than + 1, you must set FTTSK to -1. + + +18 REMOTE DATA ENTRY SOFTWARE (Y,N): + + Answer Y or N. Y indicates that you want the + software to support remote data entry terminals, + which are used for MCS-10 applications. If you + respond with Y, FTRDX in FGEN must be set to -1. + + +19 # OF CONNECTS (46,1-512) + + Respond with the maximum number of simultaneous + connections. + + + +8.7 FGEN ____ + +The FGEN dialogue simplifies the task of choosing appropriate software +from a wide selection. For example, FGEN allows you to select the +standard DECsystem-10 features for a given application. + +If you are choosing all the standard software features, simply agree +during the dialogue to accept the standard symbol settings by typing a +carriage return. Your F.MAC file will then contain all these standard +settings; these, when assembled with the other GEN files, will +produce a monitor with the appropriate routines. + +Standard DECsystem-10 software features are included or deleted by +setting feature test switches to -1 or to 0: -1 places the feature in +the monitor, and 0 omits it. + GENERATE A MONITOR WITH MONGEN Page 8-24 ________ _ _______ ____ ______ + + +In order to set the appropriate feature test switches, you will need +the file FGEN.HLP. MONGEN will first look for FGEN.HLP on the +directory from which MONGEN came, then it will look for it on SYS:. +If FGEN.HLP cannot be found, the message %Can't find FGEN.HLP will be +printed on your terminal. + +FGEN allows you to: + + 1. List the standard settings for a given application + (TINY,KALUG,KILUG,KAFULL,KIFULL,KLFULL). + + 2. Determine what the feature test switch symbols mean. + + 3. Alter the feature test switch settings. + + 4. Add new feature test switches. + + + +2 OUTPUT (DSK:F.MAC): + + If you accept F.MAC and the device DSK: as the + media for storing your answers to MONGEN, press + the RETURN key for your response. If you do not + accept them, type your preferred disk name, file + name, and project/programmer number. + + +3 FEATURE SET(TINY,KALUG,KILUG,KAFULL,KIFULL,KLFULL): + + There are six standard feature settings; respond + with one of them. Only these standard settings + have been tested during monitor development and + are fully supported. Although installations may + alter the combination of individual feature test + switches or add new switches during FGEN, such + non-standard switch combinations have not been + tested and are not supported. We wish to + emphasize that you may alter the feature test + setting from the standard or LUG configurations; + however, the new combination is NOT supported by + DIGITAL. + + +4 STANDARD SETTING (YES,NO,LIST,EXPLAIN): + + Respond with one of the words within the + parentheses. + + YES Answer YES (the default) if you accept the DECsystem-10 + standard feature test switch settings, as identified in + the previous question. + + A YES ends FGEN and closes the F.MAC file. You may now + redefine another segment of MONGEN or exit from the + program. + + NO A NO allows you to change the setting of individual + switches or add new feature test switches. You can do + this by typing the switch symbol (e.g., FTxxx) and the + value (0 or -1) in the form + + switch, value + GENERATE A MONITOR WITH MONGEN Page 8-25 ________ _ _______ ____ ______ + + + Press the RETURN key twice after the last entry. + + LIST LIST allows you to examine the current setting for any + and all of the feature test switches. You may then + either accept or change the current setting. + + The standard setting for each feature test switch + varies with the installation's DECsystem-10 + application, e.g., TINY, KALUG, KILUG, KAFULL, KIFULL + or KLFULL. You can obtain the default value for an + individual feature test switch by typing LIST in + answer to the question, and then typing the requested + switch symbol followed by a carriage return. FGEN + returns that switch symbol and its current setting. To + obtain the value of another switch, type the requested + switch, followed by a carriage return. After the last + entry, press the RETURN key twice. + + To obtain the current values for all of the feature + test switches you can type LIST and then type ALL, + followed by a carriage return. FGEN will list all + feature test switch symbols and their values on your + terminal. + + EXPLAIN EXPLAIN allows you to examine the meaning of any or all + of the feature test switch symbols in addition to the + current value. You can obtain the default value and + meaning for a feature test switch symbol by responding + to EXPLAIN (or E) in the same way you could respond to + LIST (or L). For example, the dialogue (in prompt + mode) to obtain the default value and meaning for + feature test switches FTTIME and FTSLEE is as follows: + + STANDARD SETTING (YES, NO, LIST, EXPLAIN): EXPLAIN + + Only stand settings have been tested by DEC; all other + settings may produce incorrect operation. + + Switch (switch to list or explain). + + FTTIME + FTTIME, -1; + ;TIME ACCUMULATION + + FTSLEE + FTSLEE, -1; + ;SLEEP UUO + +After you have completed the dialogue sequence associated with NO, +LIST, or EXPLAIN, FGEN repeats the question: + + STANDARD SETTING (YES, NO, LIST, EXPLAIN): + +You should answer YES if all of the values are acceptable, NO if you +wish to change any settings, and LIST or EXPLAIN if you wish to obtain +any more default information. + +When you answer NO and change the switch settings that you wish to +change, you may have FGEN type each switch and ask for its final +setting. FGEN asks + + SET EACH SWITCH (Y,N): + +When you type YES, FGEN types + GENERATE A MONITOR WITH MONGEN Page 8-26 ________ _ _______ ____ ______ + + + FTxxxx,M (ON,OFF,LIST,EXPLAIN,END): + +for each switch, where M=-1 if the switch is on and M=0 if the switch +is off. You can then specify whether the switch should be ON or OFF, +or whether to enter LIST or EXPLAIN mode as before. By typing END, +you can specify that no more switches are to be listed and that the +current values are to be used. + + +5 DO YOU WANT THE VIRTUAL MEMORY FACILITY (YES,NO): + + This question will only be typed for KI10- or + KL10- based systems. Answer Y if you want virtual + memory capabilities and have VMSER (which is an + unbundled licensed product). + + + +8.8 PRODUCING RELOCATABLE BINARY FILES COMMON.REL, COMMOD.REL, AND COMDEV.REL _________ ___________ ______ _____ ___________ ___________ ___ __________ + + + +8.8.1 Assembling the Configuration Files __________ ___ _____________ _____ + +You should assemble the files HDWCNF.MAC, TTYCNF.MAC, NETCNF.MAC, +F.MAC, with S.MAC and COMMON.MAC to produce the relocatable binary +file COMMON.REL, the files HDWCNF.MAC and F.MAC with S.MAC and +COMMOD.MAC to produce COMMOD.REL, and the files HDWCNF.MAC, +TTYCNF.MAC, NETCNF.MAC, F.MAC, with S.MAC and COMDEV.MAC to produce +COMDEV.REL. + +To assemble a 6.03 Monitor type + + COMPIL F/COMP,S/COMP,HDWCNF+NETCNF+TTYCNF+ + +It is important that F.MAC precede S.MAC, because S has conditional +assemblies depending on the contents of F. Also, all of the remaining +files must follow S.MAC and precede COMMON.MAC. + + + +8.8.2 Assembly Error Messages from COMMON ________ _____ ________ ____ ______ + +One or more of the following messages are typed on your terminal if +your attempt to assemble COMMON is unsuccessful. + + 1. ?MORE THAN N. TTYS + PTYS EXCEED FIELD OF DDB.^1 + + The system capacity of 511 TTYs and PTYs has been exceeded. + You must rerun MONGEN, answering questions for fewer TTYs and + PTYs. + + 2. ?NOT ENOUGH PI'S TO SERVICE THIS CONFIGURATION SUGGEST + EDITING COMMON TO PUT MORE DEVICES ON A SINGLE CHANNEL. + + The system capacity of seven priority interrupt channels has + been exceeded. You should assign more devices to each PI + channel by editing INTTAB in the source of COMMON or by + changing the PI assignment of the special devices that have + been added. + +------------------ +1. Note that all error messages are preceded by a number. These +numbers are used for reference only; they are not printed by COMMON. + GENERATE A MONITOR WITH MONGEN Page 8-27 ________ _ _______ ____ ______ + + + 3. ?FT2REL MUST BE -1 WHEN 2 RELOC REGISTERS EXIST. + + 4. ?PLEASE ASSEMBLE SOURCES WITH FTRTTRP = -1. + + 5. ?PLEASE ASSEMBLE SOURCES WITH FTLOCK = -1. + + 6. ?PLEASE ASSEMBLE SOURCES WITH FTHPQ = -1. + + Messages 3 through 6 indicate that you specified incorrect + settings in F.MAC, i.e., you have asked for a feature to be + included with HDWGEN but you did not include the feature in + FGEN. You must rerun FGEN to correct the improper symbol + definitions. + + 7. ?SPECIFICATION ERROR - DSCTAB. + + There is a specification error in the data set control table. + You must correct it by running MONGEN again. Usually this + error occurs when line numbers are not dense on DC10Bs and + DC10Es. + + 8. %NUMBER OF JOBS REDUCED TO MAX=511. + + You specified more than 511 jobs. You should rerun MONGEN to + correct the error. + + 9. ?512 OR MORE PTY'S EXCEEDS FIELD OF DDB. + + You specified more than 512 PTYs. You should rerun MONGEN to + correct the error. + + 10. ?TRAP OFFSET SWITCH CANNOT BE SET ON A SINGLE PROCESSOR + SYSTEM. + + You incorrectly set the CPTOS switch. You must rerun MONGEN + and change the setting of the CPTOS switch to 0 if you have a + single processor system. (Refer to Section 8.15, Octal + Default Values.) + + 11. ?DL10 MAPPED AREA EXCEEDS 1K. + + You made the mapped area too large. You must reduce the size + of the mapped area, or change jumper in DL10 hardware to 8K + and add "DLX8K ==1" in REMCNF.MAC. + + 12. ? DL10 MAPPED AREA EXCEEDS 8K. + + The mapped area is still too large. You must reduce the size + of the mapped area following the procedures described in + message 11. + + 13. ? DLXLNG IS NOT EQUAL TO LENGTH OF MAPPED AREA. + + You have specified DLXNG to be either less than or greater + than the length of the mapped area. You must change it so + that it is equal to the length of the mapped area. (This is + an internal error and should not occur.) + + GENERATE A MONITOR WITH MONGEN Page 8-28 ________ _ _______ ____ ______ + + +8.9 DESCRIPTION OF THE CONFIGURATION FILES ___________ __ ___ _____________ _____ + +The following configuration files are produced by the MONGEN dialogue +program: + + 1. HDWCNF.MAC is produced by HDWGEN + + 2. TTYCNF.MAC is produced by TTYGEN + + 3. NETCNF.MAC is produced by NETGEN + + 4. F.MAC is produced by FGEN + +All four of these files contain the following information for each of +the questions asked: + + 1. The question asked by the program as a comment + + 2. Your response to the question as a comment + + 3. The MACRO definitions containing the switch or symbol and its + value. + +MONGEN always defines all the symbols that appear in the configuration +files, regardless of your answer to a question. Therefore, you do not +have to study the MONGEN program in order to understand what happens +on certain questions. It is sufficient that you only look at the +listings of the configuration files that are assembled with +COMMON.MAC. + + + +8.9.1 Description of COMMON.MAC ___________ __ __________ + +Since COMMON.MAC selectively assembles only those items needed for the +defined configuration, it contains the following items: + + 1. The default symbols that you can override during the MONGEN + dialogue. + + 2. Special lower core locations (below 400 in the monitor). + + 3. The monitor startup locations. + + 4. The EXEC page map for a KI10/KL10 processor. + + 5. The PDP-10/PDP-11 shared core area on systems with DC75s. + + 6. CPU data blocks (CDBs) for each processor. + + 7. Variable data locations for the monitor. + + 8. The job and high segment tables. + + 9. The terminal data base. + + 10. Monitor initialization code to link device data blocks and to + create multiple copies for all multiple devices, with the + exception of disk. + + 11. Special MACROs to define the PI assignment. These MACROs + create a two-word-per-entry table that contains the + following: + GENERATE A MONITOR WITH MONGEN Page 8-29 ________ _ _______ ____ ______ + + + a. Device Data Block address + + b. Number of devices + + c. Priority Interrupt channel for device + + d. Interrupt location for device + + e. Length of Device Data Block if multiple device + + 12. Locations set by ONCE-Only dialogue. + + 13. System error stop code (407 restart). + + 14. Common subroutine returns. + + 15. Subroutine to save and restore preserved accumulators. + + 16. Common byte pointers. + + 17. The PI channel save and restore routines. + + 18. Code to handle traps to 40 and 60 (primary CPU) and 140 and + 160 (secondary CPU) and the code to handle APR interrupt + entry and exit. + + 19. Remote communications entry points and tables. + + 20. Real-time trapping tables. + + 21. High priority queue UUO code. + + 22. Scheduler queue definitions and tables. + + + + +8.9.2 Description of COMMOD.MAC ___________ __ __________ + +You assemble COMMOD.MAC with HDWCNF.MAC, F.MAC and S.MAC to produce +COMMOD.REL. COMMOD selectively assembles the items required for the +defined configuration. It contains the following items: + + 1. The assembly instructions. + + 2. The default symbols that you can override during the MONGEN + dialogue. + + 3. The instructions for writing a new controller routine. + + 4. The symbol naming conventions. + + a. 3-letter prefixes + + b. 3-letter suffixes + + 5. The list of upper and lower limits for various disk + parameters. + + 6. The data structure description. + + 7. The core and disk block symbol definitions for the file + system. + GENERATE A MONITOR WITH MONGEN Page 8-30 ________ _ _______ ____ ______ + + + a. Generalized core blocks + + b. Access table + + c. BAT blocks + + d. Channel Data Blocks + + e. Device Data Blocks + + f. Home blocks + + g. Monitor job tables + + h. Controller Data Blocks + + i. Logical block numbers within unit + + j. Monitor buffer + + k. Name block + + l. Project-Programmer number block + + m. RIB blocks + + n. SAT blocks + + o. File structure data block + + p. System variables + + q. UFD blocks + + r. Unit data blocks + + + + +8.9.3 Description of COMDEV.MAC ___________ __ __________ + +COMDEV.MAC contains symbols, code, and data bases associated with +devices (in the following order). The items are listed below. + + 1. Conversion symbols from the old MONGEN format (XXXXXn) to the + new (M.XXXX). + + 2. Terminal (TTY) and remote station conversion symbols. + + 3. MONGEN default symbols. + + 4. Terminal (TTY) data base. + + 5. Remote station data base. + + 6. All other device-specific code and data bases. + + 7. EXTERNS used to load the proper device routines from the + monitor library. + + GENERATE A MONITOR WITH MONGEN Page 8-31 ________ _ _______ ____ ______ + + +8.10 HDWGEN EXAMPLE ______ _______ + +.R MONGEN + +MONGEN for 603 monitors + +/HELP(PROMPT,SHORT,LONG)]: LONG + +Which GEN(HDW,TTY,NET,F)[ +HDW to define hardware configuration +TTY to define terminal configuration +NET to define network configuration +F to define software features]: HDW + +Output(DSK:HDWCNF.MAC): + +DECsystem10(1040,1050,1055,1070,1077,1080,1088)[ +1040 is small disk system with KA10 cpu +1050 is large disk system with KA10 cpu +1055 is disk system with 2 KA10 cpu's +1070 is disk system with KI10 cpu +1077 is disk system with 2 KI10 cpu's +1080 is disk system with KL10 cpu +1088 is disk system with 2 KL10 cpu's]: 1080 + +System name[24 characters or less]: TESTER603 + +CPU0 serial #(1-10000): 3333 + +Exclude Monitor overhead from user run time(Y,N)[ +Overhead is CPU time spent clock queue processing, command +decoding, core shuffling, swapping, and scheduling. +User run time always includes UUO execution and +unless EBOX/MBOX runtime accounting is selected +(KL10 systems only) includes IO interrupt service time. +On KA or KI systems, each CPU must have a DK10]: Y + +EBOX/MBOX runtime accounting?(y,n)[ +If EBOX/MBOX runtime accounting is selected in a KL10 +based system, user runtime is computed using the KL10 +internal accounting clocks]: Y + +Exclude PI time from user runtime?(y,n)[ +An answer of "yes" to this question will cause the monitor +to set up the KL10 accounting meters in such a manner that +users will not be charged for cpu time used during interrupts]: Y + +# Data Channels(2,1-8)[DF10s, DF10Cs, DX10s OR RH20'S for disk and tape]: 2 + +Channel 0 Type (DF10,DF10C,DX10,RH20): RH20 + +On channel # 0: + + # RH20S for RP04'S, RP06'S(0-1)[Controllers for RP04, RP06 disk pack +units on channel 0]: 1 + # Units on RPA(1-8): 2 + # RH20's for TM02'S (0-1)[Mass-Bus tape controller for +TU16's and TU45's on channel 0]: 1 + How many TM02's on RH20 # 0 (1-8)[EACH UNIT CAN CONTROL +UP TO 8 SUB-UNITS = TAPE DRIVES]: 2 +How many drives on TM02 0 (1-8): 2 +How many drives on TM02 1 (1-8):2 + +Channel 1 Type (DF10,DF10C,DX10,RH20): DX10 + GENERATE A MONITOR WITH MONGEN Page 8-32 ________ _ _______ ____ ______ + + + +On channel # 1: + # Controllers(0-1)[TX01's or TX02's for TU70 Tape Drives on channel 1]: 1 + # Units on MTB(1-8): 2 +TM10As(0,0-2)[I/O Bus type Controller for NRZI only drives]: 0 + +Specify which drives (M-N) are 7 track drives. +[Type one number (M) or one range(M-N) or ALL on separate lines. +Type an extra carriage return when through.] +For controller MTA + +For controller MTB + + +Specify which tape drives (M-N) are capable of 6250 BPI densities. +[Type one number (M) or one range (M-N) or ALL on separate lines. +Type an extra carriage return when through.] +For controller MTA + +For controller MTB + + +# DTEs on CPU0(2,1-4)[BYTE TRANSFER DEVICE USED FOR KL10 to PDP-11 front end communications]: 2 + +# Jobs(1-511)[Maximum number attached and detached, not +counting null job]: 80 + +Max. PAGES of core For each job(0,0-512)[0 means all of core]: 256 + +# K total system core(32-4096)[ONCE-only reports if +less core at startup]: 1056 + +Clock ticks per second(60,50)[Power line frequency]: 60 + +# Real-time devices(0,0-77)[Max. # which can be put +on PI channels simultaneously]: 0 + +Allow jobs to be locked in core(Y,N): Y + +# PAGES min guaranteed among jobs not locked in core(0,0-512)[ +minimum free core pool for unlocked jobs, 0 assumes all of core]: 256 + +# High priority queues(0,0-15): 2 + +CCL commands to stay in core(Y,N)[System programs pass +commands to each other via core(TMPCOR UUO) rather than disk]: Y + +Meter(Y,N)[Performance analysis metering(METER UUO)]: Y + +SYSCHK(Y,N)[Initial Hardware integrity check at ONCE-only time]: N(cr> + +MSGSER(Y,N)[Support for device MPX. (more than one device +on an I/O channel). This feature is required for TYPSET-10 +and MCS-10]: Y + +PSISER(Y,N)[Advanced programmed software interrupt service - +Support for the PISYS. UUO. This provides an easy +and powerful interrupt method for program to trap asynchronous +events. Required bY MCS-10]: Y + +IPCF(Y,N)[Inter process communition facility]; Y + +ENQ/DEQ(Y,N)[Sychronization Primitives To-allow +simultaneous file update by multiple co-operating processes]: Y + GENERATE A MONITOR WITH MONGEN Page 8-33 ________ _ _______ ____ ______ + + + +# CDRs(1,0-2)[Card reader]: 0 + +CDP(Y,N)[Card punch]: N + +CP10D(Y,N)[Special Systems unbuffered Card Punch]: N + +DIS(Y,N)[Display device(VP10,340,30,VB10C) as distinguished from +display terminals]: N + +# TD10s(1,0-2)[DECtape controls]: 2 + + # Units on DTA(1-8): 4 + + # Units on DTB(1-8): 2 + +LPTs(1,0-3)[Line printers]: 3 + +LPT0 Lower case(Y,N)[Does LPT0 have lower case capability]: Y + +LPT1 Lower case(Y,N)[Does LPT1 have lower case capability]: Y + +LPT2 Lower case(Y,N)[Does LPT2 have lower case capability]: N + +PLTS(0,0-2)[Plotters]: 0 + +PTP(Y,N)[Paper tape punch]: Y + +PTR(Y,N)[Paper tape reader]: Y + +# PTYs(20,0-510)[Pseudo-terminals - each operator +service program and Batch stream needs one]: 20 + +DC44(Y,N)[ +The DC44 is a TYPESET-10 front end which supports +the following devices: +PA611R High speed paper tape reader +PA611P High speed paper tape punch +LPC11 Online photocomposition machine]: N + +# of DA28s(0,0-4)[Interprocessor channels for PDP8/11/15]: 0 + +# DAS78'S(0,0-8)[IBM 360, 370, and/or 2780 support]: 0 + +Decimal "symbol,value"[ +For any symbols to be defined. +Type one per line, extra carriage return when through] + + + +Octal "symbol,value"[ +For any symbol to be defined. +Type one per line, extra carriage return when through] + + + +SIXBIT "symbol,value"[ +For any sixbit symbol to be defined. +Type one per line, extra carriage return when through] + + +Type "device-mnemonic,PI-channel" for special devices[ +With neither channel AC save routine nor device data block, +the "device-mnemonic" must be 3 characters or less. + GENERATE A MONITOR WITH MONGEN Page 8-34 ________ _ _______ ____ ______ + + +Type extra carriage return when through.] + + +Type "device-mnemonic,PI-channel,no.-of-devices"[ +For special devices with device data blocks. +the "device-mnemonic" must be 3 characters or less. +Type extra carriage return when through.] + + +Type "device-mnemonic,PI-channel,highest-ac-to-save"[ +For special devices with channel save routines to save acs up to +the "highest-ac-to-save". "Device" must be 3 char or less. +Type extra carriage return when through.] + + +File DSK:HDWCNF.MAC Closed [HDWGEN finished] + GENERATE A MONITOR WITH MONGEN Page 8-35 ________ _ _______ ____ ______ + + +8.11 TTYGEN EXAMPLE ______ _______ + +Which GEN(HDW,TTY,NET,F)[ +HDW to define hardware configuration +TTY to define terminal configuration +NET to define network configuration +F to define software features]: TTY + +Output(DSK:TTYCNF.MAC): + +How many DC10s(1,0-2)[ +The DC10 is a data line scanner]: 1 + +How many DC68s(1,0-2)[ +The DC68 is a PDP-8 680 or 680I communications system]: 1 + +How many DC76s(1,0-8)[ +The DC76 is a PDP-11 communications system]: 0 + +For DC10 0: + +# DC10B[ or 632] 8 line data groups(1-8)[ +1 is TTY0-7, 2 is TTY0 - 17, ... 8 is TTY0 - 77]: 2 + +# DC10E Data set control groups(0-2): 2 + +Correspondence of DC10E lines to the DC10B lines(M-N,P)[ +Type M,P for one pair and M-N,P for a range of pairs +where M is octal DC10E line, M-N is octal range of DC10E +lines, and P is octal DC10B line] + + + +FOR DC68 0: + +# Octal lines on DC68, including its console TTY(1-144): 20 + +OPR octal line #(CTY,0-37)[OPR is privileged operator terminal]: +Answer the following questions about your TTY lines(M-N). +[Type one octal line #(M) or one range(M-N) or CTY on separate +lines. Type extra carriage return when through.] + + +Data set lines[Class of terminal for LOGIN, LOGIN resets line +to computer echoing and no hardware tabs] + + +Lines with hardware tabs[Monitor simulates rest with spaces] + + +Remote lines[Class of terminal for LOGIN, do not confuse +with remote station TTYs] +3-7 + + +Local copy lines[Echoing provided by terminal rather than +by computer. Often (incorrectly) called half duplex] +10-12 + + +Half duplex lines[TWX or half duplex wired scanner(DC10C)] + + +Slaves[No commands may be typed] + GENERATE A MONITOR WITH MONGEN Page 8-36 ________ _ _______ ____ ______ + + + + +Lines with hardware form feed[Leave out if users +would rather not get form feeds until they do TTY FORM commands] + + +Lines which run INITIA at startup +0-16 + + +Filler class codes(M-N,P)[ +Type M,P for one line M with filler class code P or +M-N,P for a range of lines with filler class code P] + + +2741 lines on DC-10 interfaces[] + + +File DSK:TTYCNF.MAC Closed [TTYGEN finished] + + + +8.12 NETGEN EXAMPLE ______ _______ + +Which GEN(HDW,TTY,NET,F)[ +HDW to define hardware configuration +TTY to define terminal configuration +NET to define network configuration +F to define software features]: NET + +Output(DSK: NETCNF.MAC): + +Network software(Y,N)[ +Software to support remote computers: DECsystem-10's, +PDP-11's, PDP-8's (requires FTNET to be -1)]: Y + +How many nodes do you wish to support(3,0-63)[Maximum]: 3 + +How many DC75NP's or DN87's on the system(1,0-8)[Network +front-ends connected to DL10's.]: 1 + +For front end number 1: + +To which DL10 port is the DC75 or DN87 connected (0,0-7)[]: +How many DN87S's on the system(1,0-3)[Network +front-ends connected to DTE-20's]: 0 + +Node number of central site(1-77)[ +Unique number identifying DECsystem-10 to network.]: 1 + +Name of central site[Six characters or less.]: CENTRAL +%More than 6 characters. +Name of central site[Six characters or less.]: CENTER + +# of remote TTY's(0,0-512)[ +Maximum number of teletypes on network nodes to be +handled at any given time.]: 12 + +# of remote CDR's(0,0-63)[ +Maximum number of card readers on network nodes to be +handled at any given time.]: 0 + +# of remote LPT's(0,0-63)[ +Maximum number of line printers on network nodes to be + GENERATE A MONITOR WITH MONGEN Page 8-37 ________ _ _______ ____ ______ + + +handled at any given time.]: 22 + +# of remote PTR's(0,0-0)[ +Maximum number of paper tape readers on network nodes to be +handled at any given time.]: 0 + +# of remote PTP's(0,0-63)[ +Maximum number of paper tape punches on network nodes to be +handled at any given time.]: 0 +# of remote MTA's(0,0-0)[ +Maximum number of magnetic tape drives on network nodes to be +handled at any given time.]: 0 + +# of remote processes(0,0-128)[ +Maximum number of remote processes that can be connected to at +any given time (requires FTTSK to be -1).]: 12 + +Remote data entry software(Y,N)[ +Software to support remote data entry terminals for MCS-10 applications +(requires FTRDX to be -1)]: Y + +# of connects(46,1-512)[ +Maximum number of simultaneous connections.]: 46 + +File DSK:NETCNF.MAC Closed [NETGEN finished] + + + +8.13 FGEN EXAMPLE ____ _______ + +Which GEN(HDW,TTY,NET,F)[ +HDW to define hardware configuration +TTY to define terminal configuration +NET to define network configuration +F to define software features]: F + +Output(DSK: F.MAC): + +Feature set(TINY,KALUG,KILUG,KAFULL,KIFULL,KLFULL)[ +TINY Is minimum subset of features for KA10 timesharing +KALUG Is medium size KA10 monitor with enough features for batch +KILUG Same as KALUG but for KI10 cpu +KAFULL Includes all features of DECsystem10 monitor such + as real-time and extended file system for KA10 cpu +KIFULL Same as KAFUL but for KI10 cpu +KLFULL Same as KIFULL but for KL10 cpu]: KLFULL + +Standard setting(YES,NO,LIST,EXPLAIN)[ +Standard values for all feature test switches for your configuration]: YES + +Do you want the virtual memory facility(YES,NO)[VMSER must +be on your distribution tape]: YES + +File DSK:F.MAC Closed [FGEN finished] +Which GEN(HDW,TTY,NET,F)[ +HDW to define hardware configuration +TTY to define terminal configuration +NET to define network configuration +F to define software features]: + +. + GENERATE A MONITOR WITH MONGEN Page 8-38 ________ _ _______ ____ ______ + + +8.14 DECIMAL DEFAULT VALUES _______ _______ ______ + +This section contains a description of the standard symbols and +default decimal values assumed by the MONGEN program. Section 8.14.1 +lists those symbols defined in COMMON; Section 8.14.2 lists those +symbols defined in COMDEV; and Section 8.14.3 lists those symbols +defined in COMCON. All symbols are listed in the order in which they +are defined. + + + +8.14.1 Symbols Defined in COMMON _______ _______ __ ______ + +NSPMEM, 1000 + + The number of nanoseconds per memory cycle. This symbol is used + to compute the amount of time spent performing core shuffling, + and it is printed by the SYSTAT command. For systems with MB10 + memories, the constant should be changed to 1760. + +EPL4WD, 17 + + The number of 4-word blocks in the extended executive push-down + list. When extended it is one-fourth the length of the maximum + executive push-down list. If a push-down list overflow occurs, + this value should be increased. + +MONCOR, JOBN*72+EPLLEN (Large Disk Systems) + + The monitor reserves a table of at least MINCOR words, or + possibly up to the next 1K boundary, for allocating disk device + data blocks and extended push-down lists. MONCOR is normally + JOBN*90 words, allowing 2.5 open disk files per job. If this + value is too small, a larger value may be supplied. The total + size of the monitor is printed after this space is reserved in + the long ONCE-Only dialogue. + +MINCOR, JOBN*55 (Small Disk Systems) + + For a small disk system, there are only 1.5 open disk files per + job. Otherwise, the explanation is the same as for large disk + systems above. + +CTYDCR, 18 + + The delay for CTY carriage return during ONCE-Only dialogue. The + default causes an 18-jiffy delay. This allows the monitor to + pause before printing on the next line, allowing the CTY to + execute a carriage return/line feed. + +RLDTIM, 112 + + The time until an auto-reload. + +MINMAX, 1024*12 + + The smallest value allowed for CORMAX after the system begins + execution. + +UNIQ1,1 UNIQ2,1 and UNIQ12 ... UNIQ6,1 ... UNIQ16 + + These represent priority interrupt channels for the exclusive use + of a special device. If the priority interrupt channels are to + be reserved, set the value of UNIQn to 1, where n is the channel + GENERATE A MONITOR WITH MONGEN Page 8-39 ________ _ _______ ____ ______ + + + number. For example, if a real-time device requires extremely + fast response time, it is necessary to set the BLKI/BLKO pointer + in the channel location. (Channel 7 cannot be reserved, as it is + always used for the clock.) + +INDPPN,0 + + If the value of INDPPN is 0, each programmer number refers to the + same person in every project. If the value of INDPPN is 77777, + programmer numbers may be assigned independently within each + project. This affects only the disk file access protection + mechanism. + +M.QSTR,0 + + The default structure for the QUEUES. + +SYSSEG,-1 + + This function checks files for a flag indicating they are SYS + files. This function also prevents dormant or idle segments from + sitting in core, in addition to achieving fast GETSEGs from SYS:. + +CPTOS,0 + + CPTOS = 0 sets the trap offset for dual processor systems. CPU0 + normally traps to location 40, and CPU1 normally traps to + location 140. CPTOS = 0 traps CPU1 to location 40 and CPU0 to + location 140. The value of CPTOS must be set to 0 for + single-processor systems. (KA10 only.) + +UFCO, 10 + + Monitor call fairness count for CPU0 in a multi-processor system. + +UFC1, 10 + + Monitor call fairness count for CPU1 in a multi-processor system. + (CPU1 picks UFC1 jobs that have just completed monitor calls on + CPU0 before picking a job on CPU1.) + +M.CBAT, 10 + + The maximum number of bad memory addresses stored in each CPU + data block on a memory parity error sweep of core. + +STDENS,5 + + The standard magtape density, if the user program does not + override the symbol value with an INIT, OPEN, or SETSTS monitor + call or with the SET DENSITY command. The standard is 6250 bpi + for TU70s. + + 1 = odd parity + 200 bpi + 2 = odd parity + 556 bpi + 3 = odd parity + 800 bpi + 4 = odd parity + 1600 bpi + 5 = odd parity + 6250 bpi + +M.BMAX, 13 + + The initial setting for the maximum number of MPB jobs permitted + to log-in simultaneously. This value initializes the monitor + GETTAB word BATMAX. The operator can change this value during + GENERATE A MONITOR WITH MONGEN Page 8-40 ________ _ _______ ____ ______ + + + system operation with the OPSER command: SET BATMAX. + +M.BMIN, 0 + + The initial setting for the minimum number of jobs guaranteed for + MPB. This value initializes the monitor GETTAB word BATMIN. The + operator can change this value during system operation with the + OPSER command :SET BATMIN. + +JIFSEC.60 + + The number of clock ticks per second, i.e., jiffies. + +DDTRY,4 + + The number of times the monitor is to try to recover from DECtape + errors. + +M.EXE, 1 + + The symbol which determines the type of file to be created on the + execution of the SAVE command. If M.EXE = 0, normal (i.e., SAV, + HGH, LOW, SHR) files are created; if = 1, .EXE files are + created. + +TXTRA,0 + + The number of extra terminal disk data blocks for slave lines. + +LOGSIZE,12 + + The minimum amount of virtual core required for a user to be + logged-in. This value must be at least as large as the LOGIN + system program, which is currently 12K. If the amount of core is + insufficient, the user will receive a CORE UNAVAILABLE error + message, which includes the virtual amount of core remaining. + +M.JMAX, M.JOB + + The initial setting for the maximum number of jobs permitted to + LOGIN simultaneously. (This includes all classes of jobs: + batch, interactive, or operator service jobs. Note that operator + service jobs, subjobs under [1,2], or subjobs at OPR or CTY are + not restricted from logging-in even if LOGMAX is exceeded, + because the task may be a critical system function.) + + This value, which cannot be less than 1, initializes the monitor + GETTAB word LOGMAX. The operator can change this value during + system operation with the OPSER command :SET LOGMAX. + +M.CMCT, 32 + + The number of times the core tables (CHKTAL) are to be checked + before performing its defined functions, which requires + approximately 5 ms of overhead. This reduces CPU time for CORE, + GETSEG, and RUN monitor calls. The maximum value to which this + symbol may be set is 262,000. + +M.XFFA, 0 + + If M.XFFA is non-zero, the File Daemon will not be called if the + program accessing the file is being run under [1,2] or has the + JACCT bit set. + GENERATE A MONITOR WITH MONGEN Page 8-41 ________ _ _______ ____ ______ + + +8.14.2 Symbols Defined in COMDEV _______ _______ __ ______ + +MTSIZ, 128 + + The size of magnetic tape records in 36-bit words (i.e., data + words in the buffer). Users can override this value by using the + SET BLOCK SIZE MTAn: command. Programs can override this value + by building special buffers. + +LPTSIZ, 29 + + The size of the line printer buffer + 2. The value of 29 allows + a full line to be typed on a 132-column line printer in one + buffer. This value should be changed to 26 when using 120-column + line printers. + +FLCDEF, 1 + + The filler class code to use if one is not specified for a TTY + line. + +MTELOG, -1 + + If = -1, errors that require more than one retry are logged. If + = 0, all recoverable errors are logged. + +MTDAEM, 10 + + The number of times per reel to call DAEMON for magtape error + reporting. + + + +8.14.3 Symbols Defined in COMMOD _______ _______ __ ______ + +STRMAX, 14 + + The maximum number of disk file structures that can be on line + simultaneously. By decreasing this value, one word will be saved + for each decrement of 1. This value is automatically set to 1 + for 1040 systems; the value cannot exceed 14. + +CCWMAX,10 + + The maximum length in words of each disk channel command list. + Altering this value will affect efficiency and space. The value + is set to 10 for 1040 systems. CCWMAX is not used for KI10 and + KL10 systems. + +SWPMAX,8 + + The maximum number of disk units that may be used for swapping (1 + word per unit). The value is set to 1 for 1040 systems. + +SWCLSN,7 + + The highest class number for swapping; this value cannot exceed + 7. + +DSKTRY,10 + + The number of times to try on disk data errors for all file + structures before recalibrating (inclusive of the initial try). + GENERATE A MONITOR WITH MONGEN Page 8-42 ________ _ _______ ____ ______ + + +SERTRY,3 + + The number of times to try on search errors before recalibrating + (inclusive of the initial try). + +RCLTRY,10 + + The number of times to recalibrate and try on DSKTRY disk data + errors or on SERTRY search errors (inclusive of the initial try). + The total number of disk tries with recalibration is equal to + DSKTRY * RCLTRY (i.e., 10 * 10 = 100). The total number of + search tries with recalibration is equal to SERTRY *RCLTRY (i.e., + 10 * 3 = 30). + +CHVIFP,10 + + The standard initial fairness count for positioning. The monitor + chooses the nearest request for positioning (CHVFP times -1) + before taking the longest waiting request. + +CHVIFT,10 + + The standard initial fairness count for transfers. The monitor + chooses the shortest latency for a transfer (CHVIFT times -1) + before taking the longest waiting request. + +PTRLEN,6 + + The number of in-core retrieval pointers per file length; this + offsets the size of the device data block. + +FIL4WD,9 + + The number of 8-word blocks allocated per job in a common pool of + monitor free core. The value of FIL4WD should be increased if + the ENTER monitor call's error code 16 is received regularly. To + assign this space the ONCE-Only code multiplies this factor by + the number of jobs. These blocks are used by the Level-D Disk + Service for active, dormant, ACC, NMB, PPB, and UFB blocks. This + pool is permanently reserved for these blocks and is not used for + any other purpose. Another pool is used for variable length core + blocks, such as disk service data blocks and extended exec + push-down lists. The system sets the minimum number of 4-word + core blocks to 50 with 5 or fewer jobs. The value is set to 5 + for 1040 systems. + +UNVRSF,500 + + The reciprocal factor of the total disk size. The amount of disk + space is subtracted from the number of free blocks when the + monitor is started up. This area is not available for users' + data. It is a safety factor that ensures there is room to write + the second RIB, etc. The standard reserved for this purpose is + one five-hundredth of the disk space. + +MBFN,2 + + The number of 128-word monitor buffers used for the reading and + writing of non-user data. This value must be at least 2. The + default for MBFN is the number of jobs divided by ten, plus one. + For example, the default for a 50 job system is 6. + +LBNHOM,1 LB2HOM,10 + GENERATE A MONITOR WITH MONGEN Page 8-43 ________ _ _______ ____ ______ + + + The standard logical block number on each unit that contains the + HOME block. Note that it is also possible to change this value + for a specific disk unit as follows: + + xxxnHM,LBNHOM + xxxnH2,LB2HOM + + Where:xxxn is the unit designation, e.g., DPA0HM, 3. + +MFDSIZ,8 + + The number of blocks allocated to the MFD by the refresher in + each file structure. The MFD can be longer than this but there + is a speed advantage to consecutive blocks. Increase this value + if the MFD is normally longer than 8 blocks. + +LIMLVL,0 + + The maximum number of nested SFDs for this monitor. The maximum + value for LIMLVL is 5. + +MAXUSI,8 + + The maximum negative USETI for reading an extended RIB. + + + +8.15 OCTAL DEFAULT VALUES _____ _______ ______ + +This section contains a description of the standard symbols and +default octal values assumed by the MONGEN program. Section 8.15.1 +lists those symbols defined in COMMON; and Section 8.15.2 lists those +symbols defined in COMMOD. All symbols are listed in the order in +which they are defined. + + + +8.15.1 Symbols Defined in COMMON _______ _______ __ ______ + +A00CVN, 0 + + The customer version number. + +A00MVN, 603 + + The major version number. + +XPANDN,0 + + The value affects the listing of COMMON. If it is non-zero, + COMMON MACRO expansions are listed. + +APRSN,0 + + The serial number of the arithmetic processor. + +DEFDEB,0 + + Defines the stop code conditions under which the monitor is + automatically reloaded. The default value of 0 indicates that + the monitor is reloaded with the STOP category of stop codes. A + value of 100000000000 indicates that the monitor is reloaded with + JOB stop codes; a value of 200000000000 indicates that the + monitor is reloaded with DEBUG stop codes; and a value of + GENERATE A MONITOR WITH MONGEN Page 8-44 ________ _ _______ ____ ______ + + + 300000000000 indicates that the monitor is reloaded on all types + of stop codes. If the value is 400000000000, auto-reload is + disabled. If the value is 200000000000, the system stops if the + CPU halts. (Refer to the specification STOPCD.RNO.) + +M.WCH, JW.WMT + + The WATCH bits used to set the initial WATCHing. Because LOGIN + sets JBTWCH, this is useful only for lines that do not need + LOGIN, that is those using INITIA. + + bit 19 = 200000 = Time of day started to wait + bit 20 = 100000 = RUN time + bit 21 = 40000 = WAIT time + bit 22 = 20000 = Blocks read + bit 23 = 10000 = Blocks written + bit 24 = 4000 = Version numbers + bit 25 = 2000 = MTA statistics + + + +8.15.2 Symbols Defined in COMMOD _______ _______ __ ______ + +PRVFIL,057 + + The standard file protection code. + +PRVUFD,775 + + The standard User File Directory (UFD) protection code. + +SYRDPR,355000 + + This value is set by the refresher and it indicates + non-privileged files on SYS: (HOME.SYS, SAT.SYS). + +SYNRPR,357000 + + SYNRPR = 357000 indicates that privileged files are on SYS: + (CRASH.EXE, SNAP.SYS, RECOV.SYS, BADBLK.SYS, SWAP.SYS). Used by + the refresher. + +MFDPRV,555000 + + The standard Master File Directory (MFD) protection code. All + users can READ, LOOKUP, but not CREATE files. Set by the + refresher. + +SYSPRV,775000 + + The SYS User File Directory (UFD) protection code; the + project-programmer number is 1,4. Project 1 members can READ, + CREATE, LOOKUP files; others can READ and LOOKUP only. Set by + the refresher. + +BLKMAX,100000 + + The maximum number of blocks that can be transferred in one disk + file operation (IOWD). This default value is so high that the + effective limit is one cylinder boundary. + +PRVSPL,077 + + The default protection code for spooled files. + GENERATE A MONITOR WITH MONGEN Page 8-45 ________ _ _______ ____ ______ + + +PRVSYS,155 + + The default protection code for most files on SYS: (except files + with the .SYS extension). + +PRYSYS,157 + + The default protection code for .SYS file on SYS:. + + + + +8.15.3 Symbols Defined in COMDEV _______ _______ __ ______ + +MTDLPT,1 + + Standard magtape labels are ASCII. + + + +8.16 SIXBIT DEFAULT VALUES ______ _______ ______ + +The following list is a description of the standard symbols and +default SIXBIT values assumed by the MONGEN program. (Refer to the +description of the DESTROY startup option in the HDWGEN section.) + +M.QSTR,0 + + Force queues to be placed on a specific STR. + +M.SF00,DSKA + The name of the first file structure to contain fixed head disk + units (e.g., FHA, FHB, etc.) when the DESTROY startup option is + invoked. The value (DSKA) may be any 1- to 4-character + alphanumeric name beginning with a letter. The number of fixed + head units in the structure is set by the associated decimal + symbol M.ZF00. Note that the DEC-distributed software sets the + name of the first file structure, which contains all fixed head + units, to DSKA. + +M.SFxx,aaaa + The name of the second through sixteenth structure containing + fixed head disk units (where xx =01....15, and aaaa is any + 4-character alphanumeric name beginning with a letter). The + number of fixed head units in the structure is set by the + associated decimal symbol M.ZFxx. Note that the DEC-distributed + software does not define these symbols, because it assumes that + all fixed head units are incorporated into one structure, called + DSKA. + +M.SD00,DSKB + The name of the first file structure to contain disk pack units + (e.g., DPA, DPB, etc.) when the DESTROY startup option is invoked + by the operator. The value (DSKB) may be any 1- to 4-character + alphanumeric name beginning with a letter. The number of disk + pack units is set by the decimal symbol M.ZD00. Note that the + DEC-distributed software sets the name of the first file + structure, which contains all disk packs, to DSKB. + +M.SDxx,aaaa + The name of the second through sixteenth structure containing + disk pack units (where xx =01....15, and aaaa is any 4-character + alphanumeric name beginning with a letter). The number of disk + pack units in the structure is set by the associated decimal + GENERATE A MONITOR WITH MONGEN Page 8-46 ________ _ _______ ____ ______ + + + symbol M.ZFxx. Note that the DEC-distributed software does not + define these symbols because it assumes that all disk packs are + incorporated into one file structure called DSKB. + +M.SSxx,aaaa + + The name of the first file structure to contain RH10s/RS04s when + the DESTROY startup option is invoked by the operator. The + number of fixed head units in the structure is set by the + associated decimal symbol M.ZS00. + +M.SRxx,aaaa + + The name of the first file structure to contain RH10s/RP04s when + the DESTROY startup option is invoked by the operator. The + number of fixed head units in the structure is set by the + associated decimal symbol M.ZR00. + + + +8.17 NON-STANDARD DEVICE PI ASSIGNMENT ____________ ______ __ __________ + +Under ordinary circumstances when COMMON is assembled, devices are +assigned to PI channels according to their group priority. (Refer to +Table 8-1.) If you have at your installation a device not listed as a +standard device in Table 9-1 and you have written your own Monitor +Device Service Routine, you must specify the device mnemonic (in 3 +characters or less) and designate an appropriate priority interrupt +channel. You must answer all three questions as they apply to your +configuration. The first question + + TYPE "DEVICE-MNEMONIC,PI-CHANNEL" FOR SPECIAL DEVICES + +requests special device service routines that do not need either a +Channel Save Routine or a Device Data Block. The second question + + TYPE "DEVICE-MNEMONIC,PI-CHANNEL, NO.-OF-DEVICES" + +requests devices with special service routines that have a Device Data +Block but no Channel Save Routine. The third question + + TYPE "DEVICE-MNEMONIC,PI-CHANNEL, HIGHEST-AC-TO-SAVE" + +requests devices with special service routines that have a Channel +Save Routine, but no Device Data Block. + +Special devices that you added during the HDWGEN dialogue are chained +to the requested channel. To give a device the exclusive use of a +channel, you respond to the "symbol,value" question with + + UNIQn,1 + +where n is the priority interrupt channel to be reserved. (Refer to +the UNIQn,1 entry in Section 8.14.1.) + +One or more priority interrupt channels may be reserved for real-time +devices with the RTTRP monitor call. These devices are completely +controlled by user programs and have no specific code loaded with the +monitor. To reserve a priority interrupt channel for use with RTTRP, +you should respond to the "symbol,value" question with + + RTCHn,1 + +where n is the priority interrupt channel to be reserved. + GENERATE A MONITOR WITH MONGEN Page 8-47 ________ _ _______ ____ ______ + + +(Refer to the RTCHn,1 entry in Section 8.14.1 and to the DECsystem-10 +Monitor Calls manual.) + +I/O devices are grouped by their relative interrupt speeds. If any +device of a particular group is present, a PI channel is assigned to +that device according to its group priority. Group priorities for +standard devices may be revised by rearranging the devices in INTTAB, +which is in the COMMON source file. + + + Table 8-1 + Device Groups for PI Channel Assignment + + + Device Mnemonic Group Name + + + DCB A 136 data control for 270 disk + + MTA B TM10n magtape data channel + MTB + + DCT C 136 data control for 551 or 516 tape + controls + + DTA D TD10 DECtape data channel + DTB + + CDR E 461 or CR10 card reader + + APR E KI10, KA10, or 166 arithmetic + processor + + RTC E DK10 real-time clock (each CPU) + + SCN F Terminal scanner + + PTR F Paper-tape reader + + LPT F Line printer + + DTA F DECtape flag channel + + MTA F Magtape flag channel + MTB + + CTY F Console terminal + + NET F Remote devices + + DSK G Disk flag channel + + PEN G Light pen + + PTP G Paper-tape punch + + CDP G Card punch + + PLT G Plotter + + DIS H Display data channel + + CLK I Scheduler, clock routines (always + assigned to channel 7) + GENERATE A MONITOR WITH MONGEN Page 8-48 ________ _ _______ ____ ______ + + +8.18 TERMINAL INTERFACE LINE NUMBERS ________ _________ ____ _______ + +The DC10 data line scanner is capable of handling up to a total of 64 +lines (physical ports). The lines are monitored by scanners of two +types -- a DC10B or a DC10E. Each DC10B is designed to handle eight +lines of terminal communications, and each DC10E is designed to handle +eight lines of dataset control. When using a terminal through a +dataset, both a DC10B and a DC10E line are required. The DC10E line +interfaces the dataset control signals to system decipherable signals, +and the DC10B line carries the teletype information. + +When the monitor assigns terminal numbers to DC10 lines, only the +DC10B lines receive numbers. The reason for this action is that each +DC10E line must be paired with a DC10B line to function properly, +making an additional number unnecessary. + +Each installation's system administrator must determine which DC10E +dataset controllers are wired to which DC10B lines. (Refer to Figure +8-2, where line numbers 10 through 17 are DC10B dataset lines that are +hardwired to the DC10E controller lines 20 through 27.) + +The sequence of line number assignments for DC76s is: + + DC10 0 + DC10 1 + DC68 0 + DC68 1 + DC76 0 + DC76 1 + + Remote lines + + CTYs + PTYs + GENERATE A MONITOR WITH MONGEN Page 8-49 ________ _ _______ ____ ______ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Figure 8-1 One DC10 with Two DC10Bs + + + + + + + + + + + + + + + + + + + + + + + + + + Figure 8-2 One DC10 with One DC10B and One DC10E + GENERATE A MONITOR WITH MONGEN Page 8-50 ________ _ _______ ____ ______ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Figure 8-3 One DC76 with 33 Lines + + + + + + + + + + + + + + + + + + + + + + + + + + Figure 8-4 One DC10 with Two DC10Bs and One DC68 with Eight Lines + GENERATE A MONITOR WITH MONGEN Page 8-51 ________ _ _______ ____ ______ + + +8.19 MONGEN ERROR MESSAGES ______ _____ ________ + +?ANSWER MUST BE ONE OR (ANS0, ANS1,...) + + Your response to this question was not a legal response. Choose + one of the responses within parentheses. + +?ANSWER WITH ONE OF THE CHOICES WITHIN PARENS + + You responded to a multiple choice question with an answer that + was not one of the choices. Reanswer the question with one of + the supplied choices typed within parentheses after the question. + +?CANNOT BE SAME AS CPUn + + When you responded with the serial number of a CPU, your response + matched the response for another CPU. Retype your response and + press the carriage return. + +?DEVICE n NOT AVAILABLE + + The device you requested is not available at this time. Select + another device or wait until the desired device is ready. + +?HIGHEST-AC-TO-SAVE MUST BE N OR LESS + + You specified an illegal AC number in response to the question. + Reanswer the question and press the RETURN key. + +%MORE THAN 6 CHARACTERS + + In answer to question number 9 within the Networks Configuration + dialogue, you responded with a central site name longer than 6 + characters. Reanswer the question with a central site name + having fewer than 6 characters. + +%MORE THAN 24 CHARACTERS + + In answer to question number 4 within the Hardware Configuration + dialogue, you responded with a system name longer than 24 + characters. Reanswer the question with a system name having + fewer than 24 characters. + +?MUST BE IN RANGE MIN-MAX + + You specified an answer that was not within the legal response + range of min to max. Reanswer the question with a value that is + within the legal range. + +?NO DEFAULT RANGE ALLOWED, TYPE A NUMBER + + In response to a question, you pressed the RETURN key. There is + no default answer for this question. Reanswer the question by + typing a response before pressing the RETURN key. + +?NO DEFAULT VALUE ALLOWED + + In answer to a question, you pressed the RETURN key. This + question, however, does not have a default answer. Type an + answer in response to the question before you press the RETURN + key. + +?NOT AVAILABLE IN x MONITOR + GENERATE A MONITOR WITH MONGEN Page 8-52 ________ _ _______ ____ ______ + + + A feature was specified that is not available in the monitor you + are generating. Check the response MONGEN typed after you typed + R MONGEN; make sure that you are using the appropriate version + of MONGEN. + +?NOT DEV:FILE.EXT P,PN + + Your response was not in the legal file specification format; + retype your response and press the RETURN key. + +?NOT DEVICE-MNEMONIC, PI-CHANNEL + + Your response to the question was not in the desired format. + Retype your response in the correct format. + +?NOT DEVICE-MNEMONIC, PI-CHANNEL, HIGHEST-AC-TO-SAVE + + Your response to the question was not in the desired format. + Reanswer the question in the correct format. + +?NOT DEVICE-MNEMONIC, PI-CHANNEL, NO.-OF-DEVICES + + Your response to the question was not in the desired format. + Reanswer the question in the correct format. + +?NOT "SWITCH.VALUE" OR KEYWORD + + Your response to the question was not legal. Reanswer the + question and press the RETURN key. + +?NOT "SYMBOL.VALUE" + + Your response to the question was not in the legal format; + reanswer the question and press the RETURN key. + +?TYPE ENOUGH TO UNIQUELY DISTINGUISH ANSWER + + You abbreviated an answer to a question. The abbreviation was + not long enough to distinguish it from another possible answer. + Reanswer the question without abbreviating the answer. + +?TYPE OCTAL LINE NUMBER OR CTY OR CTY1 FOLLOWED BY A CARRIAGE RETURN + + Your response to the question was not what MONGEN expected. + Reanswer the question with a TTY line number, the word CTY, or + the word CTY1. + +?TYPE OCTAL M-N or M + + Type a range of numbers or a single number in response to this + question. + +?TYPE OCTAL M-N,P OR M,P + + Your response to the question was not in a legal format; + reanswer the question with a range of values before pressing the + RETURN key. + +?TYPE ONE ANSWER FOLLOWED BY A CARRIAGE RETURN + + You supplied more than one answer to the question. Type one + answer and press the RETURN key. + +?TYPE SINGLE NUMBER FOLLOWED BY A CARRIAGE RETURN + GENERATE A MONITOR WITH MONGEN Page 8-53 ________ _ _______ ____ ______ + + + In response to the question you supplied more than one digit + number, when only one digit is legal. Retype your response and + press the RETURN key. + +?UNKNOWN SWITCH + + You have specified a switch that is unknown to MONGEN. Refer to + the list of legal switches. Type one of them before pressing the + RETURN key. + + + + + + + + + + + + + CHAPTER 9 + + ASSEMBLE MACRO FILES ________ _____ _____ + + + +It is always necessary that you assemble F, S, HDWCNF, TTYCNF, NETCNF, +COMMON, COMDEV and COMMOD (and NETPRM and COMNET, if you have +purchased network software) because they are configuration-dependent. +The following command string can be used to assemble these files. + +For KL10 systems only, type the following: + + .COMPILE DTEPRM + +For all systems, type the following: + + .COMPILE F/COMP,S/COMP,HDWCNF+NETCNF+TTYCNF+ + +If you responded Y to the MONGEN question DO YOU WANT NETWORK +SOFTWARE, type the following command line instead of the one above. + + .COMPILE F/COMP,S/COMP,NETPRM/COMP,HDWCNF+NETCNF+TTYCNF+ + +It is important that F.MAC precede S.MAC because S has conditional +assemblies depending on the contents of F. + +If you are using a standard combination of feature test switch +settings and DEC-supplied sources, you do not need to assemble the +remainder of the bundled monitor modules because they have already +been assembled and combined in a TOP?10.REL file (see tables on +following pages). + +If you are not using a standard combination of feature test switch +settings or you have SOUPed in your own changes, you must assemble all +the bundled monitor sources. The simplest way to do this is to +compile indirectly the appropriate .CMD file (see tables on following +pages). For example, to assemble all the bundled sources for a +standard KI monitor, type: + + .COMPILE @CONKI + +You must assemble any unbundled software. To assemble monitors with +the virtual memory option, substitute TOPV10.REL (KI10) or TOPW10.REL +(KL10) for TOPI10.REL in the command line. + +To assemble monitors with the DC44 option, issue the following +command: + + .COMPILE F, S, TYPSER + +And then link your monitor in the prescribed fashion. + +To assemble monitors with the DAS78 option, issue the following + ASSEMBLE MACRO FILES Page 9-2 ________ _____ _____ + + +command line: + + .COMPILE F, S, D78INT + +Then, link your monitor in the prescribed fashion. For installation +instructions concerning the -11 portion of the DAS78 and D78SPL, +carefully read D78MNT.RNO, DAS78.RNO, and DAS78.RND found on the +unbundled distribution tape. + +To assemble monitors with the XTCSER options, issue the following +command: + + .COMPILE F, S, XTCSER + +Then, link your monitor in the prescribed fashion. + +If you also want to create cross-reference (CREF) listings, assemble +all the sources for your monitor with the CREF switch, i.e., /C. The +simplest way to do this is to assemble the appropriate command files +indirectly to produce .REL files and CREF input files. Then, CREF can +generate the listings. (See the example below.) + +The table below lists the different MACRO indirect command files for +both bundled and unbundled software. The intermediate .REL file +extensions are the extensions specified for the .REL files in the .CMD +files. + + +CONFIGURATION BUNDLED INTERMEDIATE + SOFTWARE .REL FILE + FILENAME EXTENSIONS + +KA-LUG CONLUG.CMD *.RLG +KA-Standard CONKA.CMD *.RLA +KI-LUG CONLGI.CMD *.RLH +KI-Standard CONKI.CMD *.RLI +KI-Virtual Memory CONVI.CMD *.RLV +KL-Virtual Memory CONVL.CMD *.RLW + + +After assembling the monitor sources, you may need to combine certain +modules into a TOP?10.REL file. If you are not using a TOP?10.REL +file from the distribution tape, because you have used nonstandard +feature test switch settings or you have modified the DEC sources, you +must create your own TOP?10.REL file. + +To combine the assembled monitor modules and make TOPI10.REL for a KI +system type: + + .R PIP + + *CMBKI@ + + . + +Note that indirect PIP files exit directly to monitor level +(. prompt). Therefore, you must specify R PIP or START after +specifying an indirect command file name. + +To produce the proper TOP?10.REL for your configuration, use the +appropriate PIP indirect command files from the list below. + + +CONFIGURATION SOFTWARE .REL + ASSEMBLE MACRO FILES Page 9-3 ________ _____ _____ + + + FILENAME CREATED + +KA-LUG CMBLUG.CCL TOPG10.REL +KA-Standard CMBKA.CCL TOPA10.REL +KI-LUG CMBLGI.CCL TOPH10.REL +KI-Standard CMBKI.CCL TOPI10.REL +KI-Virtual Memory CMBVI.CCL TOPV10.REL +KL-Virtual Memory CMBVL.CCL TOPW10.REL + + +EXAMPLE: For a standard KI system you would assemble the source +files, produce a complete set of CREF files (cross referenced +listings) on magtape, produce TOPI10.REL and a listing of the +monitor's global symbols as follows: + + .COMPILE/C@CONKI + + .ASSIGN MTA LPT + + .CREF + + .R PIP + + *CMBKI@ + . + +Save your terminal output from the CREF command so you will know the +order of the files on the magtape. + +Whenever you want to print the entire set of monitor source files, +mount the tape created in the previous step and type: + + .R PIP + + *MTAn:(MW)= + *LPT:=MTAn:*.* + +If you want to print a single file from the magtape, advance the tape +to the proper position and PIP the file to the line printer. Use your +terminal output that you saved from the CREF command to determine +where the desired file is on the tape. + +Then to get a listing of the monitor global symbols, you must run +GLOB. To produce a GLOB listing for a standard KI monitor with +network software and some unbundled software type: + + .R GLOB + + *COMMON,COMDEV,COMNET,COMMOD + + *DSK:TOPI10.GLB=TOPI10$ + +where $ is an ESCAPE or ALTMODE. + +If you assembled the sources with CONKI.CMD, add the extension .RLI to +COMMON,COMDEV,COMNET, and COMMOD in the above command string. + + + + + + + + + + + + + CHAPTER 10 + + LOAD AND SAVE THE MONITOR ____ ___ ____ ___ _______ + + + +Whether or not you can load the monitor under timesharing using +LINK-10 depends on how much user core is available. In general, if +your installation has about 50K of user core, you should be able to +load the new monitor using LINK-10. If you have significantly less +user core than this, consult your software specialist for details on +loading the monitor. + +The following sequence of instructions loads and saves a monitor for a +standard configuration with no unbundled software: + + .R LINK + + */NOINITIAL /HASH:6000 YURMON/SAV,YURMON/MAP = /LOCALS - + #/MAXCOR:60K - + #,COMMON,COMDEV,COMMOD,TOP?10 /SEARCH /GO + +The filename YURMON is an arbitrary name chosen for the monitor; you +may use any file name. Specify the TOP?10 to correspond to your +system configuration: + + TOPG10 for KALUG + TOPA10 for KA standard + TOPH10 for KILUG + TOPI10 for KI standard + TOPV10 for KI-virtual memory + TOPW10 for KL-virtual memory + +Note that COMMON, COMDEV, and COMMOD in this example were generated by +the COMPILE commands at the beginning of Chapter 9, so their +extensions are .REL. If an indirect compile was done on a .CMD file, +the extension created by the .CMD file would have to be specified. +For example, if .COM @CONKI was used, you would have to specify +COMMON.RLI, COMDEV.RLI, and COMMOD.RLI. + +The TOPI10.REL (or the appropriate TOP?10.REL) file can be the one +from the monitor distribution tape or one created by assembling all +the monitor sources with the proper .CMD file (see Chapter 9) and +combining them with the proper .CCL file (necessary if you are using a +nonstandard combination of feature test switch settings or you have +SOUPed in your own changes). (See Chapter 8.) + +If your monitor includes one or more unbundled options (other than +virtual memory), restore the unbundled monitor modules using the +following procedure. Repeat the procedure for each unbundled tape. + + .R BACKUP + + /TAPE MTxn ;the tape drive with + ;the unbundled tape + LOAD AND SAVE THE MONITOR Page 10-2 ____ ___ ____ ___ _______ + + + ;on it. + /RESTORE filename ;for example, D78INT.MAC + ! ;BACKUP's indication that it + ;is busy + "DONE + ;repeat above, beginning with + ;/TAPE for each unbundled tape + ^C ;CTRL/C when you are finished. + +Then, you should compile the files on the unbundled tapes. For +example, to compile the D78INT and TSKSER options, you would use the +following command line: + + .COMPILE F, S, D78INT, TSKSER + MACRO:F + MACRO:S + MACRO:D78INT + MACRO:TSKSER + +Lastly, you should type the following command line to load the monitor +with unbundled software. + + .R LINK + + */NOINITIAL/HASH:6000 YURMON/SAV,- + #YURMON/MAP = /LOCALS/MAXCOR:60K- + #COMMON, COMDEV, COMMOD, unbmod,...unbmod- + #TOP?10/SEARCH/GO + +Where: unbmod can be COMNET, + TSKSER, TYPSER, XTCSER, and/or + D78INT. + +The files included in each of the unbundled software packages are +listed below: + +Be sure that the unbundled package name (e.g., XTCSER, TYPSER, or +D78INT) precedes TOP?10. This must be done so that .SYSINI, ONCE, +etc. will be loaded last and, therefore, can be discarded after +initialization. + +Using the commands in the above examples, LINK will produce a load map +named YURMON.MAP. The monitor save file will be YURMON.SAVE or +YURMON.HGH and YURMON.LOW. These files must be converted to .EXE +files before they can be loaded with BOOTS. This can be accomplished +by using the FILEX program or the monitor commands GET followed by +NSAVE. + +Note that LINK-10 allows you to load and save a program in the same +command string. Also, certain switch settings can speed up the +loading process. MAXCOR:60K is about the minimum core necessary for +loading the monitor; if no parameter is set, however, LINK-10 will +expand to use up to one half the user core. Using a HASH size of 6000 +is an upper limit which should work for any system. For the sake of +economy, if you have a smaller system, you should try smaller HASH +values. LINK-10 will work without specifying either of these +parameters; however, they may speed up the loading process if used. +For a complete definition of all switches refer to the LINK-10 manual. + +Then, if you have built a two-segment monitor, you must convert your +monitor .HGH and .LOW files to an .EXE file (and your system must +support .EXE files). Type: + + .R FILEX + LOAD AND SAVE THE MONITOR Page 10-3 ____ ___ ____ ___ _______ + + + *YURMON.EXE=YURMON.HGH + +If you choose to have .EXE file support with a single segment monitor, +type: + + .R FILEX + + *YURMON.EXE=YURMON.SAV + +Virtual Memory _______ ______ + + VMSER.MAC The 6.03 monitor source file that implements virtual + memory. + + TOPV10.REL The combined .REL files for KI10 virtual memory + monitors. + + TOPW10.REL The combined .REL files for KL10 virtual memory + monitors. + + CONVI.CMD The command files needed for assembling KI10 virtual + memory monitors. + + CMBVI.CCL The command files needed to create the combined .REL + files for KI10 virtual memory systems. + + CONVL.CMD The command files needed for assembling KL10 virtual + memory monitors. + + CMBVL.CCL The command files needed for creating the combined + KL10 virtual memory .REL files. + + MAKPFH.MAC The page fault handler for KI10 and KL10 virtual + MAKPFH.EXE memory monitors. + PFH.VMX + + DDT.VMX The debugger to be used with virtual memory systems. + + GET.* A user-mode program to .GET virtual memory + GET2.RNO executable programs. + +DC44 Option ____ ______ + + TYPSER.MAC The 6.03 monitor source file needed for the DC44 + interface. + +DAS78 Option _____ ______ + +The following file is a part of the monitor code. + + D78INT.MAC The 6.03 source file for the DAS70 interface. + +The following files are part of the PDP-11 code. + + DAS78.CTL The control fle needed to assemble the PDP-11 code. + + DAS78.P11 The source files for the DAS78 PDP-11 code. + + DAS78.BIN The executable DAS78 PDP-11 code. + + DAS78.EX The DDT11 file for the PDP-11 code. + +The following files are part of QUEUE and QMANGR, for use with +DAS78SPL. + LOAD AND SAVE THE MONITOR Page 10-4 ____ ___ ____ ___ _______ + + + D78SPL.CTL The control file to assemble D78SPL. + + D78SPL.MAC The source code for D78SPL. + + D78SPL.EXE The executable code for D78SPL. + +The following files are used for DAS78 the modified LPTSPL. This +program is used for 2780s, remote batch stations connected to the +DECsystem-10. This modified LPTSPL can also be used to print on the +local line printer. + + SPOOL.CTL The control file for assembling a DAS78 LPTSPL. + + SPOOL.D78 The source code for DAS78 modified SPOOL. + + LPTSPL.EXE The executable code. + +The following files support the DAS78 modified SPRINT. + +This program is for use when using one 2780 as a Remote Batch Station +to the DECsystem-10. This modified SPRINT will also be used to read +cards from the local card reader. + + SPRINT.CTL The control file for assembling a DAS78 SPRINT. + + SPRINT.D78 The source code for DAS78 modified SPRINT. + + SPRINT.EXE The executable code. + +The following files support the PDP-11 Debugging program. + + DDT11.MAC Source for DDT11. + + DDT11.EXE Executable code. + + DDT11.RNO DDT11 document. + +The following files support MODEM diagnostics. + + DQMODM.HLP A short document on how to use DQMODM. + + DQMODM.BIN The executable code. + +The following are DOCUMENTS. + + DAS78.RNO The DAS78 "Cookbook" - WARNING: Preliminary + version. + + DAS78.RND + + D78MNT.RNO Installation hints and other useful information. + +The following are miscellaneous files contained in the DAS78 option. + + C.MAC Needed for assembling QUEUE. + + SCNMAC.MAC Needed for assembling QUEUE. + + HELPER.REL Needed for LPTSPL, SPRINT, and QUEUE. + + QUEUER.REL Needed for LPTSPL, SPRINT, and QUEUE. + + SCAN.REL Needed for QUEUE (V4). + LOAD AND SAVE THE MONITOR Page 10-5 ____ ___ ____ ___ _______ + + + WILD.REL Needed for QUEUE (V5). + +Note: The MACDLX assembler is required to assemble DAS78.P11, and the +BOOT11 bootstrap is required to load code from the -10 into the -11 +memory. Both these programs will be found on the main (bundled) 6.03 +monitor distribution tape. + +XTCSER Option ______ ______ + +The following file is the XTCSER option. + + XTCSER.MAC The 6.03 monitor source code for the DA28 driver. + + + + + + + + + + + + + + CHAPTER 11 + + MAKE A COPY OF THE NEW MONITOR ____ _ ____ __ ___ ___ _______ + + + +This step is a precaution against losing the newly built monitor. If +the monitor is accidentally destroyed, you need not rebuild it; you +will have a copy in READIN mode available on tape. + +Copy BOOTM, BACKUP.EXE, and your newly built monitor to magnetic tape. +You must copy the files at 556 bpi for READIN mode on TM10 controllers +and at 800 or 1600 bpi for TU70s. The entire tape must be written at +one density. + +The following steps create a backup monitor tape for a TM10 +controller. First, be sure to read the BOOTM description in Chapter +18 on how to create BOOTM.REL and BOOTM.RDI. + + .AS MTA0: BACKUP + + .SET DENSITY MTA0:556 + + .SET BLOCKSIZE MTA0:2000 + + .REWIND MTA0: + + .COPY MTA0:=BOOTM.REL + + .SET BLOCKSIZE MTA0:128 + + .COPY MTA0:=BACKUP.EXE + +Then, BACKUP your disk area that contains your new monitor by typing: + + .R BACKUP + + /DENSITY 556 + /SAVE DSKB:[ppn]=DSKB:[ppn]*.* + +The following steps create a backup monitor tape for TU70s: + + .AS MTA0: BACKUP + + .REWIND MTA0: + + .COPY MTA0:=BOOTM.RDI + + .COPY MTA0:=BACKUP.EXE + +Then, BACKUP your disk area that contains your new monitor by typing: + + .R BACKUP + + /SAVE[1,2]*.*=[1,2]*.* + + + + + + + + + + + + + CHAPTER 12 + + COMMUNICATION SYSTEMS _____________ _______ + + + +Prepare for Communications Systems and Remote Stations + + 1. DC71 - Instructions for installing and usng a DC71 + Communications System are in the Remote Station User's Guide + in the DECsystem-10 Software Notebooks. + + 2. DC72 - Instructions for installing and using a DC72 + Communications System are in the Remote Station User's Guide + in the DECsystem-10 Software Notebooks. + + 3. DC76 - Instructions for installing a DC76 Communications + System are in the Operators Guide in the DECsystem-10 + Software Notebooks. + + 4. Installations that plan to install remote station software + for the first time should contact their software specialist. + + + + + + + + + + + + + + CHAPTER 13 + + UPDATE ACCOUNTING FILES ______ __________ _____ + + + +Under the phased installation concept, if you are running a current +monitor, you have already converted the accounting files ACCT.SYS and +AUXACC.SYS to 6.02 format using the latest version of REACT. If you +have not yet converted the accounting files, LOGIN under [1,2] and +convert to the new format at this time. + +If you have no previously running monitor, you must generate the +initial accounting files or augment the Digital Equipment +Corporation-supplied accounting files using REACT. + + 1. ACCT.SYS - passwords and privileges for all users. + + To convert to the new format, simply read the old format + ACCT.SYS with the R command and write it back with the W + command. Be sure the latest version of REACT is on SYS: + + Type: + + .R REACT + + Optional: For help in running REACT type: + + */H + + then type: + + *R + + *W DSKA:[1,4] + + + CAUTION + + Make sure that you are using the latest version of + ACCT.SYS. If you have a copy of ACCT.SYS on several + file structures, make sure each structure has the + latest version. + + Also, do not use the passwords supplied in ACCT.SYS. + The passwords are well known and using them could + decrease system security. + + + + 2. AUXACC.SYS - disk file structure quotas for all users. + + Because device DSK: for any job is defined by the job's file + structure search list, different jobs may have different, and + possibly nonintersecting, definitions of DSK:. Therefore, + UPDATE ACCOUNTING FILES Page 13-2 ______ __________ _____ + + + one job could reference a file as DSK:filename when another + job could not (although that job could possibly reference the + file by specifying the file structure on which the file + exists). + + To circumvent this problem, you or the system administrator + can specify all public file structures in the AUXACC entries + for all users. If you do not want a user to have space on a + particular file structure, specify a logged-in quota of 0. + In this case, no UFD is created for the user when he logs in, + but the file structure is included in the user's search list + so that he can always reference other files on that file + structure as device DSK:. + + To convert the AUXACC files, type the following to 6.03 + REACT: + + *A + + *W DSKA:[1,4] + + and to put a second copy on a slower file structure, type: + + *W DSKB:[1,4] + + + + + + + + + + + + + + CHAPTER 14 + + GET NEW MONITOR ___ ___ _______ + + + +You can now get the new monitor from disk with BOOTS or from magtape +with BOOTM. + +If you have a KL10 system, begin reading at Step B1. If you have a +KA10 or KI10 system, begin reading below at Step A1. Note that all of +the instructions in this chapter assume that you have a saved copy of +the monitor called SYSTEM.EXE on [1,4] on either DSKA:, DSKB:, ..., +DSK0. + +Step A1 READIN BOOTS. ____ __ + +If the monitor was previously running, follow Situation A. If you _________ _ +have an RP04 and BOOTS was previously written on blocks 0 and 4 +through 7 of the disk packs with WTBOOT, follow Situation B. _________ _ +Otherwise, follow Situation C. _________ _ + +Situation A: Monitor previously running _________ _ + + 1. Set the NXM switch to off. + + 2. Set the memory address switches to 407. + + 3. Push the START button. + + 4. BOOTs responds with a carriage return. If there is no + response, try Situations B or C. + + 5. Type a carriage return to load SYS:SYSTEM.EXE from any disk + (DSKA through DSK0). If some other file, directory, or + structure is desired, type a line in the following format: + + structure:file.ext[directory] + + BOOTs types a bell and a question mark if it cannot find the + file, or if any errors occur while reading the file. + + 6. If successful, refer to step C1. + +Situation B: RP04 Readin _________ _ + + 1. Set the NXM and PAR STOP switch + + 2. Set the READIN switches to 270. (If you have multiple RH10s, + you may have to set the READIN switches to 274 or 360). + + 3. On the READIN panel in the RH10, set the toggle switch to + DISK, and set the thumbwheel to the READIN unit number. (If + the DF10C is in KI mode, use an odd-numbered unit. If it is + in KA mode or the RH10 is using a DF10, use an even-numbered + GET NEW MONITOR Page 14-2 ___ ___ _______ + + + unit.) + + 4. Push the STOP button. + + 5. Push the RESET button. + + 6. Push the READIN button. + + 7. BOOTS responds with a carriage return. If there is no + response, try the procedure for Situation C. + + 8. Type a carriage return to load SYS:SYSTEM.EXE from any disk + (DSKA through DSK0). If you want a different structure, + file, or directory from the default, type a line in the + following format: + + structure:file.ext[directory] + + BOOTS types a bell and a question mark if it cannot find the + file or if any errors occur while reading the file. + + 9. If successful, turn to step C1. + +Situation C: Read BOOTS from paper-tape reader _________ _ + + 1. Push the STOP button. + + 2. Push the RESET button. + + 3. Put the BOOTS tape in the paper tape reader. + + 4. Set the NXM switch to off. + + 5. Set the READIN switches to 104. + + 6. Push the READIN button. The paper tape should begin to move. + If it does not, retry the procedure at least once. + + 7. BOOTS responds with a carriage return when loaded. If there + is no response, retry the procedure at least once. + + 8. Type a carriage return to load SYS:SYSTEM.EXE from any disk + (DSKA through DSK0). If you want a different structure, + file, or directory from the default, type a line in the + following format: + + structure:file.ext[directory] + + BOOTS types a bell and a question mark if it cannot find the + file or if any errors occur while reading the file. + + 9. If successful, turn to Step C1. + +Step A2 Readin a Monitor from Magtape Using BOOTM. ____ __ + +The following instructions describe how you get a KA10 or KI10 monitor +from magtape with BOOTM. These instructions assume that BOOTM has +been written as the first file on the magtape, BACKUP is the second +file, and there is a BACKUP save set containing the monitor to be +loaded. + +Note that when BOOTM detects an error, it types a bell and a question +mark followed by an error message. The possible error messages are +listed in Chapter 16. + GET NEW MONITOR Page 14-3 ___ ___ _______ + + +Read BOOTM from magtape. (If you have a dual-magtape system, you must +use MTA for READIN.) + + 1. Push the STOP button. + + 2. Push the RESET button. + + 3. Mount the magtape on MTA unit 0 write-locked. (It must be + mounted on unit 0 for TM10 controllers or on the lowest + numbered ready unit for TU70s.) + + 4. For a TM10-controlled magtape, set the READIN switches to + 340. For a TU70 unit, set the READIN switches to 220. + + 5. Set the NXM switch to off. + + 6. Push the READIN switch. + + 7. The magtape should move and read in BOOTM from the first file + +BOOTM outputs the prompt characters BTM>. Then, you must give a file +specification for the monitor you want to read; for example: + + DSKB:603.EXE[1,4] + +If you type a carriage return in response to BTM>, the default monitor +(SYS:SYSTEM.EXE[1,4]) will be read in. This default file will be +gotten from the magtape on the same unit from which the hardware +READIN was done. If BOOTM was not read by hardware READIN from +magtape, the default for controller is TM10 and the default for unit +is 0. + +Turn to Step C1. + +Step B1 READIN BOOTS (KL10 Systems) ____ __ ______ _____ _____ ________ + +In most cases you should only have to check to see that the power +light to the right of the load switches is glowing red. Otherwise, +press the black power switch to the POWER ON position. + +After powering up the system or deciding that you must do a complete +reload, you have a few alternatives on how you load the console +front-end processor. You can do a standard load from a disk pack or +DECtape, or you can load using the swicth register. In most cases, +you will load from a disk pack because it is much faster than DECtape. +However, if dual-port hardware problems prevent loading from a disk +pack, or if your system manager wants you to use software residing on +a DECtape, you may need to load the system using the DECtape drive. +Also, if you need to load the system using some non-standard hardware +configurations or special software, you will have to use the switch +register. The switch register allows you to load from any disk pack +or DECtape and also enter the KL initialization operator dialogue +(KLINIT). The KLINIT dialogue allows you to take such nondefault +paths as configuring memory yourself, loading a bootstrap program from +any file, and loading a nondefault monitor. The procedures for +loading the front-end processor via a disk pack (Situation A), a +DECtape (Situation B), or the switch register (Situation C) are +described in the next three sections. + +Situation A: Loading RSX-20F from Disk _________ __ _______ _______ ____ ____ + +This is the most common way to load the console front end. It assumes +that the system power is ON, that all hardware and software have been +correctly installed, and that the disk pack has been mounted properly. + GET NEW MONITOR Page 14-4 ___ ___ _______ + + +Also, the disk pack containing both the TOPS-10 monitor and the +RSX-20F front-end monitor must be on a dual-ported drive (controller +select switch points to A/B), and the drive must be unit 0 with +respect to both the central and front-end processors. + +The operation is as follows: + + 1. Set the ENABLE/DISABLE load switch to ENABLE. + + This will enable the other three load switches. + + 2. Press the DISK load switch. + + This will cause the front-end processor to access the disk on + drive 0 and load the RSX-20F monitor. The KL initialization + program (KLINIT) is loaded and the default hardware + configurations of cache and external memory are set up. The + bootstrap program for the TOPS-10 monitor is then loaded into + the central processor and started. The following is an + example of the output you will receive on the console + terminal. + + RSX-20F V006A 0:16 21-JUN-76 + + [SY0: REDIRECTED TO DB0:] + [DB0: MOUNTED] + KLI -- VERSION V002E RUNNING + KLI -- MICROCODE VERSION 131 LOADED + KLI -- ALL CACHES ENABLED + LOGICAL MEMORY CONFIGURATION: + CONTROLLER + ADDRESS SIZE RQ0 RQ1 RQ2 RQ3 CONTYPE INT + 000000 512K 04 FOR ALL DMA20 4 + KLI -- BOOTSTRAP LOADED AND STARTED + +The first line of output tells you the version and the creation time +and date of the RSX-20F monitor for the front end. The next two lines +tell you that DB0: (the disk pack on drive 0) is the system device +(SY0:) for the front-end tasks. The next eight lines are output by +the KL initialization program. They document the version of KLINIT +that is running and tell you that the KL10 microcode was successfully +loaded, the cache was enabled, external memory was configured, and +that the bootstrap program for the TOPS-10 monitor was loaded and +started. + +If an error occurs during the KL initialization program, you will +receive an error message preceded by "KLI -- ?" and you will be placed +in the KLINIT dialogue mode described in Appendix C of the KL Series +Operator's Guide. (The loading of the TOPS-10 monitor is discussed in +Step B2.) + +Situation B: Loading RSX-20F from DECtape _________ __ _______ _______ ____ _______ + +This method of loading the console front end should be used if you +cannot load from a disk pack or if you need a particular version of +software that is only on DECtape. It assumes that the system power is +ON, that the proper software exists on DECtape, and that the DECtape +is mounted correctly on Unit 0. Be sure to leave the DECtape mounted +while the system is running. + +The operation is as follows: + GET NEW MONITOR Page 14-5 ___ ___ _______ + + + 1. Set the ENABLE/DISABLE load switch to ENABLE. + + This will enable the other three load switches. + + 2. Press the DECTAPE load switch. + + This will cause the front-end processor to access the DECtape + on drive 0 and load the RSX-20F monitor. The KL + initialization program (KLINIT) is loaded and the default + hardware configurations of cache and external memory are set + up. The bootstrap programs for the TOPS-10 monitor is then + loaded into the central processor and started. The following + is an example of the output you will receive on the console + terminal. + + RSX-20F V006A 0:16 21-JUN-76 + + [SY0: REDIRECTED TO DT0:] + [DT0: MOUNTED] + KLI -- VERSION V002E RUNNING + KLI -- MICROCODE VERSION 131 LOADED + KLI -- ALL CACHES ENABLED + LOGICAL MEMORY CONFIGURATION + CONTROLLER + ADDRESS SIZE RQ0 RQ1 RQ3 CONTYPE INT + 000000 512K 04 FOR ALL DMA20 4 + KLI -- BOOTSTRAP LOADED AND STARTED + +The first line of output tells you the version and the creation time +and date of the RSX-20F monitor for the front end. The next two lines +tell you that DT0: (the DECtape on unit 0) is the system device +(SY0:) for the front-end tasks. The next eight lines are output by +the KL initialization program. They give the version of KLINIT that +is running and tell you that the KL10 microcode was successfully +loaded, the cache was enabled, external memory was configured, and +that the bootstrap program for the TOPS-10 monitor was loaded and +started. + +If an error occurs during the KL initialization program, you will +receive an error message preceded by "KLI -- ?" and you will be placed +in the KLINIT dialogue mode described in Appendix C of the KL Series +Operator's Guide. (The loading of the TOPS-10 monitor is discussed in +Section 3.3.) + +Situation C: Loading RSX-20F via the Switch Register _________ __ _______ _______ ___ ___ ______ ________ + +You must load the console front end via the switch register if you +need to do any of the following: + + 1. Enable specific cache or configure external memory yourself + instead of using the default configurations. + + 2. Load a TOPS-10 bootstrap program from a file with a name + other than BOOT.EXB; for example, BOOTM.EXB containing + BOOTM, which loads a monitor from magnetic tape. + + 3. Load from a disk pack or DECtape that is not on unit 0. + +The software for the front-end processor must reside on a DECtape or +disk pack connected to the front end. If both the front-end software +and the system monitor reside on the same disk pack, the pack must be +mounted on a dual-ported drive and the controller select switch must +be set to A/B. + GET NEW MONITOR Page 14-6 ___ ___ _______ + + +The operation is as follows: + + 1. Set the ENABLE/DISABLE load switch to ENABLE. + + This will enable the other three load switches. + + 2. Set the appropriate switches (or bits) in the switch + register. + + Switch 0 is mandatory when loading via the switch register. + Switches 1 and 2 must be set on if you intend to use the KL + initialization dialogue (KLINIT). If RSX-20F resides on a + disk pack, set switch 7 on; if RSX-20F is on a DECtape, + switch 7 must be off. Switches 8-10 must be set to specify + the drive number of the disk or DECtape. (For a detailed + description of all the bit settings in the switch register, + see Table 14-1.) + + + Table 14-1 + Switch Register Bit Definitions + + + Bit Meaning + + + 0 If this is set, the remaining bits are interpreted. + You must set this to load via the switch register. + + 1,2 If both are set, the KL initialization operator + dialogue (KLINIT) is loaded and started. This is the + usual case when loading via the switch register. + + If either one is set, the RSX-20F is loaded; no + communication is initiated between the -10 and the + -11 processors at this time. + + If both are not set, the system is loaded much like + it is via the DISK or DECTAPE load switch. However, + because other bits are interpreted, you can specify + the unit number of the bootstrap device in bits 8-10. + + 3-6 Currently not used, and must not be set. + + 7 If this is set, the bootstrap device is a disk pack + on a dual-ported drive. + + If this is not set, the bootstrap device is a DECtape + drive on the front-end processor. + + 8-10 These three bits allow you to specify the unit number + of the bootstrap device (0 to 7). No bits set + indicate unit 0; bits 9 and 8 set indicate unit 3. + + 11-14 Currently not used, and must not be set. + + 15 This indicates the action taken when an I/O error + occurs during the bootstrapping. If this is set, the + operation is retried indefinitely if an error occurs. + If not set (the normal case), a halt occurs after ten + unsuccessful retries. + + 16,17 Not used, and must not be set. + GET NEW MONITOR Page 14-7 ___ ___ _______ + + + 1. Press the SW/REG load switch. + + This will cause the front-end processor to access the disk + drive (switch 7 set on) or the DECtape drive (switch 7 set + off) with the unit number as specified in switches 8-10. + The KL initialization program (KLINIT) is loaded and + started and the default hardware configurations of cache + and external memory are set up. The standard bootstrap + program for the TOPS-10 monitor is then loaded into the + central processor and started. + + The following is an example of the output you will receive + on the console terminal if switches 0, 7, 8, and 9 are set + on. + + RSX-20F V006A 0:16 21-JUN-76 + + [SY0: REDIRECTED TO DB3:} + [DB3: MOUNTED] + KLI -- VERSION V002E RUNNING + KLI -- MICROCODE VERSION 131 LOADED + KLI -- ALL CACHES ENABLED + LOGICAL MEMORY CONFIGURATION: + CONTROLLER + ADDRESS SIZE RQ0 RQ1 RQ2 RQ3 CONTYPE INT + 000000 512K 04 FOR ALL DMA20 4 + KLI -- BOOTSTRAP LOADED AND STARTED + + The first line of output tells you the version and the + creation time and date of the RSX-20F monitor for the front + end. The next two lines tell you that DB3: (the disk on + unit 3) is the system device (SY0:) for the front end + tasks. If bit 7 had not been set, the DB3: would have + been DT3: for a DECtape. The next eight lines are output + by the KL initialization program. They give the version of + KLINIT that is running and tell you that the KL10 microcode + was successfully loaded, the cache was enabled, external + memory was configured, and that the standard bootstrap + program for the TOPS-10 monitor was loaded and started. + (The loading of the TOPS-10 monitor is discussed in Section + 3.3.) + + If, in the previous example, you had also set switches 1 + and 2 on, the console output would have been as follows: + + RSX-20F V006A 0:16 21-JUN-76 + + [SY0: REDIRECTED TO DB3:] + [DB3: MOUNTED] + KLI -- VERSION V002E RUNNING + KLI -- ENTER DIALOG [NO,YES,EXIT,BOOT]? + KLI> + + Switches 1 and 2 set on specify that you wish to enter the + KL initialization program (KLINIT) operator dialogue. + KLINIT has just asked you the first question and is waiting + for an answer. When you have answered all the applicable + questions in the dialogue, the last message issued will be: + + KLI -- BOOTSTRAP LOADED AND STARTED + + as in the previous example. + + (For a complete description of the KLINIT dialogue + GET NEW MONITOR Page 14-8 ___ ___ _______ + + + messages, and examples, refer to Appendix C of the KL + Series Operator's Guide.) + + Step B2: Loading The Central Processor (TOPS-10 Monitor) ____ ___ _______ ___ _______ _________ ________ ________ + + When the front-end processor has been loaded using any one + of the three methods described in Section 3.2, the system + informs you: + + KLI -- BOOTSTRAP LOADED AND STARTED + + The actual bootstrap program that has been loaded depends + upon the method of loading the front end. + + If you used the DISK load, DECTAPE load, or the SW/REG load + with switches 1 and 2 off, you will have loaded the + bootstrap program found in the file BOOT.EXB. This would + usually be BOOTS, a program to load the monitor from a disk + pack. + + If you had used the KLINIT dialog to specify a non-default + BOOT file, you could have loaded a program like BOOT, which + will load the monitor from magnetic tape. + + If you are loading the monitor from disk, follow Situation + A. If you are loading the monitor from magtape, follow + Situation B. + + Situation A: Loading TOPS-10 from Disk _________ __ _______ _______ ____ ____ + + In response to the message: + + KLI -- BOOTSTRAP LOADED AND STARTED + + you can press the carriage return key and load the default + monitor from the disk file SYSTEM.EXE or you can specify + another file such as: + + DSKB:TSTSYS.EXE + + and load a different monitor. + + When the TOPS-10 monitor is loaded, it will enter into an + initialization dialogue with you to determine start-up + options and conditions. These are covered in Step C1. + + Situation B: Loading TOPS-10 from Magnetic Tape _________ __ _______ _______ ____ ________ ____ + + In order to load the TOPS-10 monitor from a magnetic tape, + the following prerequisites must be met: + + 1. The magnetic tape containing the monitor should be + mounted on drive 0. If this is not possible, mount it + on any drive but make sure that all other tape drives + are set OFFLINE. + + 2. The bootstrap program to load a monitor from magnetic + tape, BOOTM, must reside on the front-end load device; + disk or DECtape. + + 3. Load the console front end via the SW/REG load + procedure. (Situation C) with at least bits 0, 1, and + 2 set ON. This will allow you to use the KLINIT + dialog. + GET NEW MONITOR Page 14-9 ___ ___ _______ + + + 4. When KLINIT prompts you with: + + KLI -- LOAD KL BOOTSTRAP[YES,NO,filename]? + KLI> + + answer with the name of the file containing the + magnetic tape bootstrap. For example, if BOOTM was in + the file BOOTM.EXB, respond with: + + KLI>BOOTM.EXB + + KLINIT will load BOOTM, give you the message: + + KLI -- BOOTSTRAP LOADED AND STARTED + + and you would then be under control of the bootstrap + program. When BOOTM outputs its prompt characters: + + BTM> + + you can give the file specification for the monitor you + want to load, such as: + + BTM>DSKB:MAGSYS.EXE[1,4] + + or you can simply give a carriage return to get the + default file, which is DSKB: SYSTEM.EXE[1,4] from the + same magnetic tape. + + When the TOPS-10 monitor is loaded, it enters into an + initialization dialogue with the operator to determine + the start-up options and conditions. These are covered + in Step C1. + + STEP C1: TOPS-10 Initialization Dialogue ____ ___ _______ ______________ ________ + + When the TOPS-10 monitor is loaded, the system checks to + see that the monitor and processor are compatible. If they + are not, the following error message is issued: + + ?THIS MONITOR WAS BUILT FOR A xxxxxx + AND WILL NOT RUN PROPERLY ON A yyyyyy. + + where xxxxxx and yyyyyy can be KA10, KI10 or KL10. If this + message persists, the system administrator should review + the monitor generation procedure in the Software Notebooks. + + If the load time diagnostic program SYSCHK was included in + the system software at monitor generation time (determined + during the MONGEN dialogue), the system will prompt with: + + SYSCHK (N,Y): + + A response of Y runs a 5 second diagnostic program that + ensures the accessibility of all configured memory and + system devices. A reply of N or a carriage return skips + the diagnostic. + + The system then types the monitor name, date and version + number; for example: + + ABC123 KL10 SYS#1234 03-1-77 + + When the system prompts: + GET NEW MONITOR Page 14-10 ___ ___ _______ + + + WHY RELOAD: + + reply with one of the following acceptable answers: + + OPR NXM CM + PARITY HALT SA + POWER LOOP NEW + STATIC HUNG SCHED + HARDWARE PM OTHER + + If you do not reply within 60 seconds, OTHER is assumed. + (Refer to Chapter 14 for the meanings and usage of the + above replies.) The reply is stored in the system error + file (ERROR.SYS) and can be retrieved at a later time using + the SYSERR program. For example, a reply of: + + WHY RELOAD:SCHED + + will record that this particular monitor load was a + scheduled reload. + + When the system prompts: + + DATE: + + enter the numeric day and alphabetic month, in either + order. The month may be abbreviated to any point where it + is still unique. The year is optional. If entered, it + must be either the full four digits or the last two. If + the year is not entered, it is assumed to be the same as in + the monitor creation date. If, for example, the monitor + creation date was June 21, 1976, any of the following + replies would be recorded as September 8, 1976. + + DATE:SEP 8 1976 + DATE:S 8 76 + DATE:8 SEP + + When the system prompts: + + TIME: + + enter a 4 digit time based on a 24-hour clock. For + example, + + TIME:2015 + + represents 8:15 PM. + + When the system prompts: + + STARTUP OPTION: + + reply with one of the following: + + QUICK REFRESH LONG + GO UNITED NOINITIA + DESTROY CHANGE + + A complete description of each startup option is contained + in Chapter 16. The usual operator's reply is GO to start + the system with a minumim amount of dialogue or QUICK to + start the system immediately without changing any + parameters. + GET NEW MONITOR Page 14-11 ___ ___ _______ + + + The monitor is now ready for timesharing. INITIA is + brought up automatically on systems with OPSER and an + automatic restart file. + + If you have a KA10 system, set the NXM switch OFF unless + you are debugging and prefer to have the machine stop and + display the memory address when non-existent memory is + referenced. + + + + + + + + + + + + + CHAPTER 15 + + COPY NEW MONITOR TO SYS ____ ___ _______ __ ___ + + + +You should now copy the new monitor to SYS for READIN with BOOTS from +disk. + + .COPY SYS:SYSTEM.EXE = 6.03 EXE + + + + + + + + + + + + + CHAPTER 16 + + ONCE DIALOGUE ____ ________ + + + +In most instances, you should start your monitor with the GO, NOINITIA +or QUICK STARTUP Option. The STARTUP Options are a portion of the +ONCE dialogue, which is described in this chapter. + + + +16.1 INTRODUCTION ____________ + + +The ONCE-Only dialogue (Version 662) is an interactive program used by +the operator at system startup to set or alter a number of important +system parameters. These parameters include the date, time of day, +and most of the disk file structure information. + +You respond to a series of questions asked during the ONCE-Only +dialogue by typing your responses, one at a time, in conversational +mode. + +Before starting the system you should: + + 1. Read this chapter to acquaint yourself with the current + version of the ONCE-Only dialogue format. + + 2. Decide which parameters you wish to set or alter when the + system is started. + + 3. Be prepared to answer the required ONCE-Only dialogue + questions by familiarizing yourself with your installation's + configuration and the content and format of individual + questions. + +The 6.03 version of the ONCE-Only dialogue permits you to answer only +those questions directly related to the parameters that you wish to +define or alter in some way. The rest of the parameters are +automatically set according to a DEC-supplied or an +installation-defined standard. (Some parameter defaults can be +modified by the system programmer at individual installations during +the MONGEN dialogue program.) (Refer to Chapter 8 for a description +of MONGEN.) + + + +16.1.1 Summary of STARTUP Options _______ __ _______ _______ + +You have a choice of eight STARTUP Options. They are summarized here +and then described in the remainder of this chapter. + + QUICK To start the system quickly without changing any + parameters. (Refer to Section 16.2.) + ONCE DIALOGUE Page 16-2 ____ ________ + + + NOINITIA To start the system quickly without setting any + new parameters and without running INITIA. (Refer + to Section 16.2.) + + GO To check to see if everything is in order and to + start the system with a minimum of dialogue. + (Refer to Section 16.3.) + + DESTROY To automatically restructure and refresh all disks + according to a predetermined set of standards. + (Refer to Section 16.4.) + + REFRESH To explicitly refresh selected file structures + without changing other system parameters. (Refer + to Section 16.5.) + + UNITID To change selected unit IDs without changing other + system parameters. (Refer to Section 16.6.) + + CHANGE To explicitly set or change selected file + structure parameters. (Refer to Section 16.7.) + + LONG To explicitly set all parameters and restructure + the file system in a non-standard way. (Refer to + Section 16.8.) + +You should select the LONG STARTUP Option only if there is no other +alternative. You are encouraged to use one or more of the other seven +STARTUP Options (the simplest combination for their purposes), and to +accept the system standard values whenever possible. Note that the +STARTUP OPTION: question is repeated after you define some of the +parameters. This permits you to define a second set of parameters +(e.g., DESTROY, REFRESH, UNITID, or CHANGE) or to start the system +(QUICK or GO). + +The first eight steps described in Section 16.2.2 are common to all +system startups regardless of which option you choose. You must +perform these steps correctly before the ONCE-only dialogue asks you +for the STARTUP Option. The first eight steps are listed in Section +16.2.2 as they apply to all STARTUP Options. + + + +16.1.2 Special Considerations _______ ______________ + +The software supports the KA10, KI10, and KL10 processors. In +general, the procedures are the same for all systems. The primary +difference between the KA10 and the KI10 is the physical layout of the +console. Where the KA10 console has rocker switches, the KI10 console +has lighted pushbutton switches but the switch functions are the same. +The instructions in this document use the following conventions when +referring to the ON and OFF positions of the switches: + + KA10 Console KI10 Console + ------------ ------------ + +Switch ON Front (or bottom)of Lighted + rocker switch is + pressed. + +Switch OFF Back (or top) of Not Lighted + rocker switch is + pressed. + ONCE DIALOGUE Page 16-3 ____ ________ + + +In addition, the following special steps should be performed with a +KI10 system before beginning the READIN procedure. + + 1. Check to see that the MAINT light is OFF. If it is not, + check that the following switches are OFF: + + PARITY STOP + FM MANUAL + MEM OVERLAP DIS + MARGIN ENABLE + SINGLE PULSE + SINGLE INSTRUCTION + + 2. Make sure that the DATA and ADDRESS switches are operating + properly. That is, when the switch is pressed the indicator + is turned either off or on, the opposite to what it had been. + If they do not work properly, make sure that the CONSOLE LOCK + and the CONSOLE DATA LOCK switches are OFF. + + 3. Under normal circumstances systems with a KI10 processor + should be run with the switches set as follows: + + a. NXM STOP switch OFF + + b. EXEC PAGING switch ON + + c. USER PAGING switch OFF + (These paging switches should be set so that the + addresses examined by the EXAMINE switch are monitor + (EXEC mode) addresses instead of user program (USER mode) + addresses.) + +The NXM FLAG and processor clock PIA indicators are located on +different bays. + + 1. On the KA10 the NXM FLAG and processor clock PIA indicators + (PIA33, PIA34, and PIA35) are located on Bay 1, the left-most + bay, farthest from the console. They are in the second row + of lights, below the register labeled CPA. + + 2. On the KI10, the NXM FLAG and processor clock PIA indicators + (APR CLK PIA) are located on Bay 3, the same bay as the + console. They are in the bottom row of lights. + + + + +16.1.3 Special Multiprocessing Considerations _______ _______________ ______________ + +Under ordinary circumstances, multiprocessing systems do not require +any special startup procedures. CPU1, the secondary processor, waits +and automatically starts after CPU0, the primary processor, is +started. However, if the system is started after a crash, then the +procedure depends upon which CPU crashed. + + + +16.1.4 Conventions Used in this Chapter ___________ ____ __ ____ _______ + + 1. Errors messages + + ONCE-Only error messages are preceded by either a question + mark (?) or a percent sign (%). Messages preceded by a + question mark are fatal unless corrective action is taken. + ONCE DIALOGUE Page 16-4 ____ ________ + + + Messages preceded by a percent sign are warnings. + + 2. Carriage Return + + indicates that you should type a carriage return. + Because most operator typeins must be terminated by carriage + return, is used to indicate a blank line and for + emphasis when other terminators, such as altmode, are also + possible. + + 3. File Structure + + STR is an abbreviation for file structure. + + ONCE DIALOGUE Page 16-5 ____ ________ +STARTUP OPTION: QUICK aND NOINITIA + + +16.2 STARTUP OPTION: QUICK aND NOINITIA _______ _______ _____ ___ ________ + +The QUICK option enables you to start up the system quickly, without +altering any system parameters and without any further dialogue. +After listing off-line disk units, the system starts running. + +This option is recommended for startups when speed is important, when +file structure organization and other parameters need not be altered, +or after you have set selected parameters by using another option, and +you are ready to start the system. + +The NOINITIA option is identical to QUICK, except that INITIA is not +run. + +Note that if ONCE-Only encounters problems in trying to start the +monitor, the LONG dialogue is automatically invoked. (Refer to +Section 16.10 for error messages and to Section 16.8.3 for a +description of the LONG dialogue questions.) + + + +16.2.1 Frequency _________ + +The QUICK (or GO) option is invoked everytime the monitor is reloaded +into the machine. + + + +16.2.2 Summary of Steps _______ __ _____ + + 1. You get the monitor with BOOTM or BOOTS. (Refer to Chapters + 2 and 3.) + + 2. The system checks to see that the monitor and processor are + compatible. If not, an error message is typed and the + program halts. + + 3. The system asks if you wish to run the loadtime diagnostic + program, SYSCHK. + + SYSCHK(N,Y): + + Note that this is asked only if the SYSCHK program has been + included as a part of the system software (as determined by + the system programmer during the MONGEN dialogue, refer to + Chapter 8). + + USER RESPONSE: N OR to skip the diagnostic. + + 4. The system types the name of the monitor and creation date; + for example: + + 6.03 SYS #160 3-17-77 + + 5. The system asks for the reason for the reload. + + WHY RELOAD: + + USER RESPONSE: NEW + + You answer with one of the following acceptable answers + depending on your reason. (Refer to Section 16.9 for an + explanation of these answers.) + ONCE DIALOGUE Page 16-6 ____ ________ +STARTUP OPTION: QUICK aND NOINITIA + + + OPR LOOP + PARITY HUNG + POWER PM + STATIC CM + HARDWARE SA + NXM NEW + HALT SCHED + OTHER + + 6. The system asks for the date. + + DATE: + + USER RESPONSE: MAR 17 1977 + + You type the date as the name of the month (January-December) + and the numerical day of the month (1-31) in any order. (The + name of the month may be shortened as long as the + abbreviation is unique.) The year is optional. If included, + the year must be typed as a 4-digit number (1977) or a + 2-digit abbreviation (77) following the month and day. If + omitted, the year is assumed to be the same as the year the + monitor was created. Examples of acceptable dates are: + + MARCH 17 1977 + MAR 17 + 17 MAR + + 7. The system asks for the time. + + TIME: + + USER RESPONSE:0843 + + You type the time based on a 24-hour clock, e.g., + 0843=8:43 A.M. and 1345=1:45 P.M. + + 8. The system checks to see if all of memory is accessible. + + 9. ONCE asks for your choice of + + STARTUP OPTION: + + USER RESPONSE: QUICK + + For a description of the other responses, refer to the list + below: + + GO Section 16.3 + DESTROY Section 16.4 + REFRESH Section 16.5 + UNITID Section 16.6 + CHANGE Section 16.7 + LONG Section 16.8 + + 10. ONCE lists off-line units; for example: + + %xxxx IS OFF-LINE + %yyyy IS OFF-LINE + + (Note that you have no opportunity to change the status of + these units.) + ONCE DIALOGUE Page 16-7 ____ ________ +STARTUP OPTION: QUICK aND NOINITIA + + + 11. ONCE checks to see if there are controllers off line or if + any units are write locked. If so, messages are transmitted + to the operator. Otherwise, if everything is in order, the + monitor starts running the null job and initiates + timesharing, usually via INITIA, OPSER, and an automatic + STARTUP file. If you typed NOINITIA, a . is printed and you + must log in. Otherwise, you are automatically logged in. + + + + +16.2.3 Examples ________ + +Example 1 + + SYSCHK (N,Y): Y + + MEMORY MAP= + FROM TO SIZE/K + 000000 537777 176 + CONTROLLER MTA IS UNACCESSIBLE. + + 6.03 SYSTEM #160 4-12-77 + WHY RELOAD: OTHER ;MANUAL EXAMPLE + DATE: 4 MAY + TIME: 0045 + + STARTUP OPTION: QUICK + + %DPA6 IS OFF-LINE + + %DPB0 IS OFF-LINE + + 6.03 SYSTEM #160 4-12-77 + DSKN: System #160 Initia types + . the text contained + . in STR.TXT. + . + .LOGIN[1,2] ;This is typed automatically + .R OPSER + [OPRPAF PROCESSING AUTO COMMAND FILE] + 00:45:24(0) + . + 00:45:24(0) + . + 00:45:32(0) + . + 00:45:39(B\L1) + + + +Example 2 + + BOOTS + + 6.03 + SYSCHK (N,Y): N + + 6.03 SYSTEM #160 4-19-77 + WHY RELOAD:NEW + DATE: APRIL 28 + TIME: 1100 + ONCE DIALOGUE Page 16-8 ____ ________ +STARTUP OPTION: QUICK aND NOINITIA + + + STARTUP OPTION: QUICK + + %DPA4 IS OFF-LINE + + %DPA5 IS OFF-LINE + + %DPA6 IS OFF-LINE + + 6.03 SYSTEM #160 11:00:19 CTY + + .LOGIN[1,2] + .R OPSER + [OPRPAF PROCESSING AUTO COMMAND FILE] + . + . + . + + +Example 3 + + SYSCHK (N,Y): N + + 6.03 SYSTEM #160 4-19-77 + WHY RELOAD: NEW + DATE: APRIL 20 + TIME: 700 + + STARTUP OPTION: NOINITIA + + . + + + +16.3 STARTUP OPTION: GO _______ _______ __ + +When you specify the GO option, ONCE-Only checks to see if everything +is in order, and starts the system with a minimum of dialogue. After +you respond to questions asking if specific off-line units are to be +on line, off line, or down, the system is started. + +Note that if ONCE-Only encounters problems in trying to start the +monitor, then the LONG dialogue is automatically invoked. Refer to +Section 16.10 for error messages and to Section 16.8.3 for a +description of the LONG dialogue questions. + + + +16.3.1 Frequency _________ + +The GO (or QUICK) option must be invoked every time the monitor is +reloaded into the machine. + + + +16.3.2 Summary of Steps _______ __ _____ + +Steps 1 through 8 are described in Section 16.2.2, because they are +common to all STARTUP Options. + + 9. ONCE asks for your choice of + + STARTUP OPTION: + ONCE DIALOGUE Page 16-9 ____ ________ +STARTUP OPTION: GO + + + USER RESPONSE: GO + + 10. ONCE lists off-line units, if any, and then asks if off-line + units are to remain off line or not. + + %xxxx IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? + (TYPE #) + + USER RESPONSE: 1,2, or 3 + + 11. ONCE checks to see if there are any off-line controllers or + if there are any write-locked units. If so, messages are + transmitted to the operator. Otherwise, if everything is in + order, the monitor starts running the null job and initiates + timesharing, usually via INITIA, OPSER, and an automatic + startup file. + + + +16.3.3 Examples ________ + +Example 1 + + 6.03 SYSTEM #160 4-2-77 + WHY RELOAD: OTHER ;EXAMPLE + DATE: 4 MAY + TIME: 52 + + STARTUP OPTION: GO + + %DPA6 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 3 + + %DPB0 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + 6.03 SYSTEM #160 00:52:46 CTY + .R OPSER + [OPRPAF PROCESSING AUTO COMMAND FILE] + 00:52:48(0) + . + 00:52:49(0) + . + 00:52:57(0) + . + + + +Example 2 + + BOOTS + + 6.03 + SYSCHK (N,Y): + + 6.03 SYSTEM #160 12-19-77 + WHY RELOAD: SCHED + DATE: D 28 + ONCE DIALOGUE Page 16-10 ____ ________ +STARTUP OPTION: GO + + + TIME: 1120 + + STARTUP OPTION: GO + + %DPA4 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + %DPA5 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + %DPA6 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 1 + + 6.03 SYSTEM #160 11-21-04 CTY + .R OPSER + [OPRPAF PROCESSING AUTO COMMAND FILE] + . + . + . + + + +16.4 STARTUP OPTION: DESTROY _______ _______ _______ + +The DESTROY option automatically restructures and refreshes all file +structures according to a predetermined set of standards. A minimum +of dialogue is encountered, because the file structure parameters are +determined by the system programmer during the MONGEN dialogue +program. (Refer to Chapter 8.) + +The DESTROY option, as the name implies, destroys all existing file +structures, then restructures and refreshes the disk units as directed +by MONGEN. If the system programmer has not altered the values of the +MONGEN symbols, the DESTROY option organizes the file system according +to the "symbol, values" specified by the DEC-supplied software; that +is, all fixed head disks are in the first file structure (called +DSKA), and all disk pack units are in the second file structure +(called DSKB), with 200K of swapping space allocated on each of the +fixed head units, and on the first disk pack unit (as backup). (Refer +to Chapter 8 for a description of the HDWGEN decimal and octal +symbol-values that affect file structure organization.) + +The DESTROY option is recommended for new installations starting up +their systems for the first time and for existing installations using +new disk units for the first time. + + + +16.4.1 Frequency _________ + +After the file structure parameters have been established, they are +written onto each structure in two places called the HOME blocks. +Once this is done, it need not be done again. When the monitor is +reloaded, it reads the HOME blocks and sets up the disk parameters +automatically. + ONCE DIALOGUE Page 16-11 ____ ________ +STARTUP OPTION: DESTROY + + +16.4.2 Summary of Steps _______ __ _____ + +Steps 1 through 8 are described in Section 16.2.2, because they are +common to all STARTUP Options. + + 9. ONCE asks for your choice of + + STARTUP OPTION: + + USER RESPONSE: DESTROY + + Existing structures are destroyed, new structures are + created, and all disks are refreshed according to a + predetermined set of values. + + A warning message is typed and confirmation is requested. + + %WARNING-ALL STRS WILL BE REFRESHED. + PROCEED? (Y or ) + + USER RESPONSE: Y + + When finished the following is typed + + HOME BLOCKS WRITTEN ON ALL UNITS + START SYSTEM? (Y or ) + + USER RESPONSE: Y or + + An answer of returns control to the STARTUP OPTION + question again. A YES answer continues with step 10. + + 10. ONCE repeats the STARTUP question, to which you should + respond QUICK (see Example 1). ONCE asks you to login. + + TO AUTOMATICALLY LOGIN UNDER [1,2] TYPE LOGIN + + USER RESPONSE: LOGIN + + 11. ONCE starts running the null job and initiates timesharing. + + 12. If a new monitor is being generated for the first time, you + should return to Chapter 4. + + + +16.4.3 Example _______ + +BOOTS + + 6.03 + SYSCHK (N,Y): + + 6.03 SYSTEM #160 12-13-77 + WHY RELOAD: SA + DATE: 26 DEC + TIME: 1300 + + STARTUP OPTION: DESTROY + %WARNING-ALL STRS WILL BE REFRESHED. + PROCEED?(Y OR ) + + %FHA1 IS OFF-LINE + ONCE DIALOGUE Page 16-12 ____ ________ +STARTUP OPTION: DESTROY + + + %DPA0 IS OFF-LINE + + HOME BLOCKS WRITTEN ON ALL UNITS + START SYSTEM? (Y OR )Y + + STARTUP OPTION: Q + TO AUTOMATICALLY LOG-IN UNDER [1,2] TYPE "LOGIN" + LOGIN + . + . + . + + + +16.5 STARTUP OPTION: REFRESH _______ _______ _______ + +The REFRESH option allows you to restore certain file structures to +their initial condition (i.e., refresh them) without changing other +system parameters. (Note that only HOME.SYS is required to describe +the file structure. Once these have been defined via DESTROY or LONG, +refreshing individual structures is very simple.) + + + +16.5.1 Frequency _________ + +Ordinarily, structures need refreshing every two to three months. +Refreshing may be required when: + + 1. Disks are full. When you wish to retain only recently + accessed files, you save recently accessed files with BACKUP + before refreshing and then restore them (with BACKUP) after + refreshing. + + 2. System crashes have left a number of blocks not allocated to + any file. Refer to the DSKRAT documentation for instructions + on determining the number of lost blocks and recovering them + without the need for refreshing the file structure. + + 3. Fragmentation of free blocks results in inefficient use of + disk space, i.e., when free blocks on the disk are so + scattered that long sequentially written files are using + extended RIBs. (Refer to the DSKLST.RNO specification for + information on interpreting the DSKLST output.) + + + + +16.5.2 Summary of Steps _______ __ _____ + +Steps 1 through 8 are described in Section 16.2.2 because they are +common to all STARTUP Options. + + 9. ONCE asks for your choice of + + STARTUP OPTION: + + USER RESPONSE: REFRESH + + 10. ONCE lists any off-line units and asks you to indicate which + off-line units are to remain off-line. + + %xxxx IS OFF-LINE + ONCE DIALOGUE Page 16-13 ____ ________ +STARTUP OPTION: REFRESH + + + DO YOU WANT IT TO BE 1)ON-LINE, 2) OFF-LINE, OR 3)DOWN? + (TYPE #) + + USER RESPONSE: 1,2, or 3 + + 11. ONCE checks to see if there are any off-line controllers or + if there are any write-locked units. If so, messages are + transmitted to the operator. + + 12. ONCE asks for the structures to be refreshed. + + TYPE STR NAME TO BE REFRESHED (CR IF NONE, ALL IF ALL) + + USER RESPONSE: ALL or individual structure name. + + When the structures are refreshed, control returns to the + STARTUP OPTION question. You can enter another STARTUP + Option (such as DESTROY, UNITID, CHANGE, or LONG) or you can + start the system (QUICK or GO). + + + +16.5.3 Examples ________ + +Example 1 + + BOOTS + + 6.03 + SYSCHK (N,Y): + + 6.03 SYSTEM #160 12-19-77 + WHY RELOAD: NEW + DATE: DEC 28 + TIME: 1250 + + STARTUP OPTION: REFRESH + TYPE STR NAME TO BE REFRESHED (CR IF NONE, ALL IF ALL) + DSKH + TYPE STR NAME TO BE REFRESHED(CR IF NONE, ALL IF ALL) + DSKX + TYPE STR NAME TO BE REFRESHED(CR IF NONE, ALL IF ALL) + DSKX + TYPE STR NAME TO BE REFRESHED(CR IF NONE, ALL IF ALL) + + STARTUP OPTION: QUICK + TO AUTOMATICALLY LOG-IN UNDER [1,2] TYPE "LOGIN" + LOGIN + . + . + + + +Example 2 + + SYSCHK (N,Y):N + + 6.03 DUAL CPU 11-21-77 + WHY RELOAD: SA + DATE: 4 DEC + TIME: 1050 + + STARTUP OPTION: REF + ONCE DIALOGUE Page 16-14 ____ ________ +STARTUP OPTION: REFRESH + + + %DPA6 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + %DPB0 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + %NEED REFRESHING: + DSKA,DSKB,DSKC + TYPE STR NAME TO BE REFRESHED(CR IF NONE, ALL IF ALL) + DSKA + TYPE STR NAME TO BE REFRESHED(CR IF NONE, ALL IF ALL) + + STARTUP OPTION: Q + TO AUTOMATICALLY LOG-IN UNDER [1,2] TYPE "LOGIN" + LOGIN + + 6.03 DUAL CPU 1:06:02 + + .LOG + + .INITIA + + 6.03 DUAL CPU 01:06:14 CTY + .R OPSER + [OPRPAF PROCESSING AUTO COMMAND FILE] + . + . + . + + + +16.6 STARTUP OPTION: UNITID _______ _______ ______ + +The UNITID option allows you to change selected unit IDs, without +changing any other parameters. + + + +16.6.1 Frequency _________ + +After the file structure parameters have been established, they are +written onto each structure in two places called the HOME blocks. +Once this is done, it need not be done again. When the system is +reloaded, the monitor reads the HOME blocks and sets up the disk +parameters automatically. + + + +16.6.2 Summary of Steps _______ __ _____ + +Steps 1 through 8 are described in Section 16.2.2, because they are +common to all STARTUP Options. + + 9. ONCE asks for your choice of + + STARTUP OPTION: + + USER RESPONSE: UNITID + ONCE DIALOGUE Page 16-15 ____ ________ +STARTUP OPTION: UNITID + + + 10. ONCE lists any off-line units and asks you to indicate which + off-line units are to remain off-line. + + %xxxx IS OFF-LINE + + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? + (TYPE #) + + USER RESPONSE: 1,2, or 3 + + ONCE checks to see if there are any off-line controllers or + if there are any write-locked units. If so, messages are + transmitted to the operator. + + 11. ONCE asks if there are any physical unit names and unit IDs + to be changed. + + CHANGE ALL UNIT ID's (Y OR ) + + USER RESPONSE: Y OR + + When you specify Y, ONCE lists each unit and asks for the + I.D.: + + AFTER EACH UNIT NAME, TYPE THE I.D. + + xxx(aaaa): + + USER RESPONSE: ABCD + + yyyy(bbbb) + + USER RESPONSE: EFGH + + zzzz(cccc): + + USER RESPONSE: IJKL + + When you respond with , ONCE asks, for each unit, the + unit name and its I.D. + + TYPE UNIT NAME, A COMMA, AND NEW UNIT ID FOR EACH + DESIRED UNIT. + (EXTRA WHEN THROUGH) + + USER RESPONSE: xxxx, ABCD + yyyy, EFGH + + + 12. If HOME blocks are to be written, ONCE asks for the physical + unit and then indicates when HOME blocks are written. + + TYPE PHYSICAL UNIT TO WRITE HOME BLOCKS (EXTRA CR + WHEN THROUGH) + (CR IF NONE, ALL IF ALL ;"ALL" IS NORMAL CASE) + + USER RESPONSE: ALL + + HOME BLOCKS WRITTEN + + When HOME blocks are written, control returns to the STARTUP + Option question. You can enter another option (such as + DESTROY, UNITID, CHANGE, or LONG) or you can start the system + ONCE DIALOGUE Page 16-16 ____ ________ +STARTUP OPTION: UNITID + + + (QUICK or GO). + + + +16.6.3 Examples ________ + +Example 1 + + BOOTS + + 6.03 + SYSCHK (N,Y): + + 6.03 SYSTEM #160 4-19-77 + DATE: MAY 28 + TIME: 1130 + + STARTUP OPTION: UNITID + CHANGE ALL UNIT ID'S? (Y OR ) + + TYPE UNIT NAME, A COMMA, AND NEW UNIT ID FOR EACH DESIRED UNIT. + (EXTRA WHEN THROUGH) + + DPA4,UNIT4 + + DPA5,UNIT5 + + TYPE PHYSICAL UNITS TO WRITE HOME BLOCKS (EXTRA CR WHEN THROUGH) + (CR IF NONE, ALL IF ALL ;"ALL" IS NORMAL CASE) + DPA4 + DPA5 + + HOME BLOCKS WRITTEN + + STARTUP OPTION: Q + + 6.03 SYSTEM #160 11:32:43 CTY + .R OPSER + [OPRPAF PROCESSING AUTO COMMAND FILE] + . + . + . + + + +Example 2 + + SYSCHK (N,Y): N + + 6.03 SYSTEM #160 12-02-77 + WHY RELOAD: SA + DATE: 4 DEC + TIME: 55 + + STARTUP OPTION: UNITID + + %DPA6 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + %DPB0 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + ONCE DIALOGUE Page 16-17 ____ ________ +STARTUP OPTION: UNITID + + + 2 + CHANGE ALL UNIT ID'S? (Y OF )Y + AFTER EACH UNIT NAME, TYPE THE I.D. + + FHA0(GLZX):XLZG + + FHA1(XZLG):GLZX + + DPA0(RP03A):RP03A1 + + DPA1(RP03B):RP03B1 + + DPA2(3RPXYZ):RP03C1 + + DPA3(2RP023): + DPA4(2RP044): + DPA5(2RP042): + DPB1(2RP004): + + TYPE PHYSICAL UNITS TO WRITE HOME BLOCKS (EXTRA CR WHEN THROUGH) + (CR IF NONE, ALL IF ALL ;"ALL" IS NORMAL CASE) + ALL + + HOME BLOCKS WRITTEN + + STARTUP OPTION: UNITID + + %DPA6 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + %DPB0 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + CHANGE ALL UNIT ID'S (Y OR ) + + TYPE UNIT NAME, A COMMA, AND NEW UNIT ID FOR EACH DESIRED UNIT. + (EXTRA WHEN THROUGH) + FHA0,FHARD1 + FHA1,SAM + + TYPE PHYSICAL UNIT TO WRITE HOME BLOCKS + (CR IF NONE, ALL IF ALL ;"ALL" IS NORMAL CASE) + + BEFORE "HOME" BLOCKS ARE WRITTEN + + TYPE STR NAME FOR A LIST OF ITS PARAMETERS(CR IF NONE, ALL IF + ALL) + + TYPE PHYSICAL UNIT NAME TO LIST ITS PARAMETERS(CR IF NONE, ALL IF + ALL) + + DO YOU WANT TO CHANGE ANY DISK PARAMETERS(CR IF NO) + + TYPE PHYSICAL UNIT TO WRITE HOME BLOCKS + (CR IF NONE, ALL IF ALL ;"ALL" IS NORMAL CASE) + ALL + + HOME BLOCKS WRITTEN + + STARTUP OPTION: GO + ONCE DIALOGUE Page 16-18 ____ ________ +STARTUP OPTION: UNITID + + + . + . + . + + + +16.7 STARTUP OPTION: CHANGE _______ _______ ______ + +The CHANGE option allows you to set or change selected parameters on +specified structures or units. The parameters are changed, sometimes +causing file structures to be refreshed, but no restructuring +(creating or deleting) of structures is performed. This option asks +you questions about the following: + + 1. File structure parameters + + 2. Physical unit parameters + + 3. Active swapping list + + 4. System search list + +Note that if any changes require HOME blocks to be written or disks to +be refreshed, you are informed and asked for verification. + + + +16.7.1 Frequency _________ + +After the file structure parameters have been established, they are +written onto each structure in two places called the HOME blocks. +Once this is completed, it need not be done again. When the monitor +is reloaded, the monitor reads the HOME blocks and sets up the disk +parameters automatically. + + + +16.7.2 Summary of Steps _______ __ _____ + +Steps 1 through 8 are described in Section 16.2.2 because they are +common to all STARTUP Options. + + 9. ONCE asks for your choice of + + STARTUP OPTION: + + USER RESPONSE: CHANGE + + 10. ONCE lists off-line units, if any, and then asks if off-line + units are to remain off-line or not. + + %xxxx IS OFF-LINE + DO YOU WANT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? + (TYPE #) + + ONCE checks to see if there are any off-line controllers or + if there are any write-locked units. If so, appropriate + messages are transmitted to the operator terminal. + + 11. ONCE asks questions about file structure parameters, physical + unit parameters, the active swapping list, and the system + search list. You can accept the standard default answers by + responding to each question with a carriage return. (See + ONCE DIALOGUE Page 16-19 ____ ________ +STARTUP OPTION: CHANGE + + + example 1 in Section 16.7.3.) + + Or, you can answer the questions individually, thereby + setting parameters in a non-standard way. If you choose to + set the parameters in a non-standard way, the appropriate + subset of "long dialogue" questions is asked. (See examples + 2 and 3 in Section 16.7.3 and the description of the LONG + option, Section 16.8.2.) + + When the parameters have been set, control returns to the + STARTUP Option question. You can start the system via quick + or GO or continue with another option. + + + +16.7.3 Examples ________ + +Example 1 + + BOOTS + + 6.03 + SYSCHK (N,Y): + + 6.03 SYSTEM #160 12-19-77 + WHY RELOAD: NEW + DATE: DEC 28 + TIME: 1230 + + STARTUP OPTION: CHANGE + + %DPA4 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + %DPA5 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #9 + + 2 + + %DPA6 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + TYPE STR NAME TO CHANGE ITS PARAMETERS(CR IF NONE, ALL IF ALL) + + TYPE PHYSICAL UNIT NAME TO CHANGE ITS PARAMETERS(CR IF NONE, ALL + IF ALL) + + DO YOU WANT TO CHANGE THE ACTIVE SWAPPING LIST? + + DO YOU WANT TO CHANGE THE "SYS" SEARCH LIST? + + STARTUP OPTION: QUICK + . + . + . + + + +Example 2 + ONCE DIALOGUE Page 16-20 ____ ________ +STARTUP OPTION: CHANGE + + + BOOTS + + 6.03 + SYSCHK (N,Y): + + 6.03 SYSTEM #160 12-19-77 + DATE: DEC 28 + TIME: 1250 + + STARTUP OPTION: CHANGE + + TYPE STR NAME TO CHANGE ITS PARAMETERS(CR IF NONE, ALL IF ALL) + DSKX + + AFTER EACH PRINTING OF CURRENT VALUE, TYPE NEW VALUE OR CR + + PARAMETERS WHICH MAY BE CHANGED WITHOUT REFRESHING + # OF CONSECUTIVE BLOCKS TRIED FOR ON OUTPUT = 30 + MIN = 1 MAX = 80000 + + SUM OF BLOCKS GUARANTEED TO USERS = 0 + MIN = 0 MAX = 80000 + + # BLOCKS ALLOWED FOR OVERDRAW PER USER = 500 + MIN = 0 MAX = 80000 + 1000 + + PARAMETERS WHICH MAY NOT BE CHANGED WITHOUT REFRESHING + K FOR CRASH.SAV = 96 + MIN = 0 MAX = 256 + 0 + + BLOCKS PER CLUSTER = 5 + MIN = 1 MAX = 511 + + THEREFORE BITS PER CLUSTER ADR. = 13 + THEREFORE BLOCKS PER SUPER-CLUSTER = 5 + THEREFORE SUPER-CLUSTERS PER UNIT = 8000 + + BITS PER CLUSTER COUNT = 9 + MIN = 1 MAX = 18 + + THEREFORE BITS PER CHECKSUM = 14 + + TYPE STR NAME TO CHANGE ITS PARAMETERS(CR IF NONE, ALL IF ALL) + + TYPE PHYSICAL UNIT NAME TO CHANGE ITS PARAMETERS(CR IF NONE, ALL + IF ALL) + + DO YOU WNAT TO CHANGE THE ACTIVE SWAPPING LIST? + + DO YOU WANT TO CHANGE THE "SYS" SEARCH LIST? + + TYPE PHYSICAL UNIT TO WRITE HOME BLOCKS + (CR IF NONE, ALL IF ALL ;"ALL" IS NORMAL CASE) + DPA4 + DPA5 + + HOME BLOCKS WRITTEN + + %NEED REFRESHING: + DSKX + TYPE STR NAME TO BE REFRESHED(CR IF NONE, ALL IF ALL) + ONCE DIALOGUE Page 16-21 ____ ________ +STARTUP OPTION: CHANGE + + + DSKX + TYPE STR NAME TO BE REFRESHED(CR IF NONE, ALL IF ALL) + + STARTUP OPTION: Q + TO AUTOMATICALLY LOG-IN UNDER [1,2] TYPE "LOGIN" + + + +Example 3 + + SYSCHK (N,Y): Y + + MEMORY MAP = + FROM TO SIZE/K + 000000 537777 176 + CONTROLLER MTA IS UNACCESSIBLE + + 6.03 SYSTEM #160 12-02-77 + WHY RELOAD: OTHER ;ONCE EXAMPLE + DATE: 4 DEC 1977 + TIME: 46 + + STARTUP OPTION: CHANGE + + %DPA6 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + %DPB0 IS OFF-LINE + DO YOU WANT IT TO BE 1)ON-LINE, 2)OFF-LINE, OR 3)DOWN? (TYPE #) + + 2 + + TYPE STR NAME TO CHANGE ITS PARAMETERS (CR IF NONE, ALL IF ALL) + + DO YOU WANT TO CHANGE THE ACTIVE SWAPPING LIST? + Y + FOR EACH CLASS TYPED PHYSICAL UNIT NAMES(EXTRA CR WHEN DONE) + CLASS 0 + FHA0 + FHA1 + + CLASS 1 + DPA0 + + CLASS 2 + DPA0 + ?UNIT ALREADY IN ACTIVE SWAPPING LIST + DPB0 + ?UNIT HAS NO SPACE ALLOCATED FOR SWAPPING + + + DO YOU WANT TO CHANGE THE "SYS" SEARCH LIST? + Y + TYPE STR NAMES FOR "SYS" SEARCH LIST (EXTRA CR WHEN DONE) + DSKN + DSKA + DSKB + DSKC + + TYPE PHYSICAL UNIT TO WRITE HOME BLOCKS + (CR IF NONE, ALL IF ALL ;"ALL" IS NORMAL CASE) + ONCE DIALOGUE Page 16-22 ____ ________ +STARTUP OPTION: CHANGE + + + ALL + + HOME BLOCKS WRITTEN + + STARTUP OPTION: GO + + 6.03 SYSTEM #160 12-2-77 + .R OPSER + [OPRPAF PROCESSING AUTO COMMAND FILE] + 00:49:19(0) + . + 00:49:20(0) + . + 00:49:28(0) + + + +16.8 STARTUP OPTION: LONG _______ _______ ____ + +The LONG option allows you to explicitly set all system parameters, +and to refresh and restructure the entire file system in a +non-standard way. The entire "LONG dialogue", as described in Section +16.8.3, is invoked. Note that the exact sequence of operator dialogue +depends on your answers to the individual questions. That is, the +answers to certain questions cause ONCE-Only to branch in different +directions. Section 16.8.3 follows the most commonly encountered +path. + +If ONCE encounters problems in trying to start the monitor, the LONG +dialogue questions may be automatically invoked (with the QUICK and GO +options). + + + +16.8.1 Frequency _________ + +As stated in Section 16.1, you should choose the LONG option only when +no other option or combination of options will suffice. For new +systems, the preferred method is for you to specify the DESTROY +option, followed by the CHANGE option (for individual exceptions to +the standard). + + + +16.8.2 Example _______ + +This example assumes that you accept all system defaults, i.e., you +respond to all questions with a carriage return. (Section 16.8.3 +illustrates a more complex situation.) + + BOOTS + + 6.03 + SYSCHK (N,Y): + + 6.03 SYSTEM #160 3-19-77 + DATE: MAR 28 + TIME: 1255 + + STARTUP OPTION: LONG + + IN THE FOLLOWING DIALOG, ALL NUMBERS ARE DECIMAL. + TYPE IF OK, OR A NEW NUMBER TO CHANGE VALUE. + ONCE DIALOGUE Page 16-23 ____ ________ +STARTUP OPTION: LONG + + + # MONITOR BUFFERS = 6 + + + TYPE PHYSICAL UNIT NAME TO LIST # BAD REGIONS(CR IF NONE, ALL IF + ALL) + + + DSK FILE STRUCTURES(STRS): + DSKA:FHA0(XLZG),FHA1(GLZX) + DSKB:DPA1(ONC501),DPA0(ONC517) + DSKC:DPA2(RP03A) + DSKN:DPA3(2RP023) + DSKX:DPA4(ONC554),DPA4(ONC566) + DSKH:DPA6(2RP) + + UNITS IN ACTIVE SWAPPING LIST: + FHA0(0),FHA1(0) + + STRS IN "SYS" SEARCH LIST: + DSKA,DSKN,DSKB,DSKC + + TYPE STR NAME FOR A LIST OF ITS PARAMETERS(CR IF NONE, ALL IF + ALL) + + + TYPE PHYSICAL UNIT NAME TO LIST ITS PARAMETERS(CR IF NONE, ALL IF + ALL) + + DO YOU WANT TO CHANGE ANY DISK PARAMETERS?(CR IF NO) + + TYPE STR NAME TO BE REFRESHED(CR IF NONE, ALL IF ALL) + + STARTUP OPTION: QUICK + + 6.03 SYSTEM #160 12:56:33 CTY + DSKN: System #160 INITIA types the + . text found in + . STR.TXT. + . + + .LOGIN[1,2] ;This is typed + ;automatically. + .R OPSER + [OPRPAF PROCESSING AUTO COMMAND FILE] + . + . + . + + + +16.8.3 Complete Description of Each "Long Dialogue" Question ________ ___________ __ ____ _____ _________ ________ + + + + NOTE + + It is possible for an experienced + operator to stop the typeout of a + lengthy ONCE-Only question. When you + type a character during ONCE-only + typeout, a ^O is echoed and the + remainder of the question is not typed. + (The space character is recommended as + ONCE DIALOGUE Page 16-24 ____ ________ +STARTUP OPTION: LONG + + + the character for you to type to stop + output, because it is usually ignored as + input.) + + + + 1. Get the monitor from the disk with BOOTS or from magtape with + BOOTM. Refer to the earlier chapters of this manual. + + 2. The system compares the type of monitor (1040, 1050, 1055, + 1070, 1080, 1090) and the type of processor (KA10, KI10, or + KL10) for compatibility. If incompatible, the following + message is typed and the monitor halts. + + THIS MONITOR WAS BUILT FOR A (KA10, KI10, KL10) AND + WILL NOT RUN PROPERLY ON (KI10, KA10, KL10). + + 3. If the optional loadtime diagnostic SYSCHK is included in the + system software (determined by a system programmer during the + MONGEN dialogue), ONCE asks if you wish to run it at this + time + + SYSCHK (N,Y): + + USER RESPONSE: N or to skip the diagnostic + + The loadtime diagnostic SYSCHK is a 5-second program that + ensures the accessibility of memory and all devices on a + configuration. + + The system types the name of the monitor and the creation + date and asks for the reason for the reload. ONCE types + + 6.03 SYS #2 3-1-77 + + WHY RELOAD: + + You respond with one of the following acceptable answers or + an abbreviation that uniquely describes it: + + OPR + PARITY + POWER + STATIC + HARDWARE + NXM + HALT + LOOP + HUNG + PM + CM + SA + NEW + SCHED + OTHER + + (See Section 16.9 for a detailed explanation of the WHY + RELOAD: question.) + + 4. The system types the creation date and asks for today's date + and time. + + DATE: MAR 17 1977 + ONCE DIALOGUE Page 16-25 ____ ________ +STARTUP OPTION: LONG + + + Type the date as the name of the month (January - December) + and the numerical day of the month (1-31) in any order. (The + name of the month may be shortened as long as the + abbreviation is unique.) The year is optional. If included, + it must be a 4-digit number (1977) or a 2-digit (77) + abbreviation following the month and day. If omitted, the + creation date of the monitor is assumed. Examples of + acceptable input are: + + SEPTEMBER 17 1977 + SEPT 17 + 17 SEPT + S 17 + + If an incorrect format is detected, the ONCE-Only dialogue + reasks the question in more detail: + + PLEASE TYPE TODAY'S DATE AS MM-DD-YY: + + + NOTE + + It is very important that you type in the correct + date. If you type an incorrect date, user files will + be written with the wrong creation and access dates. + The automatic COMPIL, if the source file was created + later than .REL file, will break down. More + seriously, if your installation is purging files by + date created or accessed, users' files could be + incorrectly deleted. If you discover later that you + typed in the wrong date but the system has not + started running the null job yet (Step 32), you may + restart the monitor at 400, reload it, or use the SET + DATE command. + + TIME: 0843 + + You type time based on a 24-hour clock, e.g., type + 0843 for 8:43 AM, or 1345 for 1:45 PM. + + If an incorrect format is detected, the ONCE-Only + dialogue reasks the question in more detail: + + PLEASE TYPE TIME AS HHMM: + + As with the date, it is very important that you type + in the correct time. You can change the time after + the monitor has started to timeshare using the SET + DAYTIM command. (Refer to the DECsystem-10 Operating + System Command Manual in the DECsystem10 Software + Notebook.) However, this practice is to be + discouraged because it confuses the creation times of + files and causes the accounting system to make + incorrect charges for connect time. You can reload + or restart the monitor if you detect the error before + Step 31 (null job running). + + + If, after loading the monitor (Step 0), you are not asked the + reason for the reload and the date and time, perform the + following: + + a. Check that the NXM STOP is off. If not (this is a + ONCE DIALOGUE Page 16-26 ____ ________ +STARTUP OPTION: LONG + + + common error and is easily recovered), set if off. + + b. Push CONTINUE. ONCE goes back to Step 2. Now you may + respond to date and time queries. + + If this procedure does not work, it may be that the monitor + was written without a starting address. Try the following: + + a. Set the address switches to 000400. + + b. Press STOP, RESET, START (in that order). + + c. Go back to Step 1 and respond to DATE, WHY RELOAD, and + TIME queries. + + 5. ONCE checks to see if all of memory is accessible. The + amount of accessible memory is determined by scanning memory. + If the amount found is less than that specified when the + monitor was built (by a MONGEN question), the following + message is typed. + + % MEMORY FROM XXXXXX TO YYYYYY IS OFF LINE + DO YOU WANT IT TO BE 1) ON LINE, OR 2) DOWN? + (TYPE #) + + USER RESPONSE: 1 OR 2 + + If the memory is required, check to see that the memory banks + in question are properly selected and addressed, then type 1 + after any adjustments. Memory is rescanned to check for the + required amount. + + If the memory is not required, type 2. The memory is then + classified as down or unavailable, and is not used. Note + that on KA10-based systems (1040, 1050, and 1055), all + available memory should be contiguous (all memories + classified as down are at the top of core) for maximum system + performance, e.g., non-contiguous memory limits the maximum + job size and compromises the swapping algorithm. + Nevertheless, it is possible to run on a KA10 with + non-contiguous memory. + + Note that after a system power failure, the memories that you + want on-line may not be in a ready condition. If the AW + (await request) light is not ON, open the front door of the + appropriate memory cabinet and push the RESET switch several + times. If the AW light does not go on, go to the rear of the + cabinet and power the memory OFF and then ON. If the light + still does not go on, type 1 anyway (because the indicator + bulb may be burnt out). + + If the monitor repeats the message for the same memory, + deselect all ports on that memory and, if contiguous memory + is desired, switch the highest memory down into the deselect + memory. Be sure to check all ports and check for + interleaving. + + If the highest memory is interleaved, you must change the + interleaving of the memories adjacent to the highest memory. + + 6. ONCE asks for the desired STARTUP Option + + STARTUP OPTION: + ONCE DIALOGUE Page 16-27 ____ ________ +STARTUP OPTION: LONG + + + You type one of the following, depending upon your needs. + (Refer to Sections 16.2 through 16.8 for a more detailed + explanation of each option.) + + QUICK To start the system quickly without changing any + parameters. (Refer to Section 16.2.) + + GO To check to see if everything is in order and to + start the system with a minimum of dialogue. + (Refer to Section 16.3.) + + DESTROY To automatically restructure and refresh all disks + according to a predetermined set of standards. + (Refer to Section 16.4.) + + REFRESH To explicitly refresh selected file structures + without changing other system parameters. (Refer + to Section 16.5.) + + UNITID To change selected unit IDs without changing other + system parameters. (Refer to Section 16.6.) + + CHANGE To explicitly set or change selected file + structure parameters. (Refer to Section 16.7.) + + LONG To explicitly set all parameters and restructure + the file system in a non-standard way. (Refer to + Section 16.8.) + + NOINITIA To start the system quickly without setting any + new parameters and without running INITIA (refer + to Section 16.2). + + + + USER RESPONSE: LONG + + 7. ONCE lists the number of monitor buffers and accepts a + change. + + + # MONITOR BUFFERS = 6 + + + + USER RESPONSE: to leave at that number + + Type n (decimal) to change the number of + buffers + + The value you type is not written back onto the disk; + therefore, it lasts only for this load of the monitor. Note + that the value you type must be 2 or greater. + + This parameter can be changed permanently by + + a. Redefining symbol MBFN during the MONGEN dialogue or + + b. Patching the location MBFNUM with EXEC DDT or with + FILDDT and resaving it. + ONCE DIALOGUE Page 16-28 ____ ________ +STARTUP OPTION: LONG + + + 8. ONCE reads both HOME blocks from each unit in system. + + The ONCE-Only dialogue reads the HOME blocks from all disk + units that the Monitor was generated to handle. If a unit is + write protected, the ONCE-Only dialogue types: + + + + %DPA2 IS WRITE PROTECTED + + DO YOU WANT IT TO BE 1) WRITE-ENABLED, OR + 2) WRITE-PROTECTED? (TYPE #) + + + + USER RESPONSE: 1 + + Set the unit properly. If you do not wish to initialize the + HOME blocks, turn the unit off line. After the HOME blocks + have been initialized the first time, the monitor can be + started with the unit write protected. + + 9. ONCE lists HOME block consistency errors and asks to + initialize. If a disk unit has not been refreshed previously + (true for the first time Monitor startup) or has been written + on by a test or maintenance program, the ONCE-Only dialogue + types: + + ?FHA0 FIRST HOME BLOCK CONSISTENCY ERROR + + ?FHA0 SECOND HOME BLOCK CONSISTENCY ERROR + + DO YOU WANT TO INITIALIZE THE HOME BLOCKS + ON THIS UNIT? + + + + USER RESPONSE: Y + + If only one of the two HOME blocks has a consistency errors, + you type N and the data in the good HOME block will be + used. If both HOME blocks have consistency errors, you must + dissolve the file structure, redefine, and refresh. You type + Y to this question and continue with the LONG dialogue. + + If there are any off-line controllers, the ONCE-Only dialogue + might type: + + %CONTROLLER FHA IS OFF-LINE + + DO YOU WANT IT TO BE 1) ON-LINE, OR + 2) DOWN? (TYPE #) + + + + USER RESPONSE: 1 or 2 + + You must change the controller if it was not set properly. + If you type anything other than 2, the monitor tries the + controller again. If you specify that the controller is + down, the monitor does not attempt to use any of the units on + the controller. + ONCE DIALOGUE Page 16-29 ____ ________ +STARTUP OPTION: LONG + + + If there are any on-line controllers, ONCE may type: + + %CONTROLLER DPAn WRITE-HEADER LOCKOUT SWITCH + ALLOWS WRITING HEADERS. + + DO YOU WANT IT TO BE 1) SET OR + 2) IGNORED (TYPE #) + + + + USER RESPONSE: 1 + + If the write-header lockout switch is OFF, it allows + formatting of disk packs under timesharing. If it is OFF, + turn the switch to ON and type 1. This switch must be ON to + start the monitor. + + If you type 2 (ignored), ONCE types + + NOT NORMALLY DONE, ARE YOU SURE? + + as a warning. You type YES if you are sure, and NO if you + wish to reanswer the previous question. + + If there are any off-line units on the controller, the + ONCE-Only dialogue might type: + + %FHA1 IS OFF-LINE + + DO YOU WANT IT TO BE 1) ON-LINE, + 2) OFF-LINE, OR 3) DOWN? (TYPE #) + + USER RESPONSE: 1, 2, or 3. + + You must change the unit if it has not been set properly. If + you type anything other than 2 or 3, the monitor tries the + unit again. If you specify that the unit is down, the + monitor cannot access it again, unless you issue the ATTACH + command to put the unit off-line. The MOUNT command can be + used to place the unit in the monitor's pool of available + devices. You can also issue the DETACH command to declare a + unit as down, which removes the unit from the monitor's pool + of available devices. You can cause a disk pack unit to be + off-line without powering it down. Simply set the + enable/disable switch to disable the unit. If the monitor is + built to handle more units than are physically attached, no + harm is done. There is only the minor annoyance of answering + this question with 3 every time the Monitor is started (LONG + dialogue). Software unit data blocks (UDBs) can be easily + patched out of the system with EXEC DDT or FILDDT to avoid + the above questions because the unit data blocks (e.g. + RPA3CB) are linked through the LH of relative location + UNISYS. (Refer to PATMON.) + + On subsequent startups, one of the following error messages + may occur: + + ?MORE THAN ONE LAST UNIT IN ACTIVE SWAPPING LIST + + ?MORE THAN ONE LAST UNIT IN STR XXXX + + ?NO UNITS IN ACTIVE SWAPPING LIST + ONCE DIALOGUE Page 16-30 ____ ________ +STARTUP OPTION: LONG + + + %LAST UNIT IN ACTIVE SWAPPING LIST NOT FOUND + + ?CHANGE THE SLAVE OFFSET SWITCH IN BAY 2 + + ?TWO LOGICAL UNIT N'S FOUND IN ACTIVE SWAPPING LIST + + %LOGICAL UNIT N MISSING FROM ACTIVE SWAPPING LIST + + ?LAST UNIT WASN'T FOUND IN STR XXXX + + ?TWO LOGICAL UNIT N'S FOUND IN STR XXXX + + ?LOGICAL UNIT N MISSING FROM STR XXXX + + ?TWO LOGICAL STR N'S FOUND IN "SYS" SEARCH LIST + + %LOGICAL STR # N MISSING FROM SYS SEARCH LIST + + ?NO STR'S IN SYS SEARCH LIST + + You must change parameters and/or mount or dismount packs to + get rid of the error condition. It is not an error to have + units that are not in any file structure. So the message + + UNITS NOT IN A FILE STRUCTURE: + + does not need corrective action. In fact, the swapping unit + in a large system may be entirely dedicated to swapping. In + this case, it is recommended that the swapping unit not be + included in a file structure because the space for the + skeleton file structure can be saved. Note, however, that + the first 12 decimal blocks must still be used for HOME and + BAT blocks. + + 10. ONCE lists BAT block consistency errors: + + ?DPA0 FIRST BAT BLOCK CONSISTENCY ERROR + + ?DPA0 SECOND BAT BLOCK CONSISTENCY ERROR + + + + DO YOU WANT TO INITIALIZE THE BAT BLOCKS ON + THIS UNIT? + + USER RESPONSE: N + + (Type Y if the BAT block has not been written on by the + mapping option of a maintenance program.) + + If only one BAT block has consistency errors, you type N + because the other BAT block is probably all right. If both + BAT blocks have consistency errors, you type Y. ONCE + responds with + + NOT NORMALLY DONE, ARE YOU SURE? + + USER RESPONSE: Y + + ONCE responds with INITIALIZING BAT BLOCKS. + + ONCE asks for unit names on which to list the number of bad + regions from the BAT blocks. + ONCE DIALOGUE Page 16-31 ____ ________ +STARTUP OPTION: LONG + + + TYPE PHYSICAL UNIT NAME TO LIST BAD REGIONS + + ( IF NONE, ALL IF ALL) + + USER RESPONSE: + + Usually there are none, but if you specify a physical name or + ALL, then ONCE types + + DPA2 (2RP005) + + # BAD REGIONS=xxxxx + + #BAD BLOCKS=XXXXX + + 11. ONCE lists STRs and units for disk packs in them. + + The ONCE-Only dialogue types out each file structure name + followed by the physical unit name of each unit in the file + structure in its logical order. The unit ID is typed in + parentheses after each physical unit name. Example: + + DSK FILE STRUCTURES (STRS): + + DSKA:FHA0(RM10A),FHA1(RD10A) + + DSKB:DPA1(DP0KZQ),DPA0(DP2KMR),DPA2(DP1RWP) + + If there are no file structures, only the header line is + typed, because you must take action. + + 12. ONCE lists units not in an STR, if any. + + The ONCE-Only dialogue types out each physical unit not in a + file structure followed by the unit ID. This list always + includes the off-line and down units. Parentheses mean the + unit name is zero. Example: + + UNITS NOT IN A FILE STRUCTURE: + + FHA2(),DPA3(DP35WN) + + If there are no units in the file structures, the heading is + not typed. + + 13. ONCE lists units in the active swapping list. + + The ONCE-Only dialogue types out all physical units in the + active swapping list, along with the swapping class of each + unit. Class0, class1 ... classn describe different + varieties of swapping space. Lower number swapping spaces + should contain high-speed devices because all lower class + space is used first. + + UNITS IN ACTIVE SWAPPING LIST: + + FHA(0),DPA1(1) + + If there are no units in the active swapping list, the + ONCE-Only dialogue types: + + ?NO UNITS IN ACTIVE SWAPPING LIST + ONCE DIALOGUE Page 16-32 ____ ________ +STARTUP OPTION: LONG + + + This typeout is to be expected on the first monitor startup. + This situation must be corrected by including at least one + unit in the active swapping list. + + 14. ONCE lists STRs in the system search list. + + The ONCE-Only dialogue types out all file structure names in + the system search list for device SYS. SYS should include a + fast and a slow file structure. Most .EXE files should be + put on the slower file structure, because the dormant + segments are kept on the faster swapping units. Other active + files such as accounting files should also be considered as + candidates for a faster file structure within SYS. + + Example: + + STR's IN "SYS SEARCH LIST: + + DSKA,DSKB + + (There will be none the first time.) + + 15. ONCE asks for an STR name to list its parameters. + + TYPE STR NAME FOR A LIST OF ITS PARAMETERS (CR IF NONE, + ALL IF ALL) + + USER RESPONSE: + + 16. ONCE asks for a unit name to list its parameters. + + TYPE PHYSICAL UNIT NAME TO LIST ITS PARAMETERS (CR IF + NONE, ALL IF ALL) + + USER RESPONSE: + + 17. ONCE asks if you want to change anything. + + BEFORE "HOME" BLOCKS ARE REWRITTEN, + DO YOU WANT TO CHANGE ANY DISK PARAMETERS? + + USER RESPONSE: Y + + (You wish to define some file structures.) + + If you type , ONCE goes to Step 25 (ask about + refreshing). + + 18. ONCE asks if you want to dissolve any STRs. + + TYPE STR NAME TO BE DISSOLVED (CR IF NONE, ALL IF ALL) + + USER RESPONSE: + + (There are none to dissolve.) If you want to redefine a file + structure on a subsequent startup, you must first dissolve + all STRs that have the units you wish to include in the new + STR. If there are no file structures, which is the case the + first time ONCE-Only is run, this question is omitted. + + 19. ONCE asks for a STR to be defined. + + TYPE STR NAME TO BE DEFINED (CR IF NONE) + ONCE DIALOGUE Page 16-33 ____ ________ +STARTUP OPTION: LONG + + + USER RESPONSE: DSKA + + (Define the fastest file structure first.) + + ONCE asks for the names of units to be in the file structure. + + TYPE NAMES OF PHYSICAL UNITS IN STR (ALL IF ALL, EXTRA + CR WHEN DONE) + + USER RESPONSE: FHA0 + FHA1 + + + If you type a name that is not a physical unit name, this + incorrect name is ignored and you receive the message + + ?NOT A PHYSICAL UNIT - TRY AGAIN + + If you have two units (RM10B or RD10 or a mixture) on the + RC10, follow with an extra carriage return to indicate the + end of file structure DSKA. If there are a small number of + units of a particular type, say two or three, define them to + be in one file structure. If your installation has a large + number of units you can define more than one file structure + for that controller type. Remember that it is possible to + put RM10B and RD10 in the same file structure. You may wish + to leave an RM10B out of any file structure and use it solely + for swapping, thereby eliminating most STR overhead. + + If there are any physical units not yet defined to be in a + structure, ONCE asks for another STR to be defined. If not, + then ONCE goes directly to question 20. + + TYPE STR NAME TO BE DEFINED (CR IF NONE) + + USER RESPONSE: DSKB + + (Type in the second fastest file structure name.) + + + + ONCE asks for units to be in this file structure. + + TYPE NAMES OF PHYSICAL UNIT IN STR (ALL IF ALL, CR WHEN + DONE) + + USER RESPONSE: DPA0 + DPA1 + DPA2 + + + If you have, for example, three units on the RP10. + + + + ONCE asks for another STR to be defined. + + TYPE STR NAME TO BE DEFINED (CR IF NONE) + + USER RESPONSE: + + If all desired units have been defined to be part of some + file structure. + ONCE DIALOGUE Page 16-34 ____ ________ +STARTUP OPTION: LONG + + + 20. ONCE asks if you want to change any STR parameters. + + TYPE STR NAME TO CHANGE ITS PARAMETERS (CR IF NONE, ALL + IF ALL) + + USER RESPONSE: DSKA + + (Because you have not defined any parameters yet, you could + type ALL to define all.) + + AFTER EACH PRINTING OF CURRENT VALUE, TYPE NEW VALUE OR + CR + + PARAMETERS WHICH MAY BE CHANGED WITHOUT REFRESHING + + # OF CONSECUTIVE BLOCKS TRIED FOR ON OUTPUT=n + MIN=1 MAX=m + + where n is 10 for RC10 file structures or + 30 for RP10 file structures + and m is the size of the STR. + + USER RESPONSE: + + + + SUM OF BLOCKS GUARANTEED TO USERS=0 + MIN=0 MAX=m + + where m is the number of blocks on the STR. Because + reserve quotas are not implemented for the 603 release, + this number is not used. + + USER RESPONSE: + + + + # BLOCKS ALLOWED FOR OVERDRAW PER USER=n + MIN=0 MAX=m + + where n is 200 for RC10 file structures + 500 for RP10 file structures + and m is max. number of blocks in STR. + + USER RESPONSE: + + The overdraw amount should be as large as a source file + so that editing with TECO can be completed while + exceeding a user's quota, but before the overdraw + amount runs out. + + + + PARAMETERS WHICH MAY NOT BE CHANGED WITHOUT REFRESHING + K FOR CRASH.EXE=n + MIN=0 MAX=4096 + + + + n is determined by the larger of the MONGEN-specified + size or the actual size of the machine. + + USER RESPONSE: n or + ONCE DIALOGUE Page 16-35 ____ ________ +STARTUP OPTION: LONG + + + Where n is the core size of the machine on which the + monitor is running. (CRASH.EXE is used by BOOTS to + dump a core image when the monitor crashes.) + + + + BLOCKS PER CLUSTER=n + MIN=1 MAX=511 + + where n = 1 for RC10 file structures + 5 for RP10 file structures. (10 is also supported for + RP10, RHx0, and RP0x file structures.) + + USER RESPONSE: + + THEREFORE BITS PER CLUSTER ADR.=13 + THEREFORE BLOCKS PER SUPER CLUSTER=m + THEREFORE SUPERCLUSTERS PER UNIT=n + + For RP02, m=5 n=8000 + For RM10B, m=1, n=2700 + For RD10, m=1, n=4000 + For RP03, m=5, n=16000 + For RP04, m=10, n=15428 + For RP06, m=10, n=30780 + + + + BITS PER CLUSTER COUNT=9 + MIN=1 MAX=18 + + USER RESPONSE: + + This gives up to 511 clusters in one retrieval pointer. + + THEREFORE BITS PER CHECKSUM=14 + + 21. ONCE asks if you want to change any other STR parameters. + + TYPE STR NAME TO CHANGE ITS PARAMETERS (CR IF NONE, ALL + IF ALL) + + USER RESPONSE: Next STR name to be changed (e.g., + DSKB) + or + if none + + Repeat question 21. for each STR. + + 22. ONCE asks if you want to change any unit parameters. + + TYPE PHYSICAL UNIT NAME TO CHANGE ITS PARAMETERS (CR IF + NONE, ALL IF ALL) + + USER RESPONSE: ALL + + [The first time.] The ONCE-Only dialogue types out one + physical unit name. It repeats the questions for each unit. + + AFTER EACH PRINTING OF CURRENT VALUE, TYPE NEW VALUE OR + CR + + (Then the monitor types out the first physical device name.) + ONCE DIALOGUE Page 16-36 ____ ________ +STARTUP OPTION: LONG + + + PARAMETERS WHICH MAY NOT BE CHANGED WITHOUT REFRESHING + + ZERO UNIT ID-NEW ID NEEDED + + USER RESPONSE: RD001 + + The unit ID may be up to six characters in length. It is + suggested that a unit ID indicate the type of unit. For + example, + + RD000, RD001, RD002, RD003, (FOR RD10s) + RM000, RM001, RM002, RM003 (FOR RM10Bs) + 2RP000, 2RP001, 2RP002, 2RP003, 2RP004, 2RP005, + 2RP006 (FOR RP02s) + + Each pack at an installation should have a unique ID. + + K FOR SWAPPING ON UNIT=0 + MIN=0 MAX=p + + For RP02 p=4095. For RM10B or RD10 p=337. For RP03 p=8191. + + USER RESPONSE: N + + Where n is about 15 times the number of jobs the system is + built for if this is the first drum unit or 0 times for all + other units. + + You may wish to allocate some space for swapping on another + unit in case the first unit goes down. A unit will not be + used for swapping unless it is in the active swapping list. + + If n is greater than maximum, the message (for RP02). + + ?CANNOT EXCEED 4095 + + The maximum (p) may be too large. If the unit is in a file + structure, it is suggested that p-2 be the largest number + specified. + + + NOTE + + There is no requirement that a unit used for swapping + be part of a file structure. By not making it part + of a file structure, the space for the skeleton file + structure can be saved. Note that the HOME and BAT + blocks must still be present (Blocks 1, 2 and 10, 11 + decimal). + + COMPUTED 1ST LOGICAL BLOCK FOR SWAPPING=YYYYY + 1ST LOGICAL BLOCK FOR SWAPPING=YYYYY + MIN=13 MAX=YYYY + + USER RESPONSE: + + The ONCE-Only program has computed the best place for + the swapping space by putting it in the middle of the + unit. If there are any bad spots in that region, you + should move the swapping space down by typing a + smaller logical block number. The question is + skipped if no swapping space was allocated. + ONCE DIALOGUE Page 16-37 ____ ________ +STARTUP OPTION: LONG + + + If YYYYY is too low, so that it would interfere with + the HOME and BAT blocks, the ONCE-Only dialogue will + type: + + MUST EXCEED 11 + + If YYYYY is too high, so that it would run past end, + the ONCE-only dialogue will type: + + CANNOT EXCEED YYYYY + + + + # SAT BLOCKS ON UNIT=t + MIN=t MAX=223 + + Where t is the minimum. + + For RP02, t=2. For RM10B or RD10, t=1. For RP03, + t=4. For RP04, t=4. For RP06, t=7. + + USER RESPONSE: + + + Then the ONCE-Only dialogue types + + THEREFORE CLUSTERS PER SAT=xxxx + + THEREFORE WORDS PER SAT=yyy + + If the cluster size is smaller than the recommended size, + more than one SAT block per unit will be required. If you + type a number that is too small, the dialogue responds with + + TOO SMALL - MIN =N + + and repeats the question. + + PARAMETERS WHICH MAY BE CHANGED WITHOUT + REFRESHING + + # SAT BLOCKS IN CORE=M + MIN=1 MAX=m + + USER RESPONSE: m + + The suggested words per SAT block have been chosen so that + each unit has only one or two SAT blocks. It is faster to + have all SAT blocks in memory. If the number of SAT blocks + on this unit is 1, this question is skipped. If ALL had been + typed or another unit is to be changed, ONCE goes back to + beginning of question 18. + + 23. ONCE lists units in the active swapping list and asks if you + want to make any changes. + + UNITS IN ACTIVE SWAPPING LIST: + FHA0 (0), DPA0 (1) + + DO YOU WANT TO CHANGE THE ACTIVE SWAPPING + LIST? + + USER RESPONSE: Y + ONCE DIALOGUE Page 16-38 ____ ________ +STARTUP OPTION: LONG + + + (You must define an active swapping list if this is initial + system startup.) + + + + FOR EACH CLASS TYPE PHYSICAL UNIT NAMES (CR + WHEN DONE) + + CLASS 0 + + USER RESPONSE: FHA0 + + If there are more units in Class 0, type FHA1. Type an extra + carriage return when finished with Class 0. + + CLASS 1 + + USER RESPONSE: DPA0 if swapping space is allocated, + or + + + + NOTE + + 1. Class 0, class 1,....class n describe the + different varieties of swapping space. Lower + numbered swapping space should contain higher speed + devices because all lower class space is used first. + + + + + NOTE + + 2. The small monitor (DECsystem-1040) allows only + one file structure and one unit for swapping. After + the question + + UNITS IN ACTIVE SWAPPING LIST: + CLASS 0 + DPA0 + + ONCE-Only types + + %SWAPPING LIST FULL + + With the small monitor this message is expected and + should not alarm you. + + + + 24. ONCE lists STRs in the system search list and asks if you + have any changes. + + STRS IN "SYS" SEARCH LIST + DSKA,DSKB + DO YOU WANT TO CHANGE THE "SYS" SEARCH LIST? + + USER RESPONSE: Y + + (You must define a system search list if this is the initial + system startup.) + ONCE DIALOGUE Page 16-39 ____ ________ +STARTUP OPTION: LONG + + + TYPE STR NAMES FOR "SYS" SEARCH LIST (EXTRA CR WHEN + DONE) + + USER RESPONSE: DSKA + DSKB + + + The fastest file structure name (e.g., DSKA) followed by a + slower one and an extra carriage return. + + 25. ONCE asks to list STR parameters. + + BEFORE "HOME" BLOCKS ARE WRITTEN + TYPE STR NAME FOR A LIST OF ITS PARAMETERS (CR IF NONE, + ALL IF ALL) + + USER RESPONSE: + + You will be able to check after HOME blocks are written. To + check now type structure names or ALL. + + 26. ONCE asks to list unit parameters. + + TYPE PHYSICAL UNIT NAME FOR A LIST OF ITS + PARAMETERS (CR IF NONE, ALL IF ALL) + + USER RESPONSE: + + You are able to check later. + + 27. ONCE asks if you want to change anything. + + DO YOU WANT TO CHANGE ANY DISK PARAMETERS? + (CR IF NO) + + USER RESPONSE: + + 28. Asks for the HOME blocks to be written. + + TYPE PHYSICAL UNIT TO WRITE HOME BLOCKS (CR IF NONE, + ALL IF ALL; "ALL" IS NORMAL CASE) + + USER RESPONSE: ALL + + Under normal circumstances ALL is the only acceptable answer + to this question. can be used during software + development if you are experimenting and do not want to + change the HOME blocks permanently. (Any other answer can + cause problems.) + + + ONCE types + + HOME BLOCKS WRITTEN + + If an error condition exists, ONCE types a message and goes + back to question 8. If there is no error, ONCE lists the + structures defined by the HOME blocks and indicates those + that need refreshing. ONCE then lists the units that are not + in a file structure, the units that are in the swapping list + above, and the STRs in the "SYS" search list. ONCE then + lists the parameters for STRs and physical units if you + request. + ONCE DIALOGUE Page 16-40 ____ ________ +STARTUP OPTION: LONG + + + 29. ONCE asks for the STR name to be refreshed. + + DO YOU WANT TO CHANGE ANY DISK PARAMETERS + + If ONCE determines that one or more structures needs + refreshing, it will type the message: + + %NEED REFRESHING: + aaa + + where aaa are the STRs that need refreshing. + + TYPE STR NAME TO BE REFRESHED (CR IF NONE, + ALL IF ALL) + + USER RESPONSE: ALL + + (The first time you wish to refresh everything.) + + 30. ONCE asks you to LOGIN. + + TO AUTOMATICALLY LOGIN UNDER [1,2] TYPE LOGIN + + USER RESPONSE: LOGIN + + 31. The Monitor starts running the null job and initiates + timesharing. + + 32. If the LONG option is run, post the output from questions 10 + through 27 on the wall as the latest disk configuration. + + 33. When building a new monitor return to Chapter 5 for + instructions on restoring files to the disk. + + + + +16.9 WHY RELOAD QUESTION ___ ______ ________ + +As a part of the loading procedure the ONCE-Only dialogue asks for the +reason for the reload. The question + + WHY RELOAD: + +is typed on your terminal, just before the questions asking for the +date and time. You must specify your reason for reloading the monitor +by typing one of the answers described in this section, or an +abbreviation that uniquely describes it. If more than one answer +applies, you type the one that appears first in the list. If you wish +to include information related to your answer, e.g., circumstances +surrounding a system crash, you may do so by including the text on the +same line as the answer. The entire string of text is first stored in +the crash AC area and then copied to the log file by DAEMON. + +The possible answers to the WHY RELOAD: question fall into four +categories: + + System problem + Stand-alone time + New or different monitor + Other + ONCE DIALOGUE Page 16-41 ____ ________ +WHY RELOAD QUESTION + + + 1. System Problem + + If you are reloading the monitor as a result of a system + problem or crash, you identify the cause of the problem + with one of the following answers. + + Answer Meaning + ------ ------- + + OPR Operator error + + PARITY Memory parity stop or halt + + POWER Power failure on some device + + STATIC Static electricity + + HARDWARE Hardware malfunction + + NXM Non-existent memory stop + + HALT STOPCD or halt + + LOOP Monitor loop in executive mode + + HUNG No response + + 2. System Stand-Alone + + If you are reloading the monitor to get timesharing services + back on the air, you type one of the following answers. + + Answer Meaning + ------ ------- + + PM Preventive maintenance. Stand-alone + that was required for regularly + scheduled maintenance procedures. + + CM Corrective maintenance. Stand-alone + that was required for unscheduled + maintenance procedures. + + SA Other stand-alone projects, such as + programmer debugging session or + reformatting of disk packs. + + 3. New or Different Monitor + + If you are loading a new or a different monitor, you choose + one of the following answers. + + Answer Meaning + ------ ------- + + NEW New monitor, e.g., monitor with an added + feature or improvement via a patch. + + SCHED A scheduled change from one monitor to + another, e.g., a change from a dual + system monitor to a single system + monitor and back. + ONCE DIALOGUE Page 16-42 ____ ________ +WHY RELOAD QUESTION + + + 4. Other + + If none of the above reasons applies, you type OTHER. + + + + +16.10 ERROR MESSAGES _____ ________ + +The following error messages may be typed on your terminal during the +ONCE-Only dialogue. + +%ACTIVE SWAPPING LIST FULL + + An attempt was made to specify more units to the active + swapping list than the monitor tables can handle. The + current limit is 8. If you need more swapping space, you + should increase the amounts on the eight units already + specified. + + + +?CANNOT EXCEED # BLOCKS IN FILE STRUCTURE = n + + The number of disks blocks specified for reserved quotas or + the number of disk blocks specified for the overdraw amount + was too large. You should type in a number less than or + equal to n. + + + +?CANNOT EXCEED # SAT BLOCKS ON UNIT = n + + The number of SAT blocks in memory cannot exceed the number + of SAT blocks (n) on the unit. You should type a number + less than or equal to n. + +%CONTROLLER DPA HAS WRITE HEADER LOCKOUT SWITCH OFF +DO YOU WANT IT TO BE 1) ON-LINE, 2) OFF-LINE, OR + 3) DOWN? TYPE# + + + +?CPU0 FAST AC'S ARE OFF (FM ENB) + + In a multiprocessing system, the monitor halts after this + message because it is not possible for a multiprocessing + system to run without the fast ACs (split memory cycle is + enabled). You must enable the fast ACs by performing the + following steps: + + 1. Push STOP. + + 2. Turn FM ENB off. + + 3. Set ADDRESS switches to 400. + + 4. Push START. + + On a single processor system, the above is an advisory + message. The system runs considerably slower without the + fast ACs, so you should enable them as indicated in steps + 1-4 above. + ONCE DIALOGUE Page 16-43 ____ ________ +ERROR MESSAGES + + +%DPA IS OFF-LINE +DO YOU WANT IT TO BE 1) ON-LINE OR 2) DOWN? (TYPE#) + + Controller DPA (RP10) is off line. You should check the + settings of all switches in RP10 bay. All switches should + be down. After changing the switches, you should type 1. + If you do not want the monitor to use the controller, you + should type 2. This also applies to DPB. + + + +%DPA0 IS OFF-LINE +DO YOU WANT IT TO BE 1) ON-LINE, 2) OFF-LINE, OR + 3) DOWN? (TYPE#) + + You should check the START/STOP rocker switch and the + ENABLE/DISABLE switch on the individual disk pack unit. + They should be in the normal position with the top of the + switch in. After changing switches, you should type 1. If + you do not want the monitor to use the unit, you should type + 2. This message also applies with + DPA1,DPA2,...,DPA7,DPB0,DPB1,...,DPB7. + + + +%DPA0 IS WRITE PROTECTED. DO YOU WANT IT TO BE + 1) WRITE-ENABLED, OR 2) WRITE-PROTECTED? + + Disk pack unit DPA0 is on line, but is write protected. If + you wish it to remain this way, you should type 2. + Otherwise, you should set the READWRITE/READ ONLY rocker + switch to normal (top of switch in) and then type 1. This + message also applies with DPA1,...,DPA7,DPB0,DPB1,...,DPB7. + + + +?ERROR ON CPU1 +?CHANGE THE CPU1 MA TRP OFFSET SWITCH IN BAY1 + + In a multiprocessing system, the monitor halts after this + message is printed at CTY (CPU0). At the CPU1 console, + behind the door of bay 1, change the setting of the MA TRP + OFFSET switch. Then push CONT on CPU1. (CPU0 is not + affected by this error and continues timesharing.) + + + +?ERROR ON CPU1 +?FAST AC'S TURNED OFF - SET FM ENB + + In a multiprocessing system, CPU1 halts after this message + is typed at CTY (CPU0). At CPU1 console set FM ENB by + rocking the FM ENB switch (on the maintenance panel behind + the door). Then push CONT at CPU1. (CPU0 is not affected + by this error and continues timesharing.) + + + +%FHA IS OFF-LINE +DO YOU WANT IT TO BE 1) ON-LINE OR 2) DOWN? (TYPE #) + + Controller FHA (RC-10) is off line. You should check + settings of all switches in RC-10 bay. All switches should + ONCE DIALOGUE Page 16-44 ____ ________ +ERROR MESSAGES + + + be down. After changing switches, you should type 1. If + you do not want the monitor to use the controller, you + should type 2. Also applies to FHB. + + + +%FHA0 IS OFF-LINE +DO YOU WANT IT TO BE 1) ON-LINE, 2) OFF-LINE, OR + 3) DOWN? (TYPE #) + + You should check the unit dial selectors. One of them (DISK + A, DISK B, DISK C, or DISK D) should be set to 0. You + should set the switches for all the units you have to 0, 1, + 2, or 3. The other units should be OFF. You should not + touch any dials that are dialed to numbers numerically less + than the one just typed out, because the monitor has already + read these units. After changing the switches and dials, + you should type 1. If the unit is temporarily down and will + be fixed while the system runs, you should type 2. In all + other cases, you should type 3. This could apply to + FHA1,...,FHA3,FHB0,...,FHB3. + + + +FIRST BAT BLOCK CONSISTENCY ERROR + + The ONCE-Only dialogue has discovered that the first of two + redundant BAT blocks does not contain some of the data + normally expected in a BAT block. This is not a fatal error + because the other BAT block is probably all right. If both + BAT blocks have this error, you should initialize the BAT + blocks. This error may occur if some of the diagnostics are + run. + + + +FIRST BAT BLOCK HARDWARE ERROR + + The ONCE-Only dialogue has had a hardware error while + reading the first of two redundant BAT blocks. Because + there is another BAT block, this error is usually not fatal. + The controller status is put in the console lights. + + + +FIRST HOM BLOCK CONSISTENCY ERROR + + The ONCE-Only dialogue has discovered that the first of two + redundant HOME blocks does not contain some of the data + normally expected in a HOME block. Therefore, none of the + data should be considered valid. This is not a serious + error since the other HOME block is usually all right. If + both HOME blocks have consistency errors, you have to + dissolve the file structure, redefine it, and refresh it. + + + +FIRST HOM BLOCK HARDWARE ERROR + + The ONCE-Only dialogue has had a hardware error while + reading or writing the first of two redundant HOME blocks. + This is not fatal because there is another HOME block. The + controller status is put in the console lights, and the + ONCE DIALOGUE Page 16-45 ____ ________ +ERROR MESSAGES + + + controller is left in its error condition. + + + +?LAST UNIT WASNT FOUND IN STR DSKn + + The last unit in file structure is missing. You should + check to see that all the proper packs are mounted and + on-line. If not, you should remount them and restart the + monitor at 140. Otherwise, you have to dissolve the file + structure, redefine it, and then refresh it, thereby + destroying any data already on the unit. + + + +%LOGICAL STR # n MISSING FROM THE "SYS" SEARCH LIST + + A file structure is missing from the SYS search list. This + condition need not be corrected, because the monitor will + skip the missing file structure. To avoid the message in + the future, you should change the system search list when + asked. + + + +%LOGICAL UNIT n MISSING FROM ACTIVE SWAPPING LIST + + A unit is missing from the active swapping list. This can + happen if a unit is off line or down. This error need not + be corrected since the monitor will order the swapping list + accordingly. + + + +?LOGICAL UNIT n MISSING FROM STR DSKn + + A unit is missing from a file structure and must be + remedied. You should check that all proper packs are + mounted and on line. If this is not so, you should add the + proper packs and restart the monitor at 140. Otherwise, you + have to dissolve the file structure, redefine it, and + refresh it, thereby destroying any data already on the unit. + + + +%MEMORY FROM xxxxx TO yyyyy IS OFFLINE +DO YOU WANT IT TO BE 1) ONLINE OR 2) DOWN? (TYPE #) + + If the specified memory is supposed to be off line, type 2. + Otherwise, push the reset button at the rear of the + memories. Check to see that the memory is selected and all + required ports are ON. After all switches are in order, + return to the CTY and type 1. If the error message is + repeated, attempt to switch this memory out of the system + and switch the top memory into its place. + + + +?MORE THAN ONE LAST UNIT IN ACTIVE SWAPPING LIST + + The active swapping list specified in the disk unit HOME + blocks has more than one unit as the last one. You should + redefine the units in the active swapping list to correct + ONCE DIALOGUE Page 16-46 ____ ________ +ERROR MESSAGES + + + this situation. + + + +?MORE THAN ONE LAST UNIT IN STR DSKn + + The file structure has more than one unit specified as the + last unit as recorded in the disk HOME blocks. You should + dissolve the file structure and redefine it. + + + +?NO UNITS IN ACTIVE SWAPPING LIST + + None of the on-line units is in the active swapping list. + Because there must be swapping space, you must change the + active swapping list to include a unit that has some + swapping space. If there are no units with swapping space, + you must define swapping space on a unit not in a file + structure. If all units are in file structures, you must + refresh a file structure, define the necessary swapping + space, and redefine the active swapping list. + + + +NOT NORMALLY DONE, ARE YOU SURE? + + This warning message is printed when you respond to certain + important questions in an unexpected or non-standard manner. + It allows you to verify your choice of answer or recover + from a typographical error before serious damage is done. + + + +%PROBLEM ON CPU1 + + CPU1 has halted. Restart it by setting data switches to 400 + and pushing STOP, RESET, START. Note that the above message + is printed once a minute until CPU1 is started. You can use + the OPSER command :SET CPU to stop scheduling CPU1 and, + consequently, stop the message. + + + +SAT BLOCK HARDWARE ERROR + + The ONCE-Only dialogue has had a hardware error while + reading one of the SAT blocks. + + + +SECOND BAT BLOCK CONSISTENCY ERROR + + The ONCE-Only dialogue has discovered that the second of two + redundant BAT blocks does not contain some of the data + normally expected in a BAT block. This is not a fatal error + because the other BAT block is probably all right. If both + BAT blocks have this error, you should initialize the BAT + blocks. This error may occur if some of the diagnostics are + run. + ONCE DIALOGUE Page 16-47 ____ ________ +ERROR MESSAGES + + +SECOND HOM BLOCK CONSISTENCY ERROR + + The ONCE-Only dialogue has discovered that the second of two + redundant HOME blocks does not contain some of the data + normally expected in a HOME block. Therefore, none of the + data should be considered valid. This is not a serious + error since the other HOME block is usually all right. If + both HOME blocks have consistency errors, you have to + dissolve the file structures, redefine and refresh. + +SECOND HOM BLOCK HARDWARE ERROR + + The ONCE-Only dialogue has had a hardware error while + reading or writing the second of two redundant HOME blocks. + This is not fatal since there is another HOME block. The + controller status is put in the console lights, and the + controller is left in its error condition. + + + +?THIS MONITOR WAS BUILT FOR A xxxxx AND +WILL NOT RUN PROPERLY ON A yyyyy. + + xxxxx and yyyyy can be PDP-6, KA10, KI10, or KL10. You have + loaded the wrong monitor. You must try another. If, after + several tries, the monitor appears to be the correct one, + then you must rerun MONGEN and change the answer to the + question asking for the type of processor. Refer to Chapter + 9, question 3 in Section 9.4. + + + +?TOO SMALL - MIN. #=X + + An answer to the ONCE-Only dialogue or a default value is + too small. Type in an answer greater than or equal to X. + + + +?TWO LOGICAL UNIT n's FOUND IN ACTIVE SWAPPING LIST + + The active swapping list has more than one unit in the same + position. You must redefine the active swapping list. + +?TWO LOGICAL UNIT n's FOUND IN STR DSKn + + Two units are marked to be in the same logical position in + the file structure. This happens only if two different file + structures have been given the same name. You should try to + remove the pack that does not belong in the file structure + and then restart the monitor at 140. Otherwise, you have to + dissolve DSKn, redefine it and refresh it. + + + +?TWO LOGICAL STR n's FOUND IN "SYS" SEARCH LIST + + Two file structures are marked to be in the same position in + the SYS search list. You should change the SYS search list + when asked. Refreshing is not required. + ONCE DIALOGUE Page 16-48 ____ ________ +ERROR MESSAGES + + +unit +# BAD REGIONS=n +# BAD BLOCKS=n +DO YOU WANT TO INITIALIZE THE BAD BLOCKS ON THIS UNIT? + + You should answer with N or a carriage return to leave the + BAT blocks alone on this unit. The only time you should + initialize is the first time the disk is written, since the + blocks contain the accumulated information about bad + sectors. If you answer Y, the ONCE-Only dialogue responds + with NOT NORMALLY DONE, ARE YOU SURE?. Answer Y only if + this important data is to be erased. + + + +?UNIT ALREADY IN ACTIVE SWAPPING LIST + + An attempt was made to specify a unit to be in the active + swapping list more than once. You should type a different + unit name to be in the active swapping list. If you have + included the unit name earlier by mistake, you will have + another chance to change the active swapping list. + + + +?UNIT ALREADY IN FILE STRUCTURE + + An attempt was made to specify a unit to be in more than one + file structure. You should type a different unit name to be + in this file structure. If you have included the unit in an + earlier file structure by mistake, you will have to dissolve + it. + + + +?UNIT HAS NO SPACE ALLOCATED FOR SWAPPING + + An attempt has been made to specify a unit that has no + swapping space allocated to be part of the active swapping + list. The unit is not added to the list. You should do one + of the following: + + 1. Specify another unit. + + 2. Type an extra carriage return signifying completion. + + 3. Define swapping space for a unit not in a file + structure. + + 4. Change the swapping space for a unit in a file structure + and refresh it. + + + + + + + + + + + + + CHAPTER 17 + + BACKUP ______ + + + +17.1 INTRODUCTION ____________ + +BACKUP is a system program that is used to save disk files on magnetic +tape, and later to restore any or all of these files to disk. +Magnetic tape is the medium used for backup storage of disk files and +for transporting files between sites. This chapter outlines some of +the features that BACKUP provides for accomplishing these two tasks. + + + +17.2 FEATURES ________ + +BACKUP allows you flexibility in choosing the files to be transferred +between disk and tape. You specify files by the standard file +specification format of dev:filename.ext[project,programmmer]. +Wildcards and sub-file directories are fully supported. You may also +select files based on any of the dates/times associated with disk +files. + +BACKUP can handle files that are longer than one reel of magtape. +Switches are provided for checkpointing files while the files are +being handled. + +If you are backing up the disk file structure, you can recover from a +system crash without starting completely over. You can produce a +directory listing of the tape at the same time you perform a save. +Another operator feature is a set of run-time commands compatible with +the spoolers. + +To facilitate transporting files between sites, BACKUP provides an +"interchange" mode of operation that prevents the writing of system +specific overhead information on the tape. Software distribution +tapes for the DECsystem-10 are produced via BACKUP in interchange +mode. + +To increase reliability, BACKUP responds to hardware reported tape +write errors by rewriting the data in a repeater record. When the +tape is read later, these repeater records are used instead of the +originals. + +These and other features are described more fully in Sections 17.3 and +17.4. + BACKUP Page 17-2 ______ +OVERVIEW OF COMMAND FUNCTIONS + + +17.3 OVERVIEW OF COMMAND FUNCTIONS ________ __ _______ _________ + +BACKUP commands are in the form of verbs. BACKUP prompts with a slash +(/) and has three kinds of verbs: + + 1. Action + + 2. Status setting + + 3. Tape positioning. + +Tables 17-1, 17-2 and 17-3 present BACKUP's general functions and the +command verbs that perform them. Verbs are grouped into the three +categories named above. Table 17-4 contains run-time commands, which +may be given during execution of the action verbs. + + + Table 17-1 + Action Verbs + + + Functions Verbs + + + Printing directory of a tape PRINT + + Saving or restoring disk files SAVE, RESTORE + + Verifying agreement of tape and disk files CHECK + + + Table 17-2 + Status Setting Verbs + + + Functions Verbs + + + BACKUP:name option (use from SWITCH.INI) OPTION + + [do not] use Checkpoints [NO] CPOINT + + Density setting (of tape) DENSITY + + [do not] Encrypt the magtape [NO] ENCRYPT + + Include files according to: + date-time created or modified BEFORE, SINCE + moved or modified MBEFORE, MSINCE + date accessed ABEFORE, ASINCE + + length LENGTH + + PPN exemptions from above restrictions [NO] EXEMPT + + [do not] run in Interchange Mode [NO] INTERCHANGE + + [do not] make a Listing file while running [N] LIST + + Parity setting PARITY + + Protect directories UPROTECTION + BACKUP Page 17-3 ______ +OVERVIEW OF COMMAND FUNCTIONS + + + Restore files from tape SUPERSEDE + + Resume at a specified block of initial file RESUME N + + Save set name (specify) SSNAME + + Sort files or directories alphabetically, + by location, or by directory SORT + + Start processing at specified file INITIAL + + [do not] Suppress error message prefix MESSAGE [NO] PREFIX + + [do not] Suppress first line of error + message MESSAGE [NO] FIRST + + [do not] Suppress disk writing during + a RESTORE [NO] WRITE + + Suppress filenames and directories SILENCE + + [do not] Type filenames or directories + while running [NO] FILES + [NO] DIRECTORIES + + Tape unit (use MTB0) TAPE MTB0 + + [do not] run in USETI mode [NO] USETI + + + Table 17-3 + Tape Positioning Verbs + + + Functions Verbs + + + Back up to start of save set SKIP 0 tape list + + Skip to end-of-tape mark for each tape EOT + n save sets forward SKIP n tape list + backward SKIP -n tape list + + Rewind to start of tape for each tape REWIND + + Unload each tape UNLOAD + + + Table 17-4 + Run-Time Commands + + + Functions Commands + + + List and explain these commands HELP + + Abort current action verb KILL + + Continue after a STOP GO + + Display current filename and status WHAT + BACKUP Page 17-4 ______ +OVERVIEW OF COMMAND FUNCTIONS + + + Exit from BACKUP when done EXIT + Do not exit from BACKUP when done PAUSE + + Reset status settings to defaults when done RESET + + Stop temporarily STOP + + [do not] Type all directories of files [NO] DIRECTORIES + processed [NO] FILES + + Stop typing all directories or files SILENCE + + + +17.3.1 Action Verbs ______ _____ + +The action verbs perform I/O and operate on the tape specified by the +last TAPE verb (one of the status setting verbs). A tape must be +specified before using any of the action commands, or an error will +result. In the following lists of commands and switches + + spec is the standard file specification: + dev:filename.ext[directories] + date is in the form dd-mm-yy + time is in the form hh:mm:ss + +The action verbs are: + + Command Action + +SAVE spec-list Save the specified disk files on tape + +RESTORE spec-list Restore the specified tape files to disk + +CHECK spec-list Verify that the tape and disk files agree + +[N]PRINT spec Print a directory of the entire tape on spec. N + is an optional prefix meaning narrow. PRINT + produces the effect of a NODIRECTORIES command; + i.e., no user directories will be typed. + +The action commands take as an optional argument a list of file +specifications in a format similar to the monitor's COPY command. The +file specifications may contain wildcards and sub-file directories. + +For each entry in the list, you may specify both input and output file +specifications (output=input) or just the input specification. This +allows the files to be renamed as they are saved or restored. If no +output specification is given, then the specified files are +transferred without being renamed. Entries in the list are separated +by commas. + +If no argument is supplied with an action command, BACKUP will default +a file spec in the following way. The default file spec for all +action verbs is ALL:*.*[PPN,*,*,*,*,*]. This specifies all files on +all UFDs and all SFDs of all file structures with no renaming. + +If you are not logged in under [1,2] the default for the SAVE verb is +ALL:*.*[PPN,*,*,*,*,*]=DSK:*.*[PPN,*,*,*,*,*]. + +For the CHECK and RESTORE verbs the default is +DSK:*.*[PPN,*,*,*,*,*]=ALL:*.*[PPN,*,*,*,*,*]. + BACKUP Page 17-5 ______ +OVERVIEW OF COMMAND FUNCTIONS + + +The argument for the PRINT verb is a single file spec. Its default is +LPT:BACKUP.LOG. + +Note that specifying any of the file spec parameters overlays only +that parameter and leaves the rest of the defaults standing. Under no +circumstances do the file spec parameters become "sticky" parameters; +e.g., specifying the PPN for one spec does NOT carry over to the next +spec in the list. + + + +17.3.2 Status Setting Verbs ______ _______ _____ + +The status setting verbs set a parameter that affects future action +commands. Once a status parameter is set, it remains in effect until +you change it again. The format for date/time arguments is +dd-mm-yy: hh:mm:ss; relative date/times (prefixed by + or -) and +special mnemonic words (YESTERDAY, TODAY, TOMORROW, LOGIN, NOON, +MIDNIGHT) may also be used. BACKUP conforms to the specification in +the Operating System Commands manual and more details on data formats +can be found there. + +The complements, formed by preceding the verbs with NO, negate the +commands and sometimes cause alternate actions; their effects are +explained in parentheses. + +The status setting verbs are: + + Verb Action + +ABEFORE date Include only files accessed before + the specified date + +[NO]APPEND Append to existing list file + (default) (Complement: do not + supersede). + +ASINCE date Include only files accessed since + the specified date + +BEFORE date-time Include only files created and last + modified before the specified + date-time + +[NO]CPOINT Use checkpoints. (Complement: do + not use checkpoints). + +[NO]DATE75 Always accept files with possible + DATE75 problems (default) + (Complement: do not accept these + files) + +[NO]DELETE Delete disk files after saving them + (Complement: do not delete) + +DENSITY Set tape density (default is system +(200, 556, 800, 1600, 6250) dependent) + +[NO]DIRECTORIES Type each user's directory while + running (default) (Complement: do + not type directories at all) + +[NO]ENCRYPT Encrypt the magtape (asks for key + BACKUP Page 17-6 ______ +OVERVIEW OF COMMAND FUNCTIONS + + + later) (a key is similar to a + password and it can consist of up + to 30 alphabetic characters) + (Complement: do not encrypt) + +[NO]EXEMPT Exempt PPN's of the form [A,*] and + [10,B], where A and B < 7, from + date/time and length restrictions + (default) (Complement: do not + exempt) + +[NO]FILES Type each filename while running + (Complement: do not type filename + at all) + +INITIAL spec Start processing at spec + +[NO]INTERCHANGE Run in interchange mode (In + interchange mode, only the + filenames, extensions, and versions + are written. There is no + information on what UFD a file was + in when it was saved.) (Complement: + run in normal mode, in which UFDs + and device names are written) + +LENGTH 1:h Include only files whose length is + between low and high + +[NO]LIST spec While running, make a listing file + on spec (default spec is LPT: + BACKUP.LOG) (Complement: do not + make listing file) LIST produces + the effect of a NODIRECTORIES + command, i.e., no user directories + will be typed. + +MBEFORE date-time Include only files which have been + last moved or modified before the + specified time + +MSINCE date-time Include only files which have been + moved or modified since the + specified time + +MESSAGE [NO]PREFIX Suppress error message prefix + +MESSAGE [NO]FIRST Suppress first line of error + message text + +[NO]MULTIREEL Allow multiple reels during a save + (default; multiple reels are + always permitted on a restore) + (Complement: do not allow multiple + reels during a save) + +OPTION NAME Use option BACKUP:name from + SWITCH.INI + +PARITY (EVEN,ODD) Set tape parity + +[NO]REPEAT Repeat a split file on the + continuation tape (Complement: do + BACKUP Page 17-7 ______ +OVERVIEW OF COMMAND FUNCTIONS + + + not repeat) + +RESUME n Resume at block n of initial file + +SILENCE Do not type filenames or + directories while running + +SINCE date-time Include only files created or + modified since the specified + date-time + +SORT DIRECTORIES x Sort directories within each file + structure in order x when saving. + x = ALPHABETICAL LOCATION (by + compressed-file-pointer, which is + related to a file's physical + location on disk), or NONE (by + Master File Directory) + +SORT FILES x Sort files within each directory in + order x when saving. + x = ALPHABETICAL, LOCATION, or NONE + (by directory) + +SSNAME name Specify the save set name (up to 30 + characters; ALL = all save sets on + tape) + +SUPERSEDE ALWAYS Always restore file from tape + +SUPERSEDE NEVER Restore files from tape unless on + disk + +SUPERSEDE OLDER Restore only the new files from + tape (default) + +TAPE MTB0 Use tape unit MTB0. If a magtape + drive has the logical name BACKUP, + then the TAPE verb need not be + specified + +UPROTECTION NNN Set the protection for created + directories + +[NO]USETI Run in USETI mode (speeds up SAVES + with /SINCE, etc.) (Complement: do + not run in USETI) + +[NO]WRITE Suppress disk writing during a + RESTORE. (Complement: allow disk + writing during a RESTORE) + + + +17.3.3 Tape Positioning Verbs ____ ___________ _____ + +BACKUP's tape positioning verbs take immediate effect. They take, as +an argument, a list of tapes. If no tape is specified for a given +command, the last tape declared by a TAPE verb is positioned. The +tape positioning commands are: + + Command Action + BACKUP Page 17-8 ______ +OVERVIEW OF COMMAND FUNCTIONS + + + EOT tape list Skip to the end-of-tape mark for + each tape in the list + + REWIND tape list Rewind to the beginning of the tape + for each tape in the list + + SKIP n tape list Skip n save sets forward for each + tape in the list + + SKIP 0 tape list Back up to the start of the current + save set for each tape in the list + + SKIP -n tape list Skip n save sets backward for each + tape in the list + + UNLOAD tape list Unload each tape from its drive for + each tape in the list. + +The following switches may be included within the file specification +list for the action verbs. These switches can be either temporary or +permanent. A temporary switch immediately follows the file to which +it applies. A permanent switch precedes the list of files to which it +applies, or may be typed on a separate line like a status setting +verb. + + Switch Action + + ABEFORE date (On input file) include only if + accessed before date + + ASINCE date (On input file) include only if + accessed since date + + BEFORE date-time (On input file) include only if + created before date-time + + ERNONE (On input file) give error if no + files match + + ERPROTECTION (On input file) give error if there + is a protection failure + + ERSUPERSEDE (On output file) do not restore + from tape if on disk + + ESTIMATE n (On output file) estimate output + size + + LENGTH L:H (On input file) include only if the + file length is between L:H + + MBEFORE date-time (On input file) include only if + modified before date-time + + MSINCE date-time (On input file) include only if + modified since date-time + + OKNONE (On input file) do not give an + error if no files match + + OKPROTECTION (On input file) do not give an + error if there is a protection + failure + BACKUP Page 17-9 ______ +OVERVIEW OF COMMAND FUNCTIONS + + + OKSUPERSEDE (On output file) always restore + even if on disk + + [NO]PHYSICAL (Input or output) ignore logical + names (Complement: accept logical + names) + + PROTECTION nnn (On output file) set the protection + code + + SINCE date-time (On input file) include only if + created since the specified + date-time + + VERSION v (On output file) set output file + version number + + + +17.3.4 Run-Time Commands ________ ________ + +The following run-time commands may be given during the execution of +the action verbs. BACKUP prompts with an exclamation point (!) when +ready to accept a run-time command. (EXIT, HELP and RESET will also +work with a slash (/) as a prompting character.) + +The complements, formed by preceding the commands with NO, negate the +commands and sometimes cause alternate actions; their effects are +explained in parentheses. + +The run-time commands are: + + Commands Action + + [NO]DIRECTORIES Start typing every directory + processed (Complement: do not type + these directories) + + EXIT Exit from BACKUP when done + + [NO]FILES Start typing every file and + directory processed (Complement: + do not type these files) + + GO Continue after a STOP + + HELP List these commands and + explanations + + KILL Abort execution of the current + action verb + + PAUSE Do not exit from BACKUP when done + + RESET Reset all status settings to their + original defaults when done + + SILENCE Stop typing every directory or file + + STOP Stop temporarily: can be continued + by GO. + + WHAT Display current filename and status + BACKUP Page 17-10 ______ +OVERVIEW OF COMMAND FUNCTIONS + + +BACKUP also supports "/@ file" construction, allowing the use of +indirect command files, like the COMPIL-class commands. All of +BACKUP's verbs and switches, except for the run-time commands, may be +used in an indirect file. (Note that "/verb @ file" is NOT a valid +alternate format.) + + + +17.4 EXAMPLES ________ + +The following examples demonstrate the application of the BACKUP +program. + + + +17.4.1 Console User Examples _______ ____ ________ + +The console user can execute all of the BACKUP commands on his own +disk area. He can save his disk area or any other files accessible to +him on his own magnetic tape and later restore to his area all his +files or a subset of his files. In the following examples, the user +is logged in under PPN [10,123]. + + + +17.4.1.1 Saving a User's Disk Area - To save all files on his own ______ _ ______ ____ ____ +disk area on a magnetic tape mounted on MTA0, a user can type + + .R BACKUP + /TAPE MTA0 + /REWIND + /SAVE + !10,123 DSKB + 10,123 DSKC + DONE + /UNLOAD + /^C + + + +17.4.1.2 Restoring Selected Files - The following example shows how _________ ________ _____ +to retrieve a specific file and a set of files from a BACKUP tape by +using wildcards. + + .R BACKUP + /TAPE MTA1 + /REWIND + /RESTORE FOO.BAR, TST???.* + !10,123 DSKB + DONE + /UNLOAD + /^C + + + +17.4.1.3 Renaming Files as They are Transferred - A user may choose ________ _____ __ ____ ___ ___________ +to change a file's name or location path as it is moved between tape +and disk. In the following example, the file name FILEA.MAC on tape +is copied to disk as FILEB.MAC, but its path (device and directory +level) is not changed. + + .R BACKUP + /TAPE MTB0 + BACKUP Page 17-11 ______ +EXAMPLES + + + /REWIND + /RESTORE FILEB.MAC=FILEA.MAC + !10,123 DSKB + DONE + /UNLOAD + /^C + +In the next example, the file FILEC.MAC was located on DSKB in the +user's UFD [10,123] when saved on tape, but it is restored to the +sub-file directory SFD1 on DSKC. + + .R BACKUP + /TAPE MTB0 + /REWIND + /RESTORE DSKC:[10,123,SFD1]=DSKB:FILEC.MAC[10,123] + !10,123 DSKB + DONE + /UNLOAD + /^C + + + +17.5 OPERATOR USES ________ ____ + +An operator should periodically save the contents of the disk on +magtape. This provides a backup capability should something +unforeseen happen to the disk. + + + +17.5.1 Saving the Entire Disk ______ ___ ______ ____ + +To save the entire contents of DSKB on magtape and concurrently +produce a directory listing, BACKUP is run while logged in under [1,2] +as follows: + + .R BACKUP + /TAPE MTA0 + /LIST DSK:BACKUP.LOG + /SAVE DSKB: + !1,2 DSKB + 1,3 + 1,4 + . + . + . + +BACKUP types out each UFD as it begins to save files from that area. +If the tape becomes full before the save is completed, BACKUP stops, +types out the full file identification and block number of the current +file being saved, unloads the magtape, and types the message + + $BKPEOT REACHED EOT -- MOUNT NEW TAPE THEN TYPE "GO" + +When GO is typed BACKUP continues the save on the new tape. (A file +may be split across tapes.) + BACKUP Page 17-12 ______ +OPERATOR USES + + +17.5.2 Recovering from a System Crash __________ ____ _ ______ _____ + +If the system should crash during a save, for example while BACKUP is +saving files from UFD [10,456], the operator, after bringing the +system up, can instruct BACKUP to start at UFD [10,456] by using the +/INITIAL switch: + + .R BACKUP + /TAPE MTA0 + /LIST DSK:BACKUP.LOG + /INITIAL DSKB:[10,456] + /SAVE DSKB: + !10,456 DSKB + . + . + . + +Note that any status parameters which were in effect before the crash +must be reset, and that the tape should NOT be rewound. Note also +that BACKUP does an append to the existing LIST spec. + + + +17.5.3 Saving Only Recently Created or Modified Files ______ ____ ________ _______ __ ________ _____ + +The procedure for saving only those files created or modified today is +identical to that described in Section 3.2.1, with the additional +inclusion of the /MSINCE status setting switch: + + .R BACKUP + /TAPE MTA0 + /LIST DSK:BACKUP.LOG + /MSINCE:YESTERDAY + /SAVE DSKB: + !1,2 DSKB + . + . + . + +Certain files and disk areas are automatically exempted from date-time +restrictions. Files with the RP.ABU bit (always backup bit) set in +the .RBSTS word of the RIB and PPN's of the form [A,*] and [10,B] +where A and B are less then or equal to 7 are always exempted from +date/time restrictions. This causes all libraries, etc., to always be +saved and restored. (The PPN exemption can be overridden by using the +/NOEXEMPT status setting verb.) + + + +17.5.4 Restoring Only Recently Accessed Files _________ ____ ________ ________ _____ + +In the following example the /ASINCE switch is used to restore from +tape only those files whose access date is later than June 1, 1975: + + .R BACKUP + /TAPE MTA1 + /ASINCE:1-JUN-75 + /RESTORE + ! + BACKUP Page 17-13 ______ +RESTORING FROM A DISTRIBUTION TAPE + + +17.6 RESTORING FROM A DISTRIBUTION TAPE _________ ____ _ ____________ ____ + +BACKUP format distribution tapes are made in interchange mode, and +related files are grouped together in named save sets. The user does +not need to know what UFD the file was in when it was saved. Because +the tapes are made in interchange mode, this information is not even +included on tape. Suppose, for example, a new version of SCAN is on +the current tape. The following commands to BACKUP transfer all files +from only the SCAN save set onto ersatz device DEC: + + .R BACKUP + /TAPE MTB0 + /INTERCHANGE + /REWIND + /SSNAME SCAN + /RESTORE DEC:=DSK: + +The save set name "ALL" can be used in place of SCAN to indicate that +files from all save sets are to be copied. + + + +17.7 OBTAINING DIRECTORIES OF BACKUP TAPES _________ ___________ __ ______ _____ + +The command + + [N]PRINT spec + +prints a directory of the entire tape. The optional prefix N +indicates a narrow listing (72 columns). The default specification is +LPT:BACKUP.LOG. If a line-printer is not available to the user's job, +spooling is not in effect, and the default spec is used, an error will +occur. + +The following example produces a disk file directory listing named +BACKUP.LOG. + + .R BACKUP + + /REWIND + /PRINT DSK: + ! + +This is an example of the output. + +.TYPE BACKUP.LOG + + Start of save set SCAN on MTB401 + System R5200 SYS #40/2 TOPS-10 monitor 602(13053) APR#40 + 1600 BPI 9 track 18-Sep-75 13:09:13 BACKUP 2(155) format 1 + + SCAN REL 58 <055> 31-Mar-75 DSKB: [10,4077] + SCAN RNO 8 <055> 8-Mar-75 + SCAN MAC 304 <055> 31-Mar-75 + SCN7B REL 59 <055> 4-Sep-75 + SCN7B DO 101 <055> 18-Aug-75 + SCN7B RNO 97 <055> 18-Aug-75 + SCN7B CTL 3 <055> 24-Jul-75 + SCN7B MAC 309 <055> 4-Sep-75 + SCAN MEM 11 <055> 18-Sep-75 + + End of save set SCAN on MTB401 + System R5200 SYS #40/2 TOPS-10 monitor 602(13053) APR#40 + BACKUP Page 17-14 ______ +OBTAINING DIRECTORIES OF BACKUP TAPES + + + 1600 BPI 9 track 18-Sep-75 13:09:24 BACKUP 2(155) format 1 + + Start of save set BACKUP on MTB401 + System R5200 SYS #40/2 TOPS-10 monitor 602(13053) APR#40 + 1600 BPI 9 track 18-Sep-75 13:46:56 BACKUP 2(155) format 1 + + BACKUP REL 22 <055> 15-Sep-75 DSKB: [10,4077] + BACKRS REL 52 <055> 17-Sep-75 + BACKUP SHR 55 <055> 17-Sep-75 + BACKUP LOW 34 <055> 17-Sep-75 + BACKUP MAC 118 <055> 15-Sep-75 + BACKRS MAC 270 <055> 17-Sep-75 + + BACKUP RNH 19 <055> 15-Sep-75 DSKC: [10,4077] + BACKUP HLP 20 <055> 15-Sep-75 + BACKUP RNO 4 <055> 25-Aug-75 + BACKUP DOC 4 <055> 25-Aug-75 + BACKUP CTL 2 <055> 20-Aug-75 + + End of save set BACKUP on MTB401 + System R5200 SYS #40/2 TOPS-20 monitor 602(13053) APR#40 + 1600 BPI 9 track 18-Sep-75 13:47:13 BACKUP 2(155) format 1 + + + +17.8 COMPARING TAPE AND DISK FILES _________ ____ ___ ____ _____ + +The command + + CHECK spec-list + +Verifies that the tape and disk agree. BACKUP compares the tape files +specified for input to the disk files specified for output, word for +word. + +The following example saves all the user's COBOL files on tape and +then verifies that the saved tape files are identical to the disk +files. + + .R BACKUP + + /TAPE MTA0: + /REWIND + /SAVE *.CBL + /REWIND + /CHECK + ! + / + +To restore all SHR and LOW files from a tape and then verify that the +files were restored correctly type + + /REWIND + /SSNAME ALL + /RESTORE *.SHR,*.LOW + ! + /REWIND + /CHECK *.SHR,*.LOW + ! + / + BACKUP Page 17-15 ______ +CHECKPOINTING LARGE FILES + + +17.9 CHECKPOINTING LARGE FILES _____________ _____ _____ + +Installations which maintain exceptionally large files (over 5000 +blocks) will want to include the /CPOINT status setting switch when +saving and restoring files. This switch extends BACKUP's system crash +recovery capability to the file block level. During a checkpoint +save, the typeout level is set to type the filenames and checkpoints +as they are passed. To continue from the last checkpoint after a +crash, the /INITIAL switch is used to indicate the file spec and the +/RESUME switch to declare the checkpoint block number. For example: + + .R BACKUP + /TAPE MTA0 + /INITIAL DSKB:[40,577]DATBAS.DBS + /RESUME 6000 + /SAVE + !40,577 DSKB + DATBAS DBS + RESUMING AT CHECKPOINT 6000 + 7000 + 8000 + . + . + . + +Note that the tape should not be rewound to continue a checkpoint +save. + +During a checkpoint restore, the disk output file is closed at every +checkpoint and then appended to. The procedure for continuing after a +crash is the same as that for the checkpoint save, with the exception +that the tape must first be rewound. + +The default for checkpoints is 1000 blocks. + + + +17.10 BACKUP MESSAGES ______ ________ + +17.10.1 Operator Messages ________ ________ + +$BKPEOT REACHED EOT -- MOUNT NEW TAPE THEN TYPE "GO" + + The tape is full. The operator should mount a new one and then + type GO to continue. + +$BKPTWL TAPE WRITE LOCKED -- ADD WRITE RING THEN TYPE "GO" + + The tape is write locked. The operator should insert a write + ring and then type GO to continue. + + + +17.10.2 Error Messages _____ ________ + +?BKPABC AMBIGUOUS COMMAND + + The user has given a command abbreviation that is not unique. + +?BKPCOL CAN'T OPEN LISTING DEVICE + + The device specified for the LIST command cannot be selected for + output. + BACKUP Page 17-16 ______ +BACKUP MESSAGES + + +?BKPCOM CAN'T OPEN MAGTAPE + + The tape device specified cannot be selected for output. + +?BKPCSA CAN'T SAVE WITH SAVE SET NAME "ALL" + + "ALL" is reserved to mean all SAVE sets on tape; therefore, it + cannot be used to name an individual SAVE set when saving. + +?BKPDND DEVICE NOT A DISK + + The input device specified for a SAVE is not a disk. + +?BKPDNM DEVICE NOT A MAGTAPE + + The device specified for the TAPE command or a tape positioning + command is not a magnetic tape drive. + +?BKPFSL FILE SPECIFICATION DATA LOST + + During the processing of a file specification list, a consistency + check determined that data was lost. If this error occurs, + please send an SPR. + +?BKPHSG CANNOT GET HIGH SEGMENT BACK + + BACKUP releases its high segment command scanner when performing + I/O to eliminate most of the core while running. The attempt to + restore the high segment after completing the I/O operation has + failed. + +?BKPIRC INVALID RUN TIME COMMAND -- TYPE KILL TO ABORT RUN FIRST + + The user typed an illegal run time command. Type KILL to abort + the run and return to verb command level. Type HELP to get a + list of valid run time commands. + +?BKPKDM KEYS DON'T MATCH -- PLEASE TRY AGAIN + + BACKUP asks for the encryption key twice, and compares the keys + for verification. This indicates that the comparison failed. + +?BKPLFE LISTING FILE ENTER ERROR + + After opening the listing I/O channel, no entry could be made for + the listing file. + +?BKPLSI LISTING SPECIFICATION INCORRECTLY FORMATTED + + The user has used incorrect formatting or a "wild-card" in + specifying the LIST file. No list specification is created. + +?BKPNTS NO TAPE SPECIFIED + + While searching for the last tape specification given, BACKUP + could not fine one. + +?BKPNZC NEGATIVE AND ZERO CHECKPOINTS ILLEGAL + + The user specified a negative or zero argument with the RESUME + command. + +?BKPRES REACHED EOT ON A SINGLE REEL SAVE + BACKUP Page 17-17 ______ +BACKUP MESSAGES + + + This message is issued if and when the end of the tape is reached + and the user has specified the /NOMULTIREEL command. + +?BKPRTE REACHED TAPE ERROR MAXIMUM + + BACKUP will abort the execution of an action verb and return to + command level when a large number of tape I/O errors have + occurred. Currently the error maximum is set to 10. (This is an + assembly parameter.) + +?BKPTMI INSUFFICIENT CORE FOR COMMAND + + The routine for allocating space for file specifications could + not expand core enough to store the specification. + +?BKPTSI TAPE SPECIFICATION INCORRECTLY FORMATTED + + The user has used incorrect formatting or a "wild-card" in + specifying the tape device. + + + +17.10.3 Warning Messages _______ ________ + +%BKPABT ABORT spec + + The transfer of the specified file from tape to disk has been + aborted. + +%BKPBTL BLOCK TOO LARGE READING SPEC (BLOCK = n) + + The current record read from tape exceeds the buffer size. The + record will be skipped. + +%BKPCCM CANNOT COPY MFD FOR STRUCTURE + + The program cannot get enough core to copy the Master File + Directory for the indicated structure. Files for this structure + will not be saved, and the program will skip to the next + structure. + +%BKPCCR CANNOT COPY UFD/SFD RIB FOR spec + + The program cannot get enough core to copy the retrieval + information block for the indicated directory. Files for this + User File Directory/Sub-File Directory will not be saved, and the + program will skip to the next UFD/SFD. + +%BKPCCU COPY UFD/SFD FOR spec + + The program cannot get enough core to copy the indicated User + File Directory or Sub-File Directory. Files for this UFD or SFD + will not be saved, and the program will skip to the next UFD/SFD. + +%BKPCDF CANNOT DELETE FILE error bits (code) spec + + The specified file could not be deleted. The error bits and code + returned are listed in the DECsystem-10 Monitor Calls Manual, + Appendix E. + +%BKPCDS CHECK DISK FILE SHORTER spec + + During a check operation, an end-of-file occurred for the + BACKUP Page 17-18 ______ +BACKUP MESSAGES + + + indicated disk file, even though there is more file data on tape. + +%BKPCFD CHECK FILES ARE DIFFERENT spec + + The check operation determined that the disk and tape versions of + the idicated file are different. + +%BKPCHK CHECKSUM INCONSISTENCY READING spec (BLOCK = n) + + During a read, the computed checksum of the current tape record + did not agree with the checksum stored when the record was + written. + +%BKPCNF CHECK FILE NOT ON DISK spec + + The indicated file could not be found on disk during a check + operation. + +%BKPCOD CANNOT OPEN "file structure" + + The file structure indicated cannot be selected for I/O. The + transfer of files for this structure will be aborted. + +%BKPCTS CHECK TAPE FILE SHORTER spec + + During a check operation, and end-of-file occurred for the + indicated tape file, even though there is more file data on disk. + +%BKPDIO DISK I/O ERROR error bits DURING spec + + A disk I/O error occurred while attempting to read or write the + specified file. The error bits included are those returned by + the monitor GETSTS call. The transfer will be aborted for this + file. + +%BKPFEE ENTER error-code spec + + File enter error for the indicated file. The error code included + is that returned by the monitor, and the error code abbreviation + is listed in the DECsystem-10 Monitor Calls Manual, Appendix E. + +%BKPFLE LOOKUP error-code spec + + File lookup error for the indicated file. The error code + included is that returned by the monitor, and the error code + abbreviation is listed in the DECsystem-10 Monitor Calls Manual, + Appendix E. + +%BKPFRS FRS TAPES NOT SUPPORTED + + On reading a tape, if the tape format seems to correspond to an + FRS tape rather than a BACKUP tape, this message is issued and + BACKUP continues scanning the tape for records in a format which + it understands. + +%BKPHSI HEADER FILE SPEC INCONSISTENCY + + During a restore operation, a consistency check determined that + the end-of-file record for the current file was missed, and the + current record belongs to another file. The transfer will be + aborted for this file. + +%BKPIBL INCORRECT BLOCK LENGTH + BACKUP Page 17-19 ______ +BACKUP MESSAGES + + + During a read, the program encountered a tape record of the wrong + size. The record will be skipped. + +%BKPLF LISTING FILE ERROR error bits (code) spec + + The listing file is closed and appended to after the processing + of each UFD, so that it will be preserved through a system crash + and recovery procedure. If either the LOOKUP or ENTER UUO for + appending to the listing file fails, this message is issued and + no further output is done to the listing file. The error bits + and code returned are listed in the DECsystem-10 Monitor Calls + Manual, Appendix E. + +%BKPNBF NOT BACKUP FORMAT + + The current tape record is not in BACKUP format, and the program + will skip to the next tape record. + +%BKPNEC NOT ENOUGH CORE + + The program cannot get enough core. If this occurs during a + RESTORE, the RESTORE will be aborted. During a Save, the program + will skip to the next structure or User File Directory and + attempt to continue. + +%BKPNFF NO FILES FOUND TO MATCH spec + + No files were found to match the given file specification. + +%BKPRIC RESUME AT INVALID CHECKPOINT ATTEMPTED + + This message indicates that the user instructed BACKUP to + continue saving or checking a file at a checkpoint which was + larger than the actual number of blocks in the file. + +%BKPROD RESTORE OUTPUT DEVICE IS NOT A DISK + + The output device specified for a RESTORE is not a disk. + +%BKPSCE SIZE COPY ERROR spec + + While transferring a file from tape to disk an error was + encountered because the transferred file was not the same size as + the tape file. If this error occurs, please send an SPR. + +%BKPSLE SFD LEVEL EXCEEDED + + While attempting to save needed Sub-File Directories the SFD + level was exceeded. + +%BKPSNF SAVE SET NOT FOUND name + + This message may occur during a RESTORE or CHECK operation and + indicates that the save set named with the last /SSNAME verb + could not be found. + +%BKPTHE TAPE HARDWARE ERROR READING/WRITING spec (BLOCK=n) + + A hardware error occurred. The transferred file may contain + unreliable data. + +%BKPTPE TAPE PARITY ERROR READING/WRITING spec (BLOCK=n) + BACKUP Page 17-20 ______ +BACKUP MESSAGES + + + The hardware detected a parity error. The transferred file may + contain unreliable data. + +%BKPUOE UNTRACEABLE OUTPUT ERROR + + An error was encountered while trying to move data from disk to + tape. + +%BKPURT UNKNOWN RECORD TYPE + + While reading the tape, BACKUP found that the type number of the + current tape record is not within the defined range. The program + will skip to the next tape record. + + + +17.11 CAPACITIES OF DISK MEDIA VERSUS MAGNETIC TAPE __________ __ ____ _____ ______ ________ ____ + +The following table illustrates the maximum capacity of various disk +devices and the approximate number of 2400-foot magnetic tapes +required to hold the same number of blocks. The calculations were +made for 9-channel magnetic tape at 800 bpi. + + No. of magtapes + Required for same + Disk Device Capacity in Blocks capacity + RD10 (Disk) 4000 .139 + + RM10B (Drum) 2700 .094 + + RP02 (Disk Pack) 40000 1.39 + + RP03 (Disk Pack) 80000 2.78 + + RP04 (Disk Pack) 154280 5.37 + + RS04 (Disk) 2048 .071 + + + +17.12 BACKUP TAPE FORMAT ______ ____ ______ + +Note that Backup is designed for two primary functions: performing +system backup and interchanging files between systems. For the latter +function, Backup provides an "interchange" switch which causes system +dependent data to be ignored and only critical file information to be +written on tape. A restore operation in interchange mode also ignores +system dependent data, allowing the operating system to supply +defaults where necessary. Items not included in interchange mode are +noted in the description which follows. + + + +17.12.1 Tape Record Types ____ ______ _____ + +BACKUP tapes are made up of a series of tape records of various types. +Each record is self identifying. All records on the tape are written +at the standard length of 544(10) words, made up of a 32(10) word +header and a 512(10) data area. Even if the data area is not needed, +or is only partially needed it is fully written. All undefined or +unused words are written with zeroes and ignored on read. This +maximizes the probability of reading old tapes. In any case, the tape +format is included in the labels and the save set headers. + BACKUP Page 17-21 ______ +BACKUP TAPE FORMAT + + +The record types are: + + 1. T$LBL -- tape label used to identify reel ID and destruction + date/time. This record is optional, but if present must be + at the start of the tape. + + 2. T$BEG -- Beginning of a save set used to identify when the + save set was written and on what device of what system. It + also includes the save set name. This record is mandatory + and must be the first record of the save set. + + 3. T$END -- end of a save set. This is identical to the T$BEG + record except that it appears at the end. + + 4. T$FIL -- this is the actual data which has been saved. It is + the only type of record which is encrypted. It is + self-identifying as to the position within the file, but + contains only part of the full path name of the file. + + 5. T$UFD -- contains the information for each directory. It + gives all information necessary to re-create the directory. + (Not written in interchange mode.) + + 6. T$EOV -- indicates end of volume (future). + + 7. T$COM -- comment (ignored). + + 8. T$CON -- continuation of save set. This is identical to + T$BEG except that it indicates the continuation of the save + set at the start of a new volume. This ensures that each + volume is completely self identifying. + + + + +17.12.2 Standard Record Format ________ ______ ______ + +Every tape record has the same general format. This consists of a +32(10) word record header followed by one page of data (512(10) +words). All record headers start with the same first twelve words. +The first seven words are: + + 1. G$TYPE -- Record type as described in the previous section. + This is a small positive integer. + + 2. G$SEQ -- record sequence number. This is incremented by one + for each record on the tape. If a record is repeated because + of a tape write error, the number of the repeated record is + the same as that of the original. + + 3. G$RTNM -- relative tape number. This is incremented by one + for each volume. + + 4. G$FLAG -- various flag bits: + + a. GF$EOF -- This flag is set if this is the last tape + record for this disk file. On short files, this can even + be set on the first record of the file. + + b. GF$RPT -- this flag is set if this tape record is a + repeat of the previous record. This is set whenever the + record is rewritten because of a tape write error. + BACKUP Page 17-22 ______ +BACKUP TAPE FORMAT + + + c. GF$NCH -- this flag is set if no checksum has been + computed for the tape record. + + d. GF$SOF -- this flag is set if this is the first tape + record for this disk file. + + 5. G$CHK -- checksum of the tape record. + + 6. G$SIZ -- number of words used for data in this tape record. + + 7. G$LND -- number of words to skip before the data starts. + +The next four words are reserved for future expansion. The twelfth +(last) word in the general section of the record header is reserved +for customer use. The remaining 20 words in the record header vary +for each record type, with the last word of each record header being +reserved for customer use. In interchange mode, customer reserved +words will be written as zero on a save and ignored on a read. + + + +17.12.3 Non-Data Blocks ________ ______ + +The data portion of a tape record is primarily for storing file data, +but may be used for saving some overhead information. Any non-data +information written in the data area of a tape record is prefaced with +a control word of the form: + +LH = type, RH = length in words including this word. + +More than one overhead region can appear. In this case, they follow +each other with no intervening space. The currently defined types for +overhead blocks are: + + 1. O$NAME -- gives the full path identification of the file + without punctuation. The path components are treated as if + the user gave a quoted representation in "DEC Integrated + Command Language". This block consists of sub-blocks in the + standard order: device, directories (top down), file name, + extension, version, generation. Sub-blocks corresponding to + missing fields in the path specification are omitted. Each + sub-block is in the format: + + WORD0: LH = type, RH = length in words including this word. + + The rest of the sub-block is the path field in ASCIZ without + leading or imbedded nulls, terminated by at least one null. + Omitted fields will be defaulted. In interchange mode, only + the name, extension and version are written. In interchange + restore, only name, extension and version are used. + + sub-block type codes are: + + 1 = device + 2 = name + 3 = extension + 4 = version + 5 = generation + 40 = directory (lower directories are 41, 42, ...) + + 2. O$FILE -- a block containing file attributes. The first + section of this block is a fixed length header area + containing in fixed locations either single word attributes + BACKUP Page 17-23 ______ +BACKUP TAPE FORMAT + + + or byte pointers to ASCIZ string attributes located in the + remaining section. All dates and times are in universal + date/time format. In interchange mode only the critical + attributes (starred) will be written, and the rest of this + block will contain zeros. In the description which follows, + the symbols in brackets represent the RIB data from which the + attribute values will be converted. (If none is given, the + location will be zero.) + + a. A$FHLN (*) -- fixed header length in words. + + b. A$FLGS -- flags: + + 1. B$PERM -- permanent (not deletable) [RP.NDL] + + 2. B$TEMP -- temporary + + 3. B$DELE -- already deleted + + 4. B$DLRA -- don't delete for lack of recent access + [RP.ABU} + + 5. B$NQCF -- not quota checked [RP.NQC] + + 6. B$NOCS -- does not have valid checksums [RP.ABC] + + 7. B$CSER -- has checksum error [RP.FCE] + + 8. B$WRER -- has disk write error [RP.FWE] + + 9. B$MRER -- had BACKUP read error on RESTORE [RP.BFA] + + 10. B$DAER -- declared bad by damage assessment [RP.BDA] + + c. A$WRIT (*) -- date/time of last write [RB.CRD and RB.CRT] + + d. A$ALLS (*) -- allocated size in words [.RBALC] + + e. A$MODE (*) -- mode of last write [RB.MOD] + + f. A$LENG (*) --length in bytes (1B0 if > 2^35-1) [.RBSIZ] + + g. A$BSIZ (*) -- byte size (7 or 36). + + h. A$VERS (*) -- version identification (.JBVER format) + [.RBVER] + + i. A$PROT -- protection [RB.PRV]. The protection for + directories appears in the directory attribute block + (O$DIRT). For files, the protection word is defined as + four fields of eight bits each with a "5" stored in the + leftmost three bits in order to avoid looking like a byte + pointer: + + bits 0-2 "5" + + bit 3 reserved for future + + bits 4-11 future access + + bits 12-19 owner access + + bits 20-27 affinity group access + BACKUP Page 17-24 ______ +BACKUP TAPE FORMAT + + + bits 28-35 "world" access + + Each file access field is subdivided into bytes which + describe the attribute, write and read (respectively) + protections associated with the file. A description of + the "world" access field follows, with the associated + TOPS-10 protection given in parentheses, if applicable. + The owner and affinity group (project) fields are + similarly defined. + + 1. PR$SPC (bit 28) -- reserved for special checking. + The rest of the field is special if this bit is set. + + 2. PR$ATR (bits 29-31) -- the attribute subfield is a + 3-bit byte interpreted as follows: + + 0 -- file is completely hidden. + + 1 -- file name is visible (7-6). + + 2 -- file attributes are visible (5-2). + + 3 -- can change unprotected attributes. + + 4-5 -- (future) + + 6 -- can change protection (0). + + 7 -- can delete the file (1). + + 3. PR$WRT (bits 32-33) -- the write access subfield is + defined as: + + 0 -- no write access (7-5). + + 1 -- append (4). + + 2 -- write (3). + + 3 -- superseding generation (2-0). + + 4. PR$RED (bits 34-35) -- the read access subfield is + defined as: + + 0 -- no read access (7). + + 1 -- execute only (6). + + 2 -- can read the file (5-0). + + 3 -- (future). + + j. A$ACCT -- byte pointer to account string + + k. A$NOTE -- byte pointer to annotation string [.RBSPL] + + l. A$CRET -- creation date and time of this generation + + m. A$REDT -- last read date and time of this generation + [RB.ACD] + + n. A$MODT -- monitor set last write date and time [.RBTIM] + BACKUP Page 17-25 ______ +BACKUP TAPE FORMAT + + + o. A$ESTS -- estimated size in words [.RBEST] + + p. A$RADR -- requested disk address [.RBPOS] + + q. A$FSIZ -- maximum file size in words + + r. A$MUSR -- byte pointer to identification of last modifier + + s. A$CUSR -- byte pointer identification of creator [.RBAUT] + + t. A$BKID -- byte pointer to identification of previous + BACKUP [.RBMTA] + + u. A$BKDT -- date and time of last backup + + v. A$NGRT -- number of generations to retain + + w. A$NRDS - number of opens for read this generation + + x. A$NWRT -- number of opens for write this generation + + y. A$USRW -- undefined user word [.RBNCA] + + z. A$PCAW -- privileged customer word [.RBBCA] + + The remainder of this block is reserved for future expansion. + + 3. O$DIRT -- a block containing directory attributes (not + written in interchange mode). The first section of this + block is fixed length header area containing either directory + attributes or pointers to attributes located in the remaining + section. The symbols in brackets represent the RIB data used + for conversion (the location is zero if none is given). The + directory protection word appears in this block rather than + in the O$FILE block (A$PROT is zero for directories). + + a. D$FHLN -- fixed header length in words + + b. D$FLGS -- directory flags: + + 1. DF$FOD -- file only directory + + 2. DF$AAL -- alpha accounts are legal + + 3. DF$RLM -- repeat login messages + + c. D$ACCT -- account number or ASCII byte pointer to account + string + + d. D$PROT -- directory protection [RB.PRV]. The directory + protection word is divided into the same access fields as + the file protection word, A$PROT, but each directory + access field has bits as follows (RIB bits given in + parentheses): + + Bit 28 -- reserved for special checking. The rest of the + field is special if this bits is set. + + Bits 29-31 -- (future) + + Bit 32 -- connect allowed + + Bit 33 -- can open files (4) + BACKUP Page 17-26 ______ +BACKUP TAPE FORMAT + + + Bit 34 -- can create generations (2) + + Bit 35 -- directory can be read (1) + + e. D$FPRT -- default file protection + + f. D$LOGT -- date/time of last login in DEC-10 universal + format [RB.CRD and RB.CRT] + + g. D$GENR -- default number of generations to keep + + h. D$QTF -- first-come-first-served logged-in quota in words + [.RBQTF] + + i. D$QTO -- logged out quota in words [.RBQTO] + + j. D$ACSL -- list of groups which can access this directory + (see below) + + k. D$USRL -- list of groups which this user is in (see + below) + + l. D$PRVL -- privilege list (see below) + + m. D$PSWD -- ASCII byte pointer to password + + The list attribute words given above (D$ACSL, D$USRL, D$PRVL) + may be in any one of the following formats: + + a. an ASCII string pointer + + b. 5B2 + group (or 5B2 + privilege for D$PRVL) + + c. -N,, Relative location of start of list + + If in format (c), each word of the list is 5B2 + group (5B2 + + privilege for D$PRVL) + + 4. O$SYSN -- a block containing the system header line in ASCIZ. + + 5. O$SSNM -- a block containing the user supplied save set name + in ASCIZ (max of 30 characters). This block is omitted if no + save set name was specified. + + + + +17.12.4 Locations in T$LBL Record _________ __ _____ ______ + +This record has no contents in the "data" region. The remaining +locations in the record header are defined as follows: + + 1. L$DATE -- date/time of labelling in DEC-10 universal format + (i.e., LH=DAYS since 17-NOV-1858, RH=FRACTION of day) + + 2. L$FMT -- BACKUP tape format (constant = 1). + + 3. L$BVER -- version of BACKUP writing label in standard .JBVER + format. + + 4. L$MON -- monitor type (%CNMNT). + BACKUP Page 17-27 ______ +BACKUP TAPE FORMAT + + + 5. L$SVER -- system version (%CNDVN). + + 6. L$APR -- APR processor serial number on which this label was + written (integer). + + 7. L$DEV -- physical device on which the tape was written in + SIXBIT. + + 8. L$MTCH -- BTYE (31) 0 (1) 7-track (1) 0 (3) density. Density + is 1=200, 2=556, 3=800, 4=1600, 5=6250. + + 9. L$RLNM -- REELID in SIXBIT. + + 10. L$DSTR -- date/time before which the tape cannot be + scratched. Before this time, the only valid operation is to + append. + + + + +17.12.5 Locations in T$BEG, T$END, T$CON Records _________ __ ______ ______ _____ _______ + +These save set records all have the same format and are distinguished +by their record types and their location on the tape. All items are +filled in at the time of writing. The data area contains two non-data +blocks, types O$SYSN and O$SSNM. Record header locations following +the first standard twelve words are defined as follows: + + 1. S$DATE -- date/time of writing this record in universal + format. + + 2. S$FMT -- BACKUP tape format (constant = 1). + + 3. S$BVER -- BACKUP version in .JBVER format. + + 4. S$MON -- monitor type (%CNMNT). + + 5. S$SVER -- system version (%CNDVN). + + 6. S$APR -- apr serial number on which written. + + 7. S$DEV -- physical name of device on which written in SIXBIT. + + 8. S$MTCH -- BYTE (31) 0 (1) 7-track (1) 0 (3) density. Density + is 1=200, 2=556, 3=800, 4=1600, 5=6250. + + + + +17.12.6 Locations in T$UFD Record _________ __ _____ ______ + +This record is not written in interchange mode. When written, the +data portion contains two or three non-data blocks: types O$NAME, +O$FILE (optional) and O$DIRT. Remaining locations in the header +record contain: + + 1. D$PCHK -- checksum of the O$NAME full path file name block. + + 2. D$LVL -- directory level: 0=UFD, 1=first SFD, etc. + + 3. D$STR -- file structure name stored in the following format: + BYTE (7) data type, length in words, ASCII. (Date types are + defined in the T$FIL section.) + BACKUP Page 17-28 ______ +BACKUP TAPE FORMAT + + +17.12.7 Locations in T$FIL Record _________ __ _____ ______ + +The first tape record for a file contains two non-data blocks, types +O$NAME and O$FILE. There is room for two blocks of file data in the +first tape record, and if the file will completely fit in one tape +record, these will be used. If the file is longer than two blocks, +the file will be started in the second tape record, so its pages will +be lined up with tape records. Each tape record identifies the +logical disk word with which it starts. Remaining locations in the +record header are: + + 1. F$PCHK -- checksum of the full path file name block (O$NAME). + This is just a consistency check for consecutive records of + the file. + + 2. F$RDW -- relative data word of file of the first data word in + this tape record. + + 3. F$PTH -- a twelve word block used to store information + suitable for a restoration of the file. This area is big + enough to hold the entire path to a TOPS-10 file in a UFD and + two SFDS. The path information will be stored in the + standard order of device, UFD, first SFD, file name, + extension; with missing fields omitted. The path + information will be stored in the format: + + BYTE (7) data type, length in words, ASCII + + where data types are defined as: + + device = 001 + + file name = 002 + + extension = 003 + + directory = 040 + + (lower directories = 041,042, ...) + + + + + + + + + + + + + + CHAPTER 18 + + BOOTM _____ + + + +18.1 INTRODUCTION ____________ + +BOOTM is a bootstrap program used for loading the monitor from a +magnetic tape saved in BACKUP format. BOOTM runs in EXEC mode, and +automatically loads itself into the top 2K of memory. You load BOOTM +either from magnetic tape via the READIN facility or from paper tape. + + + +18.2 OPERATION _________ + +DIGITAL supplies BOOTM on either a paper tape or a bootstrap magnetic +tape. + + + +18.2.1 Load From Paper-tape (KA/KI Only) ____ ____ __________ ______ _____ + +You should follow the steps outlined below to load BOOTM from paper +tape. + + 1. Load the BOOTM paper tape into the paper-tape reader. + + 2. Set the READIN device switches to 104. + + 3. Press STOP, RESET, and READIN. + + 4. When the paper tape has been read, BOOTM types: + + BOOTM V4(16) + BTM> + + The prompt characters, indicating that you can type a + command, are BTM>. + + 5. Type a command string and press the RETURN key. + + 6. After BOOTM processes the command you typed, BOOTM either + restarts itself or transfers to the newly loaded program. + The action BOOTM takes depends on the command you type. + + BOOTM Page 18-2 _____ +OPERATION + + +18.2.2 Load From Magnetic Tape ____ ____ ________ ____ + +You should follow the steps outlined below to load BOOTM from magnetic +tape. + + 1. Place the BOOTM tape on magnetic tape drive 0 (e.g., MTA0). + If you're using a DX10 controller, you can use any drive. + + 2. Set the READIN switches to 340. When using a DX10 + controller, set the switches to 220. + + 3. Press STOP, RESET, and READIN. + + 4. When the magnetic tape has been read, BOOTM types: + + BOOTM V4(16) + BTM> + + The prompt characters, indicating that you can type a + command, are BTM>. + + 5. Type a command string and press the RETURN key. + + 6. After BOOTM processes the command you typed, BOOTM either + restarts itself or transfers to the newly loaded program. + The action BOOTM takes depends on the command you type. + + + + +18.3 COMMAND FORMAT _______ ______ + +The general format of a BOOTM command is shown below. + + structure:file.ext[proj,prog]/switch + +where: structure represents a file structure name within the disk + file system (as saved by BACKUP). The default is DSKB. + + file.ext is the name and extension of the file involved in the + loading operation. The default is SYSTEM.EXE. + + [proj,programmer] is the directory in which the specified file + can be found. The default is [1,4]. + + /switch is an optional BOOTM switch that specifies what + operation or option BOOTM should perform. The available + options and operations are listed in Section 6.3.1. + + + +18.3.1 Options and Operations _______ ___ __________ + +If you do not specify a switch in the command, 1) BOOTM finds the +specified file, 2) clears memory, 3) reads the specified file into +memory, 4) sets the PROGRAM START ADDRESS, and 5) starts the program +at that address. The default file used is DSKB:SYSTEM.EXE[1,4]. +BOOTM positions the tape to the second file on the tape before it +starts the program. + +The possible switches that you can specify in the BOOTM command line +are listed below. + BOOTM Page 18-3 _____ +COMMAND FORMAT + + + /LOAD BOOTM performs all the operations listed above, + except that it does not start the program (i.e., + does not perform step 5). + + /START:n BOOTM performs all the operations listed above, + except it starts the program at location n. The + default value for n is the start address specified + in the file. + + /NOREWIND BOOTM is disabled from repositioning the tape to + the second file, which is assumed to be a copy of + BACKUP.EXE. + + /DENSITY:d Set the tape read density to the value of d. + Legal values are 200, 556, 800, and 1600. + + /kontroller:u Inform BOOTM what type of tape controller you are + reading from and the unit "u" that has the tape + mounted. Legal values for "kontroller" are TM10, + TX01, TM02, and TC10. If READIN was done from + either a TM10 or a TX01, then it is not necessary + to specify this switch. The default tape drive is + the unit that a READIN was performed on if a TM10 + or a TX01 was used. If BOOTM was read in from a + device other than magtape, then the default is + TM10 unit 0. If a TC10 controller is used, it + must be specified by a /TC10 switch. The default + value for u is unit #0. Example: /TX01:2 + specifies unit 2 on the TX01 controller. + + /REWIND This operation will rewind the tape to load point. + /DENSITY and /kontroller above may be used in + conjunction with this switch; however, no + filename can be given. + + /SKIP This operation will skip forward over one file. + Options 5 and 6 above may be used in conjunction + with this command; however, no filename can be + given. + + + +18.4 ERRORS ______ + +Whenever BOOTM encounters an error, the following style of error +message appears: + + 1. The user terminal end-of-line bell is rung; + + 2. The string ?BTM followed by a 3-character mnemonic followed + by the error message text terminated by a carriage return and + line feed; + + 3. BOOTM is then restarted. + + BOOTM Page 18-4 _____ +ERRORS + + +18.4.1 Error Messages _____ ________ + + + ?BTMIPP - Invalid PROJ,PROG number + ?BTMCME - Command error + ?BTMISW - Illegal switch or argument + ?BTMFNF - File not found + ?BTMTSF - Tape mark in save file + ?BTMSFI - Save file inconsistent + ?BTMNSA - No start address + ?BTMNDL - Not an EXE file or directory too long + ?BTMPNM - Page not monotonically increasing + ?BTMTRE - Tape read error + ?BTMCSD - Cannot start DX10 + ?BTMCSE - Channel synchronization error + ?BTMNMS - No magtape status + ?BTMFDE - Fatal DX10 error or drive off-line + ?BTMNES - Not ending status (TU70 only) + ?BTMNCS - Not CU status (TU70 only) + + + +18.5 ASSEMBLY INSTRUCTIONS ________ ____________ + +The following feature test switches are available in BOOTM: + + + FTEXE Include EXE file support (default) + FTFRS Include FRS/BACKUP file format (default) + FTTU70 Include TU70 support (default) + FTTC10 Include TC10 support (default) + MAGRIM Assemble in MAGRIM format (default) + PTPSW Make paper tape version (normally off) + CORE Value set to 5000 (default) used to determine where to + readin BOOTM before relocation. + DEBUG Make debug version + + +Assembly instructions: + + 1. To make a paper tape version (location independent): + + .MAKE BTMPTP.MAC + *IPTPSW==1 + MAGRIM==0 + $EX$$ + .R MACRO + *PTP:=BTMPTP,BOOTM + + 2. To make a file that can be copied to a magtape for READIN, + just assemble with no special switches. + + 3. To make a file that can be loaded with DXLD to make a TU70 + readin tape: + + .MAKE BTMDX.MAC + *IMAGRIM==0 + $EX$$ + .LOAD DXLD,BTMDX+BOOTM + .ASSIGN DSK OUT + .START ;This produces BOOTM.RDI + + BOOTM Page 18-5 _____ +EXAMPLES + + +18.6 EXAMPLES ________ + +To retrieve and run a fresh monitor from a BACKUP format magtape +containing DSKB:SYSTEM.EXE(1,4), type a carriage return only. + +To rewind a tape on TM10 drive #3 type: + + /REWIND/TM10:3 + +To load RV765 from DSKB:[10,2362] on a BACKUP format tape and start +EXEC DDT type: + + RV765[10,2362]/START:401 + + + +18.7 SPECIAL 1080 INSTRUCTIONS _______ ____ ____________ + +There is no readin on KL10 CPUs. See the Operators Guide for +instructions for readin in BOOTM on 1080s. Be sure to specify /TX01, +when reading in a tape on a TU70. diff --git a/assets/files/tops10/mig603.pdf b/assets/files/tops10/mig603.pdf new file mode 100644 index 0000000..1808197 Binary files /dev/null and b/assets/files/tops10/mig603.pdf differ diff --git a/assets/files/xlib/xlib-article-files.tar.gz b/assets/files/xlib/xlib-article-files.tar.gz new file mode 100644 index 0000000..1cf820c Binary files /dev/null and b/assets/files/xlib/xlib-article-files.tar.gz differ diff --git a/assets/img/dragonfly/01-big.jpeg b/assets/img/dragonfly/01-big.jpeg new file mode 100644 index 0000000..249bf61 Binary files /dev/null and b/assets/img/dragonfly/01-big.jpeg differ diff --git a/assets/img/dragonfly/01.jpeg b/assets/img/dragonfly/01.jpeg new file mode 100644 index 0000000..5fb5010 Binary files /dev/null and b/assets/img/dragonfly/01.jpeg differ diff --git a/assets/img/fossil/fb-content-large.jpeg b/assets/img/fossil/fb-content-large.jpeg new file mode 100644 index 0000000..9f956a2 Binary files /dev/null and b/assets/img/fossil/fb-content-large.jpeg differ diff --git a/assets/img/fossil/fb-content-small.jpeg b/assets/img/fossil/fb-content-small.jpeg new file mode 100644 index 0000000..1911335 Binary files /dev/null and b/assets/img/fossil/fb-content-small.jpeg differ diff --git a/assets/img/fossil/fb-large.jpeg b/assets/img/fossil/fb-large.jpeg new file mode 100644 index 0000000..78507ca Binary files /dev/null and b/assets/img/fossil/fb-large.jpeg differ diff --git a/assets/img/fossil/fb-small.jpeg b/assets/img/fossil/fb-small.jpeg new file mode 100644 index 0000000..bc1097c Binary files /dev/null and b/assets/img/fossil/fb-small.jpeg differ diff --git a/assets/img/genode/01.png b/assets/img/genode/01.png new file mode 100644 index 0000000..de5fff6 Binary files /dev/null and b/assets/img/genode/01.png differ diff --git a/assets/img/genode/02.png b/assets/img/genode/02.png new file mode 100644 index 0000000..d4b3749 Binary files /dev/null and b/assets/img/genode/02.png differ diff --git a/assets/img/genode/03.png b/assets/img/genode/03.png new file mode 100644 index 0000000..0473174 Binary files /dev/null and b/assets/img/genode/03.png differ diff --git a/assets/img/genode/04.png b/assets/img/genode/04.png new file mode 100644 index 0000000..1d15fe8 Binary files /dev/null and b/assets/img/genode/04.png differ diff --git a/assets/img/genode/05.png b/assets/img/genode/05.png new file mode 100644 index 0000000..72ed8e1 Binary files /dev/null and b/assets/img/genode/05.png differ diff --git a/assets/img/genode/06.png b/assets/img/genode/06.png new file mode 100644 index 0000000..3b07d44 Binary files /dev/null and b/assets/img/genode/06.png differ diff --git a/assets/img/genode/07.png b/assets/img/genode/07.png new file mode 100644 index 0000000..3592a76 Binary files /dev/null and b/assets/img/genode/07.png differ diff --git a/assets/img/genode/08.png b/assets/img/genode/08.png new file mode 100644 index 0000000..5dfd083 Binary files /dev/null and b/assets/img/genode/08.png differ diff --git a/assets/img/genode/08a.png b/assets/img/genode/08a.png new file mode 100644 index 0000000..fbf21a8 Binary files /dev/null and b/assets/img/genode/08a.png differ diff --git a/assets/img/genode/09.png b/assets/img/genode/09.png new file mode 100644 index 0000000..8eccbd4 Binary files /dev/null and b/assets/img/genode/09.png differ diff --git a/assets/img/genode/10.png b/assets/img/genode/10.png new file mode 100644 index 0000000..b368a63 Binary files /dev/null and b/assets/img/genode/10.png differ diff --git a/assets/img/genode/11.png b/assets/img/genode/11.png new file mode 100644 index 0000000..17982c1 Binary files /dev/null and b/assets/img/genode/11.png differ diff --git a/assets/img/genode/12.png b/assets/img/genode/12.png new file mode 100644 index 0000000..b00d0be Binary files /dev/null and b/assets/img/genode/12.png differ diff --git a/assets/img/genode/13.png b/assets/img/genode/13.png new file mode 100644 index 0000000..aa4bf04 Binary files /dev/null and b/assets/img/genode/13.png differ diff --git a/assets/img/genode/14.png b/assets/img/genode/14.png new file mode 100644 index 0000000..b490ea7 Binary files /dev/null and b/assets/img/genode/14.png differ diff --git a/assets/img/genode/15.png b/assets/img/genode/15.png new file mode 100644 index 0000000..6b47f11 Binary files /dev/null and b/assets/img/genode/15.png differ diff --git a/assets/img/genode/16.png b/assets/img/genode/16.png new file mode 100644 index 0000000..76177f5 Binary files /dev/null and b/assets/img/genode/16.png differ diff --git a/assets/img/genode/17.png b/assets/img/genode/17.png new file mode 100644 index 0000000..58587bb Binary files /dev/null and b/assets/img/genode/17.png differ diff --git a/assets/img/genode/18.png b/assets/img/genode/18.png new file mode 100644 index 0000000..cb9a4dd Binary files /dev/null and b/assets/img/genode/18.png differ diff --git a/assets/img/genode/19.png b/assets/img/genode/19.png new file mode 100644 index 0000000..fb1843b Binary files /dev/null and b/assets/img/genode/19.png differ diff --git a/assets/img/genode/20.png b/assets/img/genode/20.png new file mode 100644 index 0000000..7acc7f2 Binary files /dev/null and b/assets/img/genode/20.png differ diff --git a/assets/img/genode/21.png b/assets/img/genode/21.png new file mode 100644 index 0000000..1340f39 Binary files /dev/null and b/assets/img/genode/21.png differ diff --git a/assets/img/genode/22.png b/assets/img/genode/22.png new file mode 100644 index 0000000..6299978 Binary files /dev/null and b/assets/img/genode/22.png differ diff --git a/assets/img/genode/23.png b/assets/img/genode/23.png new file mode 100644 index 0000000..4e39698 Binary files /dev/null and b/assets/img/genode/23.png differ diff --git a/assets/img/genode/24.png b/assets/img/genode/24.png new file mode 100644 index 0000000..98eef47 Binary files /dev/null and b/assets/img/genode/24.png differ diff --git a/assets/img/genode/25.png b/assets/img/genode/25.png new file mode 100644 index 0000000..5e49260 Binary files /dev/null and b/assets/img/genode/25.png differ diff --git a/assets/img/genode/26.png b/assets/img/genode/26.png new file mode 100644 index 0000000..7cb79ea Binary files /dev/null and b/assets/img/genode/26.png differ diff --git a/assets/img/genode/27.png b/assets/img/genode/27.png new file mode 100644 index 0000000..0e6e86a Binary files /dev/null and b/assets/img/genode/27.png differ diff --git a/assets/img/genode/28.png b/assets/img/genode/28.png new file mode 100644 index 0000000..07efb21 Binary files /dev/null and b/assets/img/genode/28.png differ diff --git a/assets/img/genode/29.png b/assets/img/genode/29.png new file mode 100644 index 0000000..aaf8b86 Binary files /dev/null and b/assets/img/genode/29.png differ diff --git a/assets/img/genode/30.png b/assets/img/genode/30.png new file mode 100644 index 0000000..4754538 Binary files /dev/null and b/assets/img/genode/30.png differ diff --git a/assets/img/genode/31.png b/assets/img/genode/31.png new file mode 100644 index 0000000..2dcadde Binary files /dev/null and b/assets/img/genode/31.png differ diff --git a/assets/img/genode/32.png b/assets/img/genode/32.png new file mode 100644 index 0000000..d615dc1 Binary files /dev/null and b/assets/img/genode/32.png differ diff --git a/assets/img/genode/33.png b/assets/img/genode/33.png new file mode 100644 index 0000000..01c2e49 Binary files /dev/null and b/assets/img/genode/33.png differ diff --git a/assets/img/genode/34.png b/assets/img/genode/34.png new file mode 100644 index 0000000..c11ea28 Binary files /dev/null and b/assets/img/genode/34.png differ diff --git a/assets/img/genode/35.png b/assets/img/genode/35.png new file mode 100644 index 0000000..ab703ed Binary files /dev/null and b/assets/img/genode/35.png differ diff --git a/assets/img/genode/36.png b/assets/img/genode/36.png new file mode 100644 index 0000000..7ed5e81 Binary files /dev/null and b/assets/img/genode/36.png differ diff --git a/assets/img/genode/37.png b/assets/img/genode/37.png new file mode 100644 index 0000000..734be4c Binary files /dev/null and b/assets/img/genode/37.png differ diff --git a/assets/img/genode/38.png b/assets/img/genode/38.png new file mode 100644 index 0000000..e48a581 Binary files /dev/null and b/assets/img/genode/38.png differ diff --git a/assets/img/genode/39.png b/assets/img/genode/39.png new file mode 100644 index 0000000..742b0f4 Binary files /dev/null and b/assets/img/genode/39.png differ diff --git a/assets/img/genode/40.png b/assets/img/genode/40.png new file mode 100644 index 0000000..c3d045e Binary files /dev/null and b/assets/img/genode/40.png differ diff --git a/assets/img/genode/41.png b/assets/img/genode/41.png new file mode 100644 index 0000000..3b2a78a Binary files /dev/null and b/assets/img/genode/41.png differ diff --git a/assets/img/genode/42.png b/assets/img/genode/42.png new file mode 100644 index 0000000..a087623 Binary files /dev/null and b/assets/img/genode/42.png differ diff --git a/assets/img/genode/43.png b/assets/img/genode/43.png new file mode 100644 index 0000000..5526963 Binary files /dev/null and b/assets/img/genode/43.png differ diff --git a/assets/img/its/knight-01.png b/assets/img/its/knight-01.png new file mode 100644 index 0000000..b9a04ff Binary files /dev/null and b/assets/img/its/knight-01.png differ diff --git a/assets/img/its/knight-02.png b/assets/img/its/knight-02.png new file mode 100644 index 0000000..8a4528a Binary files /dev/null and b/assets/img/its/knight-02.png differ diff --git a/assets/img/lisp/Terminal_001.png b/assets/img/lisp/Terminal_001.png new file mode 100644 index 0000000..678fb26 Binary files /dev/null and b/assets/img/lisp/Terminal_001.png differ diff --git a/assets/img/lisp/Terminal_002.png b/assets/img/lisp/Terminal_002.png new file mode 100644 index 0000000..8e08d15 Binary files /dev/null and b/assets/img/lisp/Terminal_002.png differ diff --git a/assets/img/lisp/Terminal_003.png b/assets/img/lisp/Terminal_003.png new file mode 100644 index 0000000..e66f4d5 Binary files /dev/null and b/assets/img/lisp/Terminal_003.png differ diff --git a/assets/img/lisp/Terminal_004.png b/assets/img/lisp/Terminal_004.png new file mode 100644 index 0000000..f0d9106 Binary files /dev/null and b/assets/img/lisp/Terminal_004.png differ diff --git a/assets/img/lisp/Terminal_005.png b/assets/img/lisp/Terminal_005.png new file mode 100644 index 0000000..d8139b2 Binary files /dev/null and b/assets/img/lisp/Terminal_005.png differ diff --git a/assets/img/lisp/Terminal_006.png b/assets/img/lisp/Terminal_006.png new file mode 100644 index 0000000..5fcc14f Binary files /dev/null and b/assets/img/lisp/Terminal_006.png differ diff --git a/assets/img/lisp/Terminal_007.png b/assets/img/lisp/Terminal_007.png new file mode 100644 index 0000000..6cd578f Binary files /dev/null and b/assets/img/lisp/Terminal_007.png differ diff --git a/assets/img/lisp/Terminal_008.png b/assets/img/lisp/Terminal_008.png new file mode 100644 index 0000000..555f8e9 Binary files /dev/null and b/assets/img/lisp/Terminal_008.png differ diff --git a/assets/img/scheme/01.png b/assets/img/scheme/01.png new file mode 100644 index 0000000..f19f00a Binary files /dev/null and b/assets/img/scheme/01.png differ diff --git a/assets/img/scheme/02.png b/assets/img/scheme/02.png new file mode 100644 index 0000000..035be8c Binary files /dev/null and b/assets/img/scheme/02.png differ diff --git a/assets/img/scheme/03.png b/assets/img/scheme/03.png new file mode 100644 index 0000000..4d7bdad Binary files /dev/null and b/assets/img/scheme/03.png differ diff --git a/assets/img/t430/01.png b/assets/img/t430/01.png new file mode 100644 index 0000000..fff22e2 Binary files /dev/null and b/assets/img/t430/01.png differ diff --git a/assets/img/t430/02-big.png b/assets/img/t430/02-big.png new file mode 100644 index 0000000..e3708bd Binary files /dev/null and b/assets/img/t430/02-big.png differ diff --git a/assets/img/t430/02.png b/assets/img/t430/02.png new file mode 100644 index 0000000..75505bf Binary files /dev/null and b/assets/img/t430/02.png differ diff --git a/assets/img/vi/four.png b/assets/img/vi/four.png new file mode 100644 index 0000000..b4166e0 Binary files /dev/null and b/assets/img/vi/four.png differ diff --git a/assets/img/vi/motions-notecard.jpg b/assets/img/vi/motions-notecard.jpg new file mode 100644 index 0000000..3635acc Binary files /dev/null and b/assets/img/vi/motions-notecard.jpg differ diff --git a/assets/img/vi/one.jpg b/assets/img/vi/one.jpg new file mode 100644 index 0000000..ad6c0c6 Binary files /dev/null and b/assets/img/vi/one.jpg differ diff --git a/assets/img/vi/three.png b/assets/img/vi/three.png new file mode 100644 index 0000000..a7a5fc2 Binary files /dev/null and b/assets/img/vi/three.png differ diff --git a/assets/img/vi/two.png b/assets/img/vi/two.png new file mode 100644 index 0000000..5361830 Binary files /dev/null and b/assets/img/vi/two.png differ diff --git a/assets/img/xlib/01.png b/assets/img/xlib/01.png new file mode 100644 index 0000000..5c7a21c Binary files /dev/null and b/assets/img/xlib/01.png differ diff --git a/assets/img/xwindows/01-big.png b/assets/img/xwindows/01-big.png new file mode 100644 index 0000000..734e2dd Binary files /dev/null and b/assets/img/xwindows/01-big.png differ diff --git a/assets/img/xwindows/01-small.jpeg b/assets/img/xwindows/01-small.jpeg new file mode 100644 index 0000000..56afade Binary files /dev/null and b/assets/img/xwindows/01-small.jpeg differ diff --git a/assets/img/xwindows/02.png b/assets/img/xwindows/02.png new file mode 100644 index 0000000..de443d3 Binary files /dev/null and b/assets/img/xwindows/02.png differ diff --git a/assets/img/xwindows/03.png b/assets/img/xwindows/03.png new file mode 100644 index 0000000..36a1b28 Binary files /dev/null and b/assets/img/xwindows/03.png differ diff --git a/assets/img/xwindows/04.png b/assets/img/xwindows/04.png new file mode 100644 index 0000000..d5175d6 Binary files /dev/null and b/assets/img/xwindows/04.png differ diff --git a/assets/img/xwindows/05.png b/assets/img/xwindows/05.png new file mode 100644 index 0000000..024b3e3 Binary files /dev/null and b/assets/img/xwindows/05.png differ diff --git a/assets/img/xwindows/06.png b/assets/img/xwindows/06.png new file mode 100644 index 0000000..0ceb21a Binary files /dev/null and b/assets/img/xwindows/06.png differ diff --git a/assets/mermaid-9.3.0/mermaid.js b/assets/mermaid-9.3.0/mermaid.js new file mode 100644 index 0000000..d241aa4 --- /dev/null +++ b/assets/mermaid-9.3.0/mermaid.js @@ -0,0 +1,41781 @@ +var __defProp = Object.defineProperty; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; +(function(global2, factory) { + typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, global2.mermaid = factory()); +})(this, function() { + "use strict"; + var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {}; + function commonjsRequire(path2) { + throw new Error('Could not dynamically require "' + path2 + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); + } + var moment_min = { exports: {} }; + (function(module2, exports2) { + !function(e, t) { + module2.exports = t(); + }(commonjsGlobal, function() { + var H; + function f() { + return H.apply(null, arguments); + } + function a(e3) { + return e3 instanceof Array || "[object Array]" === Object.prototype.toString.call(e3); + } + function F(e3) { + return null != e3 && "[object Object]" === Object.prototype.toString.call(e3); + } + function c2(e3, t4) { + return Object.prototype.hasOwnProperty.call(e3, t4); + } + function L(e3) { + if (Object.getOwnPropertyNames) + return 0 === Object.getOwnPropertyNames(e3).length; + for (var t4 in e3) + if (c2(e3, t4)) + return; + return 1; + } + function o(e3) { + return void 0 === e3; + } + function u(e3) { + return "number" == typeof e3 || "[object Number]" === Object.prototype.toString.call(e3); + } + function V(e3) { + return e3 instanceof Date || "[object Date]" === Object.prototype.toString.call(e3); + } + function G(e3, t4) { + for (var n2 = [], s2 = e3.length, i3 = 0; i3 < s2; ++i3) + n2.push(t4(e3[i3], i3)); + return n2; + } + function E(e3, t4) { + for (var n2 in t4) + c2(t4, n2) && (e3[n2] = t4[n2]); + return c2(t4, "toString") && (e3.toString = t4.toString), c2(t4, "valueOf") && (e3.valueOf = t4.valueOf), e3; + } + function l(e3, t4, n2, s2) { + return Pt(e3, t4, n2, s2, true).utc(); + } + function m(e3) { + return null == e3._pf && (e3._pf = { empty: false, unusedTokens: [], unusedInput: [], overflow: -2, charsLeftOver: 0, nullInput: false, invalidEra: null, invalidMonth: null, invalidFormat: false, userInvalidated: false, iso: false, parsedDateParts: [], era: null, meridiem: null, rfc2822: false, weekdayMismatch: false }), e3._pf; + } + function A(e3) { + if (null == e3._isValid) { + var t4 = m(e3), n2 = j.call(t4.parsedDateParts, function(e4) { + return null != e4; + }), n2 = !isNaN(e3._d.getTime()) && t4.overflow < 0 && !t4.empty && !t4.invalidEra && !t4.invalidMonth && !t4.invalidWeekday && !t4.weekdayMismatch && !t4.nullInput && !t4.invalidFormat && !t4.userInvalidated && (!t4.meridiem || t4.meridiem && n2); + if (e3._strict && (n2 = n2 && 0 === t4.charsLeftOver && 0 === t4.unusedTokens.length && void 0 === t4.bigHour), null != Object.isFrozen && Object.isFrozen(e3)) + return n2; + e3._isValid = n2; + } + return e3._isValid; + } + function I(e3) { + var t4 = l(NaN); + return null != e3 ? E(m(t4), e3) : m(t4).userInvalidated = true, t4; + } + var j = Array.prototype.some || function(e3) { + for (var t4 = Object(this), n2 = t4.length >>> 0, s2 = 0; s2 < n2; s2++) + if (s2 in t4 && e3.call(this, t4[s2], s2, t4)) + return true; + return false; + }, Z = f.momentProperties = [], z = false; + function $(e3, t4) { + var n2, s2, i3, r2 = Z.length; + if (o(t4._isAMomentObject) || (e3._isAMomentObject = t4._isAMomentObject), o(t4._i) || (e3._i = t4._i), o(t4._f) || (e3._f = t4._f), o(t4._l) || (e3._l = t4._l), o(t4._strict) || (e3._strict = t4._strict), o(t4._tzm) || (e3._tzm = t4._tzm), o(t4._isUTC) || (e3._isUTC = t4._isUTC), o(t4._offset) || (e3._offset = t4._offset), o(t4._pf) || (e3._pf = m(t4)), o(t4._locale) || (e3._locale = t4._locale), 0 < r2) + for (n2 = 0; n2 < r2; n2++) + o(i3 = t4[s2 = Z[n2]]) || (e3[s2] = i3); + return e3; + } + function q(e3) { + $(this, e3), this._d = new Date(null != e3._d ? e3._d.getTime() : NaN), this.isValid() || (this._d = new Date(NaN)), false === z && (z = true, f.updateOffset(this), z = false); + } + function h(e3) { + return e3 instanceof q || null != e3 && null != e3._isAMomentObject; + } + function B(e3) { + false === f.suppressDeprecationWarnings && "undefined" != typeof console && console.warn && console.warn("Deprecation warning: " + e3); + } + function e(r2, a2) { + var o2 = true; + return E(function() { + if (null != f.deprecationHandler && f.deprecationHandler(null, r2), o2) { + for (var e3, t4, n2 = [], s2 = arguments.length, i3 = 0; i3 < s2; i3++) { + if (e3 = "", "object" == typeof arguments[i3]) { + for (t4 in e3 += "\n[" + i3 + "] ", arguments[0]) + c2(arguments[0], t4) && (e3 += t4 + ": " + arguments[0][t4] + ", "); + e3 = e3.slice(0, -2); + } else + e3 = arguments[i3]; + n2.push(e3); + } + B(r2 + "\nArguments: " + Array.prototype.slice.call(n2).join("") + "\n" + new Error().stack), o2 = false; + } + return a2.apply(this, arguments); + }, a2); + } + var J = {}; + function Q(e3, t4) { + null != f.deprecationHandler && f.deprecationHandler(e3, t4), J[e3] || (B(t4), J[e3] = true); + } + function d(e3) { + return "undefined" != typeof Function && e3 instanceof Function || "[object Function]" === Object.prototype.toString.call(e3); + } + function X(e3, t4) { + var n2, s2 = E({}, e3); + for (n2 in t4) + c2(t4, n2) && (F(e3[n2]) && F(t4[n2]) ? (s2[n2] = {}, E(s2[n2], e3[n2]), E(s2[n2], t4[n2])) : null != t4[n2] ? s2[n2] = t4[n2] : delete s2[n2]); + for (n2 in e3) + c2(e3, n2) && !c2(t4, n2) && F(e3[n2]) && (s2[n2] = E({}, s2[n2])); + return s2; + } + function K2(e3) { + null != e3 && this.set(e3); + } + f.suppressDeprecationWarnings = false, f.deprecationHandler = null; + var ee = Object.keys || function(e3) { + var t4, n2 = []; + for (t4 in e3) + c2(e3, t4) && n2.push(t4); + return n2; + }; + function r(e3, t4, n2) { + var s2 = "" + Math.abs(e3); + return (0 <= e3 ? n2 ? "+" : "" : "-") + Math.pow(10, Math.max(0, t4 - s2.length)).toString().substr(1) + s2; + } + var te = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g, ne = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, se = {}, ie = {}; + function s(e3, t4, n2, s2) { + var i3 = "string" == typeof s2 ? function() { + return this[s2](); + } : s2; + e3 && (ie[e3] = i3), t4 && (ie[t4[0]] = function() { + return r(i3.apply(this, arguments), t4[1], t4[2]); + }), n2 && (ie[n2] = function() { + return this.localeData().ordinal(i3.apply(this, arguments), e3); + }); + } + function re2(e3, t4) { + return e3.isValid() ? (t4 = ae(t4, e3.localeData()), se[t4] = se[t4] || function(s2) { + for (var e4, i3 = s2.match(te), t5 = 0, r2 = i3.length; t5 < r2; t5++) + ie[i3[t5]] ? i3[t5] = ie[i3[t5]] : i3[t5] = (e4 = i3[t5]).match(/\[[\s\S]/) ? e4.replace(/^\[|\]$/g, "") : e4.replace(/\\/g, ""); + return function(e6) { + for (var t6 = "", n2 = 0; n2 < r2; n2++) + t6 += d(i3[n2]) ? i3[n2].call(e6, s2) : i3[n2]; + return t6; + }; + }(t4), se[t4](e3)) : e3.localeData().invalidDate(); + } + function ae(e3, t4) { + var n2 = 5; + function s2(e4) { + return t4.longDateFormat(e4) || e4; + } + for (ne.lastIndex = 0; 0 <= n2 && ne.test(e3); ) + e3 = e3.replace(ne, s2), ne.lastIndex = 0, --n2; + return e3; + } + var oe = {}; + function t(e3, t4) { + var n2 = e3.toLowerCase(); + oe[n2] = oe[n2 + "s"] = oe[t4] = e3; + } + function _2(e3) { + return "string" == typeof e3 ? oe[e3] || oe[e3.toLowerCase()] : void 0; + } + function ue(e3) { + var t4, n2, s2 = {}; + for (n2 in e3) + c2(e3, n2) && (t4 = _2(n2)) && (s2[t4] = e3[n2]); + return s2; + } + var le = {}; + function n(e3, t4) { + le[e3] = t4; + } + function he(e3) { + return e3 % 4 == 0 && e3 % 100 != 0 || e3 % 400 == 0; + } + function y2(e3) { + return e3 < 0 ? Math.ceil(e3) || 0 : Math.floor(e3); + } + function g(e3) { + var e3 = +e3, t4 = 0; + return t4 = 0 != e3 && isFinite(e3) ? y2(e3) : t4; + } + function de(t4, n2) { + return function(e3) { + return null != e3 ? (fe(this, t4, e3), f.updateOffset(this, n2), this) : ce(this, t4); + }; + } + function ce(e3, t4) { + return e3.isValid() ? e3._d["get" + (e3._isUTC ? "UTC" : "") + t4]() : NaN; + } + function fe(e3, t4, n2) { + e3.isValid() && !isNaN(n2) && ("FullYear" === t4 && he(e3.year()) && 1 === e3.month() && 29 === e3.date() ? (n2 = g(n2), e3._d["set" + (e3._isUTC ? "UTC" : "") + t4](n2, e3.month(), We(n2, e3.month()))) : e3._d["set" + (e3._isUTC ? "UTC" : "") + t4](n2)); + } + var i2 = /\d/, w2 = /\d\d/, me = /\d{3}/, _e = /\d{4}/, ye = /[+-]?\d{6}/, p = /\d\d?/, ge = /\d\d\d\d?/, we = /\d\d\d\d\d\d?/, pe = /\d{1,3}/, ke = /\d{1,4}/, ve = /[+-]?\d{1,6}/, Me = /\d+/, De = /[+-]?\d+/, Se = /Z|[+-]\d\d:?\d\d/gi, Ye = /Z|[+-]\d\d(?::?\d\d)?/gi, k = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i; + function v(e3, n2, s2) { + be[e3] = d(n2) ? n2 : function(e4, t4) { + return e4 && s2 ? s2 : n2; + }; + } + function Oe(e3, t4) { + return c2(be, e3) ? be[e3](t4._strict, t4._locale) : new RegExp(M(e3.replace("\\", "").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function(e4, t5, n2, s2, i3) { + return t5 || n2 || s2 || i3; + }))); + } + function M(e3) { + return e3.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); + } + var be = {}, xe = {}; + function D(e3, n2) { + var t4, s2, i3 = n2; + for ("string" == typeof e3 && (e3 = [e3]), u(n2) && (i3 = function(e4, t5) { + t5[n2] = g(e4); + }), s2 = e3.length, t4 = 0; t4 < s2; t4++) + xe[e3[t4]] = i3; + } + function Te(e3, i3) { + D(e3, function(e4, t4, n2, s2) { + n2._w = n2._w || {}, i3(e4, n2._w, n2, s2); + }); + } + var S, Y = 0, O = 1, b = 2, x2 = 3, T = 4, N = 5, Ne = 6, Pe = 7, Re = 8; + function We(e3, t4) { + if (isNaN(e3) || isNaN(t4)) + return NaN; + var n2 = (t4 % (n2 = 12) + n2) % n2; + return e3 += (t4 - n2) / 12, 1 == n2 ? he(e3) ? 29 : 28 : 31 - n2 % 7 % 2; + } + S = Array.prototype.indexOf || function(e3) { + for (var t4 = 0; t4 < this.length; ++t4) + if (this[t4] === e3) + return t4; + return -1; + }, s("M", ["MM", 2], "Mo", function() { + return this.month() + 1; + }), s("MMM", 0, 0, function(e3) { + return this.localeData().monthsShort(this, e3); + }), s("MMMM", 0, 0, function(e3) { + return this.localeData().months(this, e3); + }), t("month", "M"), n("month", 8), v("M", p), v("MM", p, w2), v("MMM", function(e3, t4) { + return t4.monthsShortRegex(e3); + }), v("MMMM", function(e3, t4) { + return t4.monthsRegex(e3); + }), D(["M", "MM"], function(e3, t4) { + t4[O] = g(e3) - 1; + }), D(["MMM", "MMMM"], function(e3, t4, n2, s2) { + s2 = n2._locale.monthsParse(e3, s2, n2._strict); + null != s2 ? t4[O] = s2 : m(n2).invalidMonth = e3; + }); + var Ce = "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), Ue = "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), He = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/, Fe = k, Le = k; + function Ve(e3, t4) { + var n2; + if (e3.isValid()) { + if ("string" == typeof t4) { + if (/^\d+$/.test(t4)) + t4 = g(t4); + else if (!u(t4 = e3.localeData().monthsParse(t4))) + return; + } + n2 = Math.min(e3.date(), We(e3.year(), t4)), e3._d["set" + (e3._isUTC ? "UTC" : "") + "Month"](t4, n2); + } + } + function Ge(e3) { + return null != e3 ? (Ve(this, e3), f.updateOffset(this, true), this) : ce(this, "Month"); + } + function Ee() { + function e3(e4, t5) { + return t5.length - e4.length; + } + for (var t4, n2 = [], s2 = [], i3 = [], r2 = 0; r2 < 12; r2++) + t4 = l([2e3, r2]), n2.push(this.monthsShort(t4, "")), s2.push(this.months(t4, "")), i3.push(this.months(t4, "")), i3.push(this.monthsShort(t4, "")); + for (n2.sort(e3), s2.sort(e3), i3.sort(e3), r2 = 0; r2 < 12; r2++) + n2[r2] = M(n2[r2]), s2[r2] = M(s2[r2]); + for (r2 = 0; r2 < 24; r2++) + i3[r2] = M(i3[r2]); + this._monthsRegex = new RegExp("^(" + i3.join("|") + ")", "i"), this._monthsShortRegex = this._monthsRegex, this._monthsStrictRegex = new RegExp("^(" + s2.join("|") + ")", "i"), this._monthsShortStrictRegex = new RegExp("^(" + n2.join("|") + ")", "i"); + } + function Ae(e3) { + return he(e3) ? 366 : 365; + } + s("Y", 0, 0, function() { + var e3 = this.year(); + return e3 <= 9999 ? r(e3, 4) : "+" + e3; + }), s(0, ["YY", 2], 0, function() { + return this.year() % 100; + }), s(0, ["YYYY", 4], 0, "year"), s(0, ["YYYYY", 5], 0, "year"), s(0, ["YYYYYY", 6, true], 0, "year"), t("year", "y"), n("year", 1), v("Y", De), v("YY", p, w2), v("YYYY", ke, _e), v("YYYYY", ve, ye), v("YYYYYY", ve, ye), D(["YYYYY", "YYYYYY"], Y), D("YYYY", function(e3, t4) { + t4[Y] = 2 === e3.length ? f.parseTwoDigitYear(e3) : g(e3); + }), D("YY", function(e3, t4) { + t4[Y] = f.parseTwoDigitYear(e3); + }), D("Y", function(e3, t4) { + t4[Y] = parseInt(e3, 10); + }), f.parseTwoDigitYear = function(e3) { + return g(e3) + (68 < g(e3) ? 1900 : 2e3); + }; + var Ie = de("FullYear", true); + function je(e3, t4, n2, s2, i3, r2, a2) { + var o2; + return e3 < 100 && 0 <= e3 ? (o2 = new Date(e3 + 400, t4, n2, s2, i3, r2, a2), isFinite(o2.getFullYear()) && o2.setFullYear(e3)) : o2 = new Date(e3, t4, n2, s2, i3, r2, a2), o2; + } + function Ze(e3) { + var t4; + return e3 < 100 && 0 <= e3 ? ((t4 = Array.prototype.slice.call(arguments))[0] = e3 + 400, t4 = new Date(Date.UTC.apply(null, t4)), isFinite(t4.getUTCFullYear()) && t4.setUTCFullYear(e3)) : t4 = new Date(Date.UTC.apply(null, arguments)), t4; + } + function ze(e3, t4, n2) { + n2 = 7 + t4 - n2; + return n2 - (7 + Ze(e3, 0, n2).getUTCDay() - t4) % 7 - 1; + } + function $e(e3, t4, n2, s2, i3) { + var r2, t4 = 1 + 7 * (t4 - 1) + (7 + n2 - s2) % 7 + ze(e3, s2, i3), n2 = t4 <= 0 ? Ae(r2 = e3 - 1) + t4 : t4 > Ae(e3) ? (r2 = e3 + 1, t4 - Ae(e3)) : (r2 = e3, t4); + return { year: r2, dayOfYear: n2 }; + } + function qe(e3, t4, n2) { + var s2, i3, r2 = ze(e3.year(), t4, n2), r2 = Math.floor((e3.dayOfYear() - r2 - 1) / 7) + 1; + return r2 < 1 ? s2 = r2 + P(i3 = e3.year() - 1, t4, n2) : r2 > P(e3.year(), t4, n2) ? (s2 = r2 - P(e3.year(), t4, n2), i3 = e3.year() + 1) : (i3 = e3.year(), s2 = r2), { week: s2, year: i3 }; + } + function P(e3, t4, n2) { + var s2 = ze(e3, t4, n2), t4 = ze(e3 + 1, t4, n2); + return (Ae(e3) - s2 + t4) / 7; + } + s("w", ["ww", 2], "wo", "week"), s("W", ["WW", 2], "Wo", "isoWeek"), t("week", "w"), t("isoWeek", "W"), n("week", 5), n("isoWeek", 5), v("w", p), v("ww", p, w2), v("W", p), v("WW", p, w2), Te(["w", "ww", "W", "WW"], function(e3, t4, n2, s2) { + t4[s2.substr(0, 1)] = g(e3); + }); + function Be(e3, t4) { + return e3.slice(t4, 7).concat(e3.slice(0, t4)); + } + s("d", 0, "do", "day"), s("dd", 0, 0, function(e3) { + return this.localeData().weekdaysMin(this, e3); + }), s("ddd", 0, 0, function(e3) { + return this.localeData().weekdaysShort(this, e3); + }), s("dddd", 0, 0, function(e3) { + return this.localeData().weekdays(this, e3); + }), s("e", 0, 0, "weekday"), s("E", 0, 0, "isoWeekday"), t("day", "d"), t("weekday", "e"), t("isoWeekday", "E"), n("day", 11), n("weekday", 11), n("isoWeekday", 11), v("d", p), v("e", p), v("E", p), v("dd", function(e3, t4) { + return t4.weekdaysMinRegex(e3); + }), v("ddd", function(e3, t4) { + return t4.weekdaysShortRegex(e3); + }), v("dddd", function(e3, t4) { + return t4.weekdaysRegex(e3); + }), Te(["dd", "ddd", "dddd"], function(e3, t4, n2, s2) { + s2 = n2._locale.weekdaysParse(e3, s2, n2._strict); + null != s2 ? t4.d = s2 : m(n2).invalidWeekday = e3; + }), Te(["d", "e", "E"], function(e3, t4, n2, s2) { + t4[s2] = g(e3); + }); + var Je = "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), Qe = "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), Xe = "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), Ke = k, et = k, tt = k; + function nt() { + function e3(e4, t5) { + return t5.length - e4.length; + } + for (var t4, n2, s2, i3 = [], r2 = [], a2 = [], o2 = [], u2 = 0; u2 < 7; u2++) + s2 = l([2e3, 1]).day(u2), t4 = M(this.weekdaysMin(s2, "")), n2 = M(this.weekdaysShort(s2, "")), s2 = M(this.weekdays(s2, "")), i3.push(t4), r2.push(n2), a2.push(s2), o2.push(t4), o2.push(n2), o2.push(s2); + i3.sort(e3), r2.sort(e3), a2.sort(e3), o2.sort(e3), this._weekdaysRegex = new RegExp("^(" + o2.join("|") + ")", "i"), this._weekdaysShortRegex = this._weekdaysRegex, this._weekdaysMinRegex = this._weekdaysRegex, this._weekdaysStrictRegex = new RegExp("^(" + a2.join("|") + ")", "i"), this._weekdaysShortStrictRegex = new RegExp("^(" + r2.join("|") + ")", "i"), this._weekdaysMinStrictRegex = new RegExp("^(" + i3.join("|") + ")", "i"); + } + function st() { + return this.hours() % 12 || 12; + } + function it(e3, t4) { + s(e3, 0, 0, function() { + return this.localeData().meridiem(this.hours(), this.minutes(), t4); + }); + } + function rt(e3, t4) { + return t4._meridiemParse; + } + s("H", ["HH", 2], 0, "hour"), s("h", ["hh", 2], 0, st), s("k", ["kk", 2], 0, function() { + return this.hours() || 24; + }), s("hmm", 0, 0, function() { + return "" + st.apply(this) + r(this.minutes(), 2); + }), s("hmmss", 0, 0, function() { + return "" + st.apply(this) + r(this.minutes(), 2) + r(this.seconds(), 2); + }), s("Hmm", 0, 0, function() { + return "" + this.hours() + r(this.minutes(), 2); + }), s("Hmmss", 0, 0, function() { + return "" + this.hours() + r(this.minutes(), 2) + r(this.seconds(), 2); + }), it("a", true), it("A", false), t("hour", "h"), n("hour", 13), v("a", rt), v("A", rt), v("H", p), v("h", p), v("k", p), v("HH", p, w2), v("hh", p, w2), v("kk", p, w2), v("hmm", ge), v("hmmss", we), v("Hmm", ge), v("Hmmss", we), D(["H", "HH"], x2), D(["k", "kk"], function(e3, t4, n2) { + e3 = g(e3); + t4[x2] = 24 === e3 ? 0 : e3; + }), D(["a", "A"], function(e3, t4, n2) { + n2._isPm = n2._locale.isPM(e3), n2._meridiem = e3; + }), D(["h", "hh"], function(e3, t4, n2) { + t4[x2] = g(e3), m(n2).bigHour = true; + }), D("hmm", function(e3, t4, n2) { + var s2 = e3.length - 2; + t4[x2] = g(e3.substr(0, s2)), t4[T] = g(e3.substr(s2)), m(n2).bigHour = true; + }), D("hmmss", function(e3, t4, n2) { + var s2 = e3.length - 4, i3 = e3.length - 2; + t4[x2] = g(e3.substr(0, s2)), t4[T] = g(e3.substr(s2, 2)), t4[N] = g(e3.substr(i3)), m(n2).bigHour = true; + }), D("Hmm", function(e3, t4, n2) { + var s2 = e3.length - 2; + t4[x2] = g(e3.substr(0, s2)), t4[T] = g(e3.substr(s2)); + }), D("Hmmss", function(e3, t4, n2) { + var s2 = e3.length - 4, i3 = e3.length - 2; + t4[x2] = g(e3.substr(0, s2)), t4[T] = g(e3.substr(s2, 2)), t4[N] = g(e3.substr(i3)); + }); + k = de("Hours", true); + var at, ot = { calendar: { sameDay: "[Today at] LT", nextDay: "[Tomorrow at] LT", nextWeek: "dddd [at] LT", lastDay: "[Yesterday at] LT", lastWeek: "[Last] dddd [at] LT", sameElse: "L" }, longDateFormat: { LTS: "h:mm:ss A", LT: "h:mm A", L: "MM/DD/YYYY", LL: "MMMM D, YYYY", LLL: "MMMM D, YYYY h:mm A", LLLL: "dddd, MMMM D, YYYY h:mm A" }, invalidDate: "Invalid date", ordinal: "%d", dayOfMonthOrdinalParse: /\d{1,2}/, relativeTime: { future: "in %s", past: "%s ago", s: "a few seconds", ss: "%d seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", w: "a week", ww: "%d weeks", M: "a month", MM: "%d months", y: "a year", yy: "%d years" }, months: Ce, monthsShort: Ue, week: { dow: 0, doy: 6 }, weekdays: Je, weekdaysMin: Xe, weekdaysShort: Qe, meridiemParse: /[ap]\.?m?\.?/i }, R = {}, ut = {}; + function lt(e3) { + return e3 && e3.toLowerCase().replace("_", "-"); + } + function ht(e3) { + for (var t4, n2, s2, i3, r2 = 0; r2 < e3.length; ) { + for (t4 = (i3 = lt(e3[r2]).split("-")).length, n2 = (n2 = lt(e3[r2 + 1])) ? n2.split("-") : null; 0 < t4; ) { + if (s2 = dt(i3.slice(0, t4).join("-"))) + return s2; + if (n2 && n2.length >= t4 && function(e4, t5) { + for (var n3 = Math.min(e4.length, t5.length), s3 = 0; s3 < n3; s3 += 1) + if (e4[s3] !== t5[s3]) + return s3; + return n3; + }(i3, n2) >= t4 - 1) + break; + t4--; + } + r2++; + } + return at; + } + function dt(t4) { + var e3; + if (void 0 === R[t4] && true && module2 && module2.exports && null != t4.match("^[^/\\\\]*$")) + try { + e3 = at._abbr, commonjsRequire("./locale/" + t4), ct(e3); + } catch (e4) { + R[t4] = null; + } + return R[t4]; + } + function ct(e3, t4) { + return e3 && ((t4 = o(t4) ? mt(e3) : ft(e3, t4)) ? at = t4 : "undefined" != typeof console && console.warn && console.warn("Locale " + e3 + " not found. Did you forget to load it?")), at._abbr; + } + function ft(e3, t4) { + if (null === t4) + return delete R[e3], null; + var n2, s2 = ot; + if (t4.abbr = e3, null != R[e3]) + Q("defineLocaleOverride", "use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."), s2 = R[e3]._config; + else if (null != t4.parentLocale) + if (null != R[t4.parentLocale]) + s2 = R[t4.parentLocale]._config; + else { + if (null == (n2 = dt(t4.parentLocale))) + return ut[t4.parentLocale] || (ut[t4.parentLocale] = []), ut[t4.parentLocale].push({ name: e3, config: t4 }), null; + s2 = n2._config; + } + return R[e3] = new K2(X(s2, t4)), ut[e3] && ut[e3].forEach(function(e4) { + ft(e4.name, e4.config); + }), ct(e3), R[e3]; + } + function mt(e3) { + var t4; + if (!(e3 = e3 && e3._locale && e3._locale._abbr ? e3._locale._abbr : e3)) + return at; + if (!a(e3)) { + if (t4 = dt(e3)) + return t4; + e3 = [e3]; + } + return ht(e3); + } + function _t(e3) { + var t4 = e3._a; + return t4 && -2 === m(e3).overflow && (t4 = t4[O] < 0 || 11 < t4[O] ? O : t4[b] < 1 || t4[b] > We(t4[Y], t4[O]) ? b : t4[x2] < 0 || 24 < t4[x2] || 24 === t4[x2] && (0 !== t4[T] || 0 !== t4[N] || 0 !== t4[Ne]) ? x2 : t4[T] < 0 || 59 < t4[T] ? T : t4[N] < 0 || 59 < t4[N] ? N : t4[Ne] < 0 || 999 < t4[Ne] ? Ne : -1, m(e3)._overflowDayOfYear && (t4 < Y || b < t4) && (t4 = b), m(e3)._overflowWeeks && -1 === t4 && (t4 = Pe), m(e3)._overflowWeekday && -1 === t4 && (t4 = Re), m(e3).overflow = t4), e3; + } + var yt = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, gt = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, wt = /Z|[+-]\d\d(?::?\d\d)?/, pt = [["YYYYYY-MM-DD", /[+-]\d{6}-\d\d-\d\d/], ["YYYY-MM-DD", /\d{4}-\d\d-\d\d/], ["GGGG-[W]WW-E", /\d{4}-W\d\d-\d/], ["GGGG-[W]WW", /\d{4}-W\d\d/, false], ["YYYY-DDD", /\d{4}-\d{3}/], ["YYYY-MM", /\d{4}-\d\d/, false], ["YYYYYYMMDD", /[+-]\d{10}/], ["YYYYMMDD", /\d{8}/], ["GGGG[W]WWE", /\d{4}W\d{3}/], ["GGGG[W]WW", /\d{4}W\d{2}/, false], ["YYYYDDD", /\d{7}/], ["YYYYMM", /\d{6}/, false], ["YYYY", /\d{4}/, false]], kt = [["HH:mm:ss.SSSS", /\d\d:\d\d:\d\d\.\d+/], ["HH:mm:ss,SSSS", /\d\d:\d\d:\d\d,\d+/], ["HH:mm:ss", /\d\d:\d\d:\d\d/], ["HH:mm", /\d\d:\d\d/], ["HHmmss.SSSS", /\d\d\d\d\d\d\.\d+/], ["HHmmss,SSSS", /\d\d\d\d\d\d,\d+/], ["HHmmss", /\d\d\d\d\d\d/], ["HHmm", /\d\d\d\d/], ["HH", /\d\d/]], vt = /^\/?Date\((-?\d+)/i, Mt = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/, Dt = { UT: 0, GMT: 0, EDT: -240, EST: -300, CDT: -300, CST: -360, MDT: -360, MST: -420, PDT: -420, PST: -480 }; + function St(e3) { + var t4, n2, s2, i3, r2, a2, o2 = e3._i, u2 = yt.exec(o2) || gt.exec(o2), o2 = pt.length, l2 = kt.length; + if (u2) { + for (m(e3).iso = true, t4 = 0, n2 = o2; t4 < n2; t4++) + if (pt[t4][1].exec(u2[1])) { + i3 = pt[t4][0], s2 = false !== pt[t4][2]; + break; + } + if (null == i3) + e3._isValid = false; + else { + if (u2[3]) { + for (t4 = 0, n2 = l2; t4 < n2; t4++) + if (kt[t4][1].exec(u2[3])) { + r2 = (u2[2] || " ") + kt[t4][0]; + break; + } + if (null == r2) + return void (e3._isValid = false); + } + if (s2 || null == r2) { + if (u2[4]) { + if (!wt.exec(u2[4])) + return void (e3._isValid = false); + a2 = "Z"; + } + e3._f = i3 + (r2 || "") + (a2 || ""), Tt(e3); + } else + e3._isValid = false; + } + } else + e3._isValid = false; + } + function Yt(e3, t4, n2, s2, i3, r2) { + e3 = [function(e4) { + e4 = parseInt(e4, 10); + { + if (e4 <= 49) + return 2e3 + e4; + if (e4 <= 999) + return 1900 + e4; + } + return e4; + }(e3), Ue.indexOf(t4), parseInt(n2, 10), parseInt(s2, 10), parseInt(i3, 10)]; + return r2 && e3.push(parseInt(r2, 10)), e3; + } + function Ot(e3) { + var t4, n2, s2, i3, r2 = Mt.exec(e3._i.replace(/\([^()]*\)|[\n\t]/g, " ").replace(/(\s\s+)/g, " ").replace(/^\s\s*/, "").replace(/\s\s*$/, "")); + r2 ? (t4 = Yt(r2[4], r2[3], r2[2], r2[5], r2[6], r2[7]), n2 = r2[1], s2 = t4, i3 = e3, n2 && Qe.indexOf(n2) !== new Date(s2[0], s2[1], s2[2]).getDay() ? (m(i3).weekdayMismatch = true, i3._isValid = false) : (e3._a = t4, e3._tzm = (n2 = r2[8], s2 = r2[9], i3 = r2[10], n2 ? Dt[n2] : s2 ? 0 : 60 * (((n2 = parseInt(i3, 10)) - (s2 = n2 % 100)) / 100) + s2), e3._d = Ze.apply(null, e3._a), e3._d.setUTCMinutes(e3._d.getUTCMinutes() - e3._tzm), m(e3).rfc2822 = true)) : e3._isValid = false; + } + function bt(e3, t4, n2) { + return null != e3 ? e3 : null != t4 ? t4 : n2; + } + function xt(e3) { + var t4, n2, s2, i3, r2, a2, o2, u2, l2, h2, d2, c3 = []; + if (!e3._d) { + for (s2 = e3, i3 = new Date(f.now()), n2 = s2._useUTC ? [i3.getUTCFullYear(), i3.getUTCMonth(), i3.getUTCDate()] : [i3.getFullYear(), i3.getMonth(), i3.getDate()], e3._w && null == e3._a[b] && null == e3._a[O] && (null != (i3 = (s2 = e3)._w).GG || null != i3.W || null != i3.E ? (u2 = 1, l2 = 4, r2 = bt(i3.GG, s2._a[Y], qe(W(), 1, 4).year), a2 = bt(i3.W, 1), ((o2 = bt(i3.E, 1)) < 1 || 7 < o2) && (h2 = true)) : (u2 = s2._locale._week.dow, l2 = s2._locale._week.doy, d2 = qe(W(), u2, l2), r2 = bt(i3.gg, s2._a[Y], d2.year), a2 = bt(i3.w, d2.week), null != i3.d ? ((o2 = i3.d) < 0 || 6 < o2) && (h2 = true) : null != i3.e ? (o2 = i3.e + u2, (i3.e < 0 || 6 < i3.e) && (h2 = true)) : o2 = u2), a2 < 1 || a2 > P(r2, u2, l2) ? m(s2)._overflowWeeks = true : null != h2 ? m(s2)._overflowWeekday = true : (d2 = $e(r2, a2, o2, u2, l2), s2._a[Y] = d2.year, s2._dayOfYear = d2.dayOfYear)), null != e3._dayOfYear && (i3 = bt(e3._a[Y], n2[Y]), (e3._dayOfYear > Ae(i3) || 0 === e3._dayOfYear) && (m(e3)._overflowDayOfYear = true), h2 = Ze(i3, 0, e3._dayOfYear), e3._a[O] = h2.getUTCMonth(), e3._a[b] = h2.getUTCDate()), t4 = 0; t4 < 3 && null == e3._a[t4]; ++t4) + e3._a[t4] = c3[t4] = n2[t4]; + for (; t4 < 7; t4++) + e3._a[t4] = c3[t4] = null == e3._a[t4] ? 2 === t4 ? 1 : 0 : e3._a[t4]; + 24 === e3._a[x2] && 0 === e3._a[T] && 0 === e3._a[N] && 0 === e3._a[Ne] && (e3._nextDay = true, e3._a[x2] = 0), e3._d = (e3._useUTC ? Ze : je).apply(null, c3), r2 = e3._useUTC ? e3._d.getUTCDay() : e3._d.getDay(), null != e3._tzm && e3._d.setUTCMinutes(e3._d.getUTCMinutes() - e3._tzm), e3._nextDay && (e3._a[x2] = 24), e3._w && void 0 !== e3._w.d && e3._w.d !== r2 && (m(e3).weekdayMismatch = true); + } + } + function Tt(e3) { + if (e3._f === f.ISO_8601) + St(e3); + else if (e3._f === f.RFC_2822) + Ot(e3); + else { + e3._a = [], m(e3).empty = true; + for (var t4, n2, s2, i3, r2, a2 = "" + e3._i, o2 = a2.length, u2 = 0, l2 = ae(e3._f, e3._locale).match(te) || [], h2 = l2.length, d2 = 0; d2 < h2; d2++) + n2 = l2[d2], (t4 = (a2.match(Oe(n2, e3)) || [])[0]) && (0 < (s2 = a2.substr(0, a2.indexOf(t4))).length && m(e3).unusedInput.push(s2), a2 = a2.slice(a2.indexOf(t4) + t4.length), u2 += t4.length), ie[n2] ? (t4 ? m(e3).empty = false : m(e3).unusedTokens.push(n2), s2 = n2, r2 = e3, null != (i3 = t4) && c2(xe, s2) && xe[s2](i3, r2._a, r2, s2)) : e3._strict && !t4 && m(e3).unusedTokens.push(n2); + m(e3).charsLeftOver = o2 - u2, 0 < a2.length && m(e3).unusedInput.push(a2), e3._a[x2] <= 12 && true === m(e3).bigHour && 0 < e3._a[x2] && (m(e3).bigHour = void 0), m(e3).parsedDateParts = e3._a.slice(0), m(e3).meridiem = e3._meridiem, e3._a[x2] = function(e4, t5, n3) { + if (null == n3) + return t5; + return null != e4.meridiemHour ? e4.meridiemHour(t5, n3) : null != e4.isPM ? ((e4 = e4.isPM(n3)) && t5 < 12 && (t5 += 12), t5 = e4 || 12 !== t5 ? t5 : 0) : t5; + }(e3._locale, e3._a[x2], e3._meridiem), null !== (o2 = m(e3).era) && (e3._a[Y] = e3._locale.erasConvertYear(o2, e3._a[Y])), xt(e3), _t(e3); + } + } + function Nt(e3) { + var t4, n2, s2, i3 = e3._i, r2 = e3._f; + if (e3._locale = e3._locale || mt(e3._l), null === i3 || void 0 === r2 && "" === i3) + return I({ nullInput: true }); + if ("string" == typeof i3 && (e3._i = i3 = e3._locale.preparse(i3)), h(i3)) + return new q(_t(i3)); + if (V(i3)) + e3._d = i3; + else if (a(r2)) + !function(e4) { + var t5, n3, s3, i4, r3, a2, o2 = false, u2 = e4._f.length; + if (0 === u2) + return m(e4).invalidFormat = true, e4._d = new Date(NaN); + for (i4 = 0; i4 < u2; i4++) + r3 = 0, a2 = false, t5 = $({}, e4), null != e4._useUTC && (t5._useUTC = e4._useUTC), t5._f = e4._f[i4], Tt(t5), A(t5) && (a2 = true), r3 = (r3 += m(t5).charsLeftOver) + 10 * m(t5).unusedTokens.length, m(t5).score = r3, o2 ? r3 < s3 && (s3 = r3, n3 = t5) : (null == s3 || r3 < s3 || a2) && (s3 = r3, n3 = t5, a2 && (o2 = true)); + E(e4, n3 || t5); + }(e3); + else if (r2) + Tt(e3); + else if (o(r2 = (i3 = e3)._i)) + i3._d = new Date(f.now()); + else + V(r2) ? i3._d = new Date(r2.valueOf()) : "string" == typeof r2 ? (n2 = i3, null !== (t4 = vt.exec(n2._i)) ? n2._d = new Date(+t4[1]) : (St(n2), false === n2._isValid && (delete n2._isValid, Ot(n2), false === n2._isValid && (delete n2._isValid, n2._strict ? n2._isValid = false : f.createFromInputFallback(n2))))) : a(r2) ? (i3._a = G(r2.slice(0), function(e4) { + return parseInt(e4, 10); + }), xt(i3)) : F(r2) ? (t4 = i3)._d || (s2 = void 0 === (n2 = ue(t4._i)).day ? n2.date : n2.day, t4._a = G([n2.year, n2.month, s2, n2.hour, n2.minute, n2.second, n2.millisecond], function(e4) { + return e4 && parseInt(e4, 10); + }), xt(t4)) : u(r2) ? i3._d = new Date(r2) : f.createFromInputFallback(i3); + return A(e3) || (e3._d = null), e3; + } + function Pt(e3, t4, n2, s2, i3) { + var r2 = {}; + return true !== t4 && false !== t4 || (s2 = t4, t4 = void 0), true !== n2 && false !== n2 || (s2 = n2, n2 = void 0), (F(e3) && L(e3) || a(e3) && 0 === e3.length) && (e3 = void 0), r2._isAMomentObject = true, r2._useUTC = r2._isUTC = i3, r2._l = n2, r2._i = e3, r2._f = t4, r2._strict = s2, (i3 = new q(_t(Nt(i3 = r2))))._nextDay && (i3.add(1, "d"), i3._nextDay = void 0), i3; + } + function W(e3, t4, n2, s2) { + return Pt(e3, t4, n2, s2, false); + } + f.createFromInputFallback = e("value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.", function(e3) { + e3._d = new Date(e3._i + (e3._useUTC ? " UTC" : "")); + }), f.ISO_8601 = function() { + }, f.RFC_2822 = function() { + }; + ge = e("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/", function() { + var e3 = W.apply(null, arguments); + return this.isValid() && e3.isValid() ? e3 < this ? this : e3 : I(); + }), we = e("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/", function() { + var e3 = W.apply(null, arguments); + return this.isValid() && e3.isValid() ? this < e3 ? this : e3 : I(); + }); + function Rt(e3, t4) { + var n2, s2; + if (!(t4 = 1 === t4.length && a(t4[0]) ? t4[0] : t4).length) + return W(); + for (n2 = t4[0], s2 = 1; s2 < t4.length; ++s2) + t4[s2].isValid() && !t4[s2][e3](n2) || (n2 = t4[s2]); + return n2; + } + var Wt = ["year", "quarter", "month", "week", "day", "hour", "minute", "second", "millisecond"]; + function Ct(e3) { + var e3 = ue(e3), t4 = e3.year || 0, n2 = e3.quarter || 0, s2 = e3.month || 0, i3 = e3.week || e3.isoWeek || 0, r2 = e3.day || 0, a2 = e3.hour || 0, o2 = e3.minute || 0, u2 = e3.second || 0, l2 = e3.millisecond || 0; + this._isValid = function(e4) { + var t5, n3, s3 = false, i4 = Wt.length; + for (t5 in e4) + if (c2(e4, t5) && (-1 === S.call(Wt, t5) || null != e4[t5] && isNaN(e4[t5]))) + return false; + for (n3 = 0; n3 < i4; ++n3) + if (e4[Wt[n3]]) { + if (s3) + return false; + parseFloat(e4[Wt[n3]]) !== g(e4[Wt[n3]]) && (s3 = true); + } + return true; + }(e3), this._milliseconds = +l2 + 1e3 * u2 + 6e4 * o2 + 1e3 * a2 * 60 * 60, this._days = +r2 + 7 * i3, this._months = +s2 + 3 * n2 + 12 * t4, this._data = {}, this._locale = mt(), this._bubble(); + } + function Ut(e3) { + return e3 instanceof Ct; + } + function Ht(e3) { + return e3 < 0 ? -1 * Math.round(-1 * e3) : Math.round(e3); + } + function Ft(e3, n2) { + s(e3, 0, 0, function() { + var e4 = this.utcOffset(), t4 = "+"; + return e4 < 0 && (e4 = -e4, t4 = "-"), t4 + r(~~(e4 / 60), 2) + n2 + r(~~e4 % 60, 2); + }); + } + Ft("Z", ":"), Ft("ZZ", ""), v("Z", Ye), v("ZZ", Ye), D(["Z", "ZZ"], function(e3, t4, n2) { + n2._useUTC = true, n2._tzm = Vt(Ye, e3); + }); + var Lt = /([\+\-]|\d\d)/gi; + function Vt(e3, t4) { + var t4 = (t4 || "").match(e3); + return null === t4 ? null : 0 === (t4 = 60 * (e3 = ((t4[t4.length - 1] || []) + "").match(Lt) || ["-", 0, 0])[1] + g(e3[2])) ? 0 : "+" === e3[0] ? t4 : -t4; + } + function Gt(e3, t4) { + var n2; + return t4._isUTC ? (t4 = t4.clone(), n2 = (h(e3) || V(e3) ? e3 : W(e3)).valueOf() - t4.valueOf(), t4._d.setTime(t4._d.valueOf() + n2), f.updateOffset(t4, false), t4) : W(e3).local(); + } + function Et(e3) { + return -Math.round(e3._d.getTimezoneOffset()); + } + function At() { + return !!this.isValid() && (this._isUTC && 0 === this._offset); + } + f.updateOffset = function() { + }; + var It = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/, jt = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; + function C(e3, t4) { + var n2, s2 = e3, i3 = null; + return Ut(e3) ? s2 = { ms: e3._milliseconds, d: e3._days, M: e3._months } : u(e3) || !isNaN(+e3) ? (s2 = {}, t4 ? s2[t4] = +e3 : s2.milliseconds = +e3) : (i3 = It.exec(e3)) ? (n2 = "-" === i3[1] ? -1 : 1, s2 = { y: 0, d: g(i3[b]) * n2, h: g(i3[x2]) * n2, m: g(i3[T]) * n2, s: g(i3[N]) * n2, ms: g(Ht(1e3 * i3[Ne])) * n2 }) : (i3 = jt.exec(e3)) ? (n2 = "-" === i3[1] ? -1 : 1, s2 = { y: Zt(i3[2], n2), M: Zt(i3[3], n2), w: Zt(i3[4], n2), d: Zt(i3[5], n2), h: Zt(i3[6], n2), m: Zt(i3[7], n2), s: Zt(i3[8], n2) }) : null == s2 ? s2 = {} : "object" == typeof s2 && ("from" in s2 || "to" in s2) && (t4 = function(e4, t5) { + var n3; + if (!e4.isValid() || !t5.isValid()) + return { milliseconds: 0, months: 0 }; + t5 = Gt(t5, e4), e4.isBefore(t5) ? n3 = zt(e4, t5) : ((n3 = zt(t5, e4)).milliseconds = -n3.milliseconds, n3.months = -n3.months); + return n3; + }(W(s2.from), W(s2.to)), (s2 = {}).ms = t4.milliseconds, s2.M = t4.months), i3 = new Ct(s2), Ut(e3) && c2(e3, "_locale") && (i3._locale = e3._locale), Ut(e3) && c2(e3, "_isValid") && (i3._isValid = e3._isValid), i3; + } + function Zt(e3, t4) { + e3 = e3 && parseFloat(e3.replace(",", ".")); + return (isNaN(e3) ? 0 : e3) * t4; + } + function zt(e3, t4) { + var n2 = {}; + return n2.months = t4.month() - e3.month() + 12 * (t4.year() - e3.year()), e3.clone().add(n2.months, "M").isAfter(t4) && --n2.months, n2.milliseconds = +t4 - +e3.clone().add(n2.months, "M"), n2; + } + function $t(s2, i3) { + return function(e3, t4) { + var n2; + return null === t4 || isNaN(+t4) || (Q(i3, "moment()." + i3 + "(period, number) is deprecated. Please use moment()." + i3 + "(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."), n2 = e3, e3 = t4, t4 = n2), qt(this, C(e3, t4), s2), this; + }; + } + function qt(e3, t4, n2, s2) { + var i3 = t4._milliseconds, r2 = Ht(t4._days), t4 = Ht(t4._months); + e3.isValid() && (s2 = null == s2 || s2, t4 && Ve(e3, ce(e3, "Month") + t4 * n2), r2 && fe(e3, "Date", ce(e3, "Date") + r2 * n2), i3 && e3._d.setTime(e3._d.valueOf() + i3 * n2), s2 && f.updateOffset(e3, r2 || t4)); + } + C.fn = Ct.prototype, C.invalid = function() { + return C(NaN); + }; + Ce = $t(1, "add"), Je = $t(-1, "subtract"); + function Bt(e3) { + return "string" == typeof e3 || e3 instanceof String; + } + function Jt(e3) { + return h(e3) || V(e3) || Bt(e3) || u(e3) || function(t4) { + var e4 = a(t4), n2 = false; + e4 && (n2 = 0 === t4.filter(function(e6) { + return !u(e6) && Bt(t4); + }).length); + return e4 && n2; + }(e3) || function(e4) { + var t4, n2, s2 = F(e4) && !L(e4), i3 = false, r2 = ["years", "year", "y", "months", "month", "M", "days", "day", "d", "dates", "date", "D", "hours", "hour", "h", "minutes", "minute", "m", "seconds", "second", "s", "milliseconds", "millisecond", "ms"], a2 = r2.length; + for (t4 = 0; t4 < a2; t4 += 1) + n2 = r2[t4], i3 = i3 || c2(e4, n2); + return s2 && i3; + }(e3) || null == e3; + } + function Qt(e3, t4) { + if (e3.date() < t4.date()) + return -Qt(t4, e3); + var n2 = 12 * (t4.year() - e3.year()) + (t4.month() - e3.month()), s2 = e3.clone().add(n2, "months"), t4 = t4 - s2 < 0 ? (t4 - s2) / (s2 - e3.clone().add(n2 - 1, "months")) : (t4 - s2) / (e3.clone().add(1 + n2, "months") - s2); + return -(n2 + t4) || 0; + } + function Xt(e3) { + return void 0 === e3 ? this._locale._abbr : (null != (e3 = mt(e3)) && (this._locale = e3), this); + } + f.defaultFormat = "YYYY-MM-DDTHH:mm:ssZ", f.defaultFormatUtc = "YYYY-MM-DDTHH:mm:ss[Z]"; + Xe = e("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.", function(e3) { + return void 0 === e3 ? this.localeData() : this.locale(e3); + }); + function Kt() { + return this._locale; + } + var en = 126227808e5; + function tn(e3, t4) { + return (e3 % t4 + t4) % t4; + } + function nn(e3, t4, n2) { + return e3 < 100 && 0 <= e3 ? new Date(e3 + 400, t4, n2) - en : new Date(e3, t4, n2).valueOf(); + } + function sn(e3, t4, n2) { + return e3 < 100 && 0 <= e3 ? Date.UTC(e3 + 400, t4, n2) - en : Date.UTC(e3, t4, n2); + } + function rn(e3, t4) { + return t4.erasAbbrRegex(e3); + } + function an() { + for (var e3 = [], t4 = [], n2 = [], s2 = [], i3 = this.eras(), r2 = 0, a2 = i3.length; r2 < a2; ++r2) + t4.push(M(i3[r2].name)), e3.push(M(i3[r2].abbr)), n2.push(M(i3[r2].narrow)), s2.push(M(i3[r2].name)), s2.push(M(i3[r2].abbr)), s2.push(M(i3[r2].narrow)); + this._erasRegex = new RegExp("^(" + s2.join("|") + ")", "i"), this._erasNameRegex = new RegExp("^(" + t4.join("|") + ")", "i"), this._erasAbbrRegex = new RegExp("^(" + e3.join("|") + ")", "i"), this._erasNarrowRegex = new RegExp("^(" + n2.join("|") + ")", "i"); + } + function on(e3, t4) { + s(0, [e3, e3.length], 0, t4); + } + function un(e3, t4, n2, s2, i3) { + var r2; + return null == e3 ? qe(this, s2, i3).year : (r2 = P(e3, s2, i3), function(e4, t5, n3, s3, i4) { + e4 = $e(e4, t5, n3, s3, i4), t5 = Ze(e4.year, 0, e4.dayOfYear); + return this.year(t5.getUTCFullYear()), this.month(t5.getUTCMonth()), this.date(t5.getUTCDate()), this; + }.call(this, e3, t4 = r2 < t4 ? r2 : t4, n2, s2, i3)); + } + s("N", 0, 0, "eraAbbr"), s("NN", 0, 0, "eraAbbr"), s("NNN", 0, 0, "eraAbbr"), s("NNNN", 0, 0, "eraName"), s("NNNNN", 0, 0, "eraNarrow"), s("y", ["y", 1], "yo", "eraYear"), s("y", ["yy", 2], 0, "eraYear"), s("y", ["yyy", 3], 0, "eraYear"), s("y", ["yyyy", 4], 0, "eraYear"), v("N", rn), v("NN", rn), v("NNN", rn), v("NNNN", function(e3, t4) { + return t4.erasNameRegex(e3); + }), v("NNNNN", function(e3, t4) { + return t4.erasNarrowRegex(e3); + }), D(["N", "NN", "NNN", "NNNN", "NNNNN"], function(e3, t4, n2, s2) { + s2 = n2._locale.erasParse(e3, s2, n2._strict); + s2 ? m(n2).era = s2 : m(n2).invalidEra = e3; + }), v("y", Me), v("yy", Me), v("yyy", Me), v("yyyy", Me), v("yo", function(e3, t4) { + return t4._eraYearOrdinalRegex || Me; + }), D(["y", "yy", "yyy", "yyyy"], Y), D(["yo"], function(e3, t4, n2, s2) { + var i3; + n2._locale._eraYearOrdinalRegex && (i3 = e3.match(n2._locale._eraYearOrdinalRegex)), n2._locale.eraYearOrdinalParse ? t4[Y] = n2._locale.eraYearOrdinalParse(e3, i3) : t4[Y] = parseInt(e3, 10); + }), s(0, ["gg", 2], 0, function() { + return this.weekYear() % 100; + }), s(0, ["GG", 2], 0, function() { + return this.isoWeekYear() % 100; + }), on("gggg", "weekYear"), on("ggggg", "weekYear"), on("GGGG", "isoWeekYear"), on("GGGGG", "isoWeekYear"), t("weekYear", "gg"), t("isoWeekYear", "GG"), n("weekYear", 1), n("isoWeekYear", 1), v("G", De), v("g", De), v("GG", p, w2), v("gg", p, w2), v("GGGG", ke, _e), v("gggg", ke, _e), v("GGGGG", ve, ye), v("ggggg", ve, ye), Te(["gggg", "ggggg", "GGGG", "GGGGG"], function(e3, t4, n2, s2) { + t4[s2.substr(0, 2)] = g(e3); + }), Te(["gg", "GG"], function(e3, t4, n2, s2) { + t4[s2] = f.parseTwoDigitYear(e3); + }), s("Q", 0, "Qo", "quarter"), t("quarter", "Q"), n("quarter", 7), v("Q", i2), D("Q", function(e3, t4) { + t4[O] = 3 * (g(e3) - 1); + }), s("D", ["DD", 2], "Do", "date"), t("date", "D"), n("date", 9), v("D", p), v("DD", p, w2), v("Do", function(e3, t4) { + return e3 ? t4._dayOfMonthOrdinalParse || t4._ordinalParse : t4._dayOfMonthOrdinalParseLenient; + }), D(["D", "DD"], b), D("Do", function(e3, t4) { + t4[b] = g(e3.match(p)[0]); + }); + ke = de("Date", true); + s("DDD", ["DDDD", 3], "DDDo", "dayOfYear"), t("dayOfYear", "DDD"), n("dayOfYear", 4), v("DDD", pe), v("DDDD", me), D(["DDD", "DDDD"], function(e3, t4, n2) { + n2._dayOfYear = g(e3); + }), s("m", ["mm", 2], 0, "minute"), t("minute", "m"), n("minute", 14), v("m", p), v("mm", p, w2), D(["m", "mm"], T); + var ln, _e = de("Minutes", false), ve = (s("s", ["ss", 2], 0, "second"), t("second", "s"), n("second", 15), v("s", p), v("ss", p, w2), D(["s", "ss"], N), de("Seconds", false)); + for (s("S", 0, 0, function() { + return ~~(this.millisecond() / 100); + }), s(0, ["SS", 2], 0, function() { + return ~~(this.millisecond() / 10); + }), s(0, ["SSS", 3], 0, "millisecond"), s(0, ["SSSS", 4], 0, function() { + return 10 * this.millisecond(); + }), s(0, ["SSSSS", 5], 0, function() { + return 100 * this.millisecond(); + }), s(0, ["SSSSSS", 6], 0, function() { + return 1e3 * this.millisecond(); + }), s(0, ["SSSSSSS", 7], 0, function() { + return 1e4 * this.millisecond(); + }), s(0, ["SSSSSSSS", 8], 0, function() { + return 1e5 * this.millisecond(); + }), s(0, ["SSSSSSSSS", 9], 0, function() { + return 1e6 * this.millisecond(); + }), t("millisecond", "ms"), n("millisecond", 16), v("S", pe, i2), v("SS", pe, w2), v("SSS", pe, me), ln = "SSSS"; ln.length <= 9; ln += "S") + v(ln, Me); + function hn(e3, t4) { + t4[Ne] = g(1e3 * ("0." + e3)); + } + for (ln = "S"; ln.length <= 9; ln += "S") + D(ln, hn); + ye = de("Milliseconds", false), s("z", 0, 0, "zoneAbbr"), s("zz", 0, 0, "zoneName"); + i2 = q.prototype; + function dn(e3) { + return e3; + } + i2.add = Ce, i2.calendar = function(e3, t4) { + 1 === arguments.length && (arguments[0] ? Jt(arguments[0]) ? (e3 = arguments[0], t4 = void 0) : function(e4) { + for (var t5 = F(e4) && !L(e4), n3 = false, s2 = ["sameDay", "nextDay", "lastDay", "nextWeek", "lastWeek", "sameElse"], i3 = 0; i3 < s2.length; i3 += 1) + n3 = n3 || c2(e4, s2[i3]); + return t5 && n3; + }(arguments[0]) && (t4 = arguments[0], e3 = void 0) : t4 = e3 = void 0); + var e3 = e3 || W(), n2 = Gt(e3, this).startOf("day"), n2 = f.calendarFormat(this, n2) || "sameElse", t4 = t4 && (d(t4[n2]) ? t4[n2].call(this, e3) : t4[n2]); + return this.format(t4 || this.localeData().calendar(n2, this, W(e3))); + }, i2.clone = function() { + return new q(this); + }, i2.diff = function(e3, t4, n2) { + var s2, i3, r2; + if (!this.isValid()) + return NaN; + if (!(s2 = Gt(e3, this)).isValid()) + return NaN; + switch (i3 = 6e4 * (s2.utcOffset() - this.utcOffset()), t4 = _2(t4)) { + case "year": + r2 = Qt(this, s2) / 12; + break; + case "month": + r2 = Qt(this, s2); + break; + case "quarter": + r2 = Qt(this, s2) / 3; + break; + case "second": + r2 = (this - s2) / 1e3; + break; + case "minute": + r2 = (this - s2) / 6e4; + break; + case "hour": + r2 = (this - s2) / 36e5; + break; + case "day": + r2 = (this - s2 - i3) / 864e5; + break; + case "week": + r2 = (this - s2 - i3) / 6048e5; + break; + default: + r2 = this - s2; + } + return n2 ? r2 : y2(r2); + }, i2.endOf = function(e3) { + var t4, n2; + if (void 0 === (e3 = _2(e3)) || "millisecond" === e3 || !this.isValid()) + return this; + switch (n2 = this._isUTC ? sn : nn, e3) { + case "year": + t4 = n2(this.year() + 1, 0, 1) - 1; + break; + case "quarter": + t4 = n2(this.year(), this.month() - this.month() % 3 + 3, 1) - 1; + break; + case "month": + t4 = n2(this.year(), this.month() + 1, 1) - 1; + break; + case "week": + t4 = n2(this.year(), this.month(), this.date() - this.weekday() + 7) - 1; + break; + case "isoWeek": + t4 = n2(this.year(), this.month(), this.date() - (this.isoWeekday() - 1) + 7) - 1; + break; + case "day": + case "date": + t4 = n2(this.year(), this.month(), this.date() + 1) - 1; + break; + case "hour": + t4 = this._d.valueOf(), t4 += 36e5 - tn(t4 + (this._isUTC ? 0 : 6e4 * this.utcOffset()), 36e5) - 1; + break; + case "minute": + t4 = this._d.valueOf(), t4 += 6e4 - tn(t4, 6e4) - 1; + break; + case "second": + t4 = this._d.valueOf(), t4 += 1e3 - tn(t4, 1e3) - 1; + break; + } + return this._d.setTime(t4), f.updateOffset(this, true), this; + }, i2.format = function(e3) { + return e3 = e3 || (this.isUtc() ? f.defaultFormatUtc : f.defaultFormat), e3 = re2(this, e3), this.localeData().postformat(e3); + }, i2.from = function(e3, t4) { + return this.isValid() && (h(e3) && e3.isValid() || W(e3).isValid()) ? C({ to: this, from: e3 }).locale(this.locale()).humanize(!t4) : this.localeData().invalidDate(); + }, i2.fromNow = function(e3) { + return this.from(W(), e3); + }, i2.to = function(e3, t4) { + return this.isValid() && (h(e3) && e3.isValid() || W(e3).isValid()) ? C({ from: this, to: e3 }).locale(this.locale()).humanize(!t4) : this.localeData().invalidDate(); + }, i2.toNow = function(e3) { + return this.to(W(), e3); + }, i2.get = function(e3) { + return d(this[e3 = _2(e3)]) ? this[e3]() : this; + }, i2.invalidAt = function() { + return m(this).overflow; + }, i2.isAfter = function(e3, t4) { + return e3 = h(e3) ? e3 : W(e3), !(!this.isValid() || !e3.isValid()) && ("millisecond" === (t4 = _2(t4) || "millisecond") ? this.valueOf() > e3.valueOf() : e3.valueOf() < this.clone().startOf(t4).valueOf()); + }, i2.isBefore = function(e3, t4) { + return e3 = h(e3) ? e3 : W(e3), !(!this.isValid() || !e3.isValid()) && ("millisecond" === (t4 = _2(t4) || "millisecond") ? this.valueOf() < e3.valueOf() : this.clone().endOf(t4).valueOf() < e3.valueOf()); + }, i2.isBetween = function(e3, t4, n2, s2) { + return e3 = h(e3) ? e3 : W(e3), t4 = h(t4) ? t4 : W(t4), !!(this.isValid() && e3.isValid() && t4.isValid()) && (("(" === (s2 = s2 || "()")[0] ? this.isAfter(e3, n2) : !this.isBefore(e3, n2)) && (")" === s2[1] ? this.isBefore(t4, n2) : !this.isAfter(t4, n2))); + }, i2.isSame = function(e3, t4) { + var e3 = h(e3) ? e3 : W(e3); + return !(!this.isValid() || !e3.isValid()) && ("millisecond" === (t4 = _2(t4) || "millisecond") ? this.valueOf() === e3.valueOf() : (e3 = e3.valueOf(), this.clone().startOf(t4).valueOf() <= e3 && e3 <= this.clone().endOf(t4).valueOf())); + }, i2.isSameOrAfter = function(e3, t4) { + return this.isSame(e3, t4) || this.isAfter(e3, t4); + }, i2.isSameOrBefore = function(e3, t4) { + return this.isSame(e3, t4) || this.isBefore(e3, t4); + }, i2.isValid = function() { + return A(this); + }, i2.lang = Xe, i2.locale = Xt, i2.localeData = Kt, i2.max = we, i2.min = ge, i2.parsingFlags = function() { + return E({}, m(this)); + }, i2.set = function(e3, t4) { + if ("object" == typeof e3) + for (var n2 = function(e4) { + var t5, n3 = []; + for (t5 in e4) + c2(e4, t5) && n3.push({ unit: t5, priority: le[t5] }); + return n3.sort(function(e6, t6) { + return e6.priority - t6.priority; + }), n3; + }(e3 = ue(e3)), s2 = n2.length, i3 = 0; i3 < s2; i3++) + this[n2[i3].unit](e3[n2[i3].unit]); + else if (d(this[e3 = _2(e3)])) + return this[e3](t4); + return this; + }, i2.startOf = function(e3) { + var t4, n2; + if (void 0 === (e3 = _2(e3)) || "millisecond" === e3 || !this.isValid()) + return this; + switch (n2 = this._isUTC ? sn : nn, e3) { + case "year": + t4 = n2(this.year(), 0, 1); + break; + case "quarter": + t4 = n2(this.year(), this.month() - this.month() % 3, 1); + break; + case "month": + t4 = n2(this.year(), this.month(), 1); + break; + case "week": + t4 = n2(this.year(), this.month(), this.date() - this.weekday()); + break; + case "isoWeek": + t4 = n2(this.year(), this.month(), this.date() - (this.isoWeekday() - 1)); + break; + case "day": + case "date": + t4 = n2(this.year(), this.month(), this.date()); + break; + case "hour": + t4 = this._d.valueOf(), t4 -= tn(t4 + (this._isUTC ? 0 : 6e4 * this.utcOffset()), 36e5); + break; + case "minute": + t4 = this._d.valueOf(), t4 -= tn(t4, 6e4); + break; + case "second": + t4 = this._d.valueOf(), t4 -= tn(t4, 1e3); + break; + } + return this._d.setTime(t4), f.updateOffset(this, true), this; + }, i2.subtract = Je, i2.toArray = function() { + var e3 = this; + return [e3.year(), e3.month(), e3.date(), e3.hour(), e3.minute(), e3.second(), e3.millisecond()]; + }, i2.toObject = function() { + var e3 = this; + return { years: e3.year(), months: e3.month(), date: e3.date(), hours: e3.hours(), minutes: e3.minutes(), seconds: e3.seconds(), milliseconds: e3.milliseconds() }; + }, i2.toDate = function() { + return new Date(this.valueOf()); + }, i2.toISOString = function(e3) { + if (!this.isValid()) + return null; + var t4 = (e3 = true !== e3) ? this.clone().utc() : this; + return t4.year() < 0 || 9999 < t4.year() ? re2(t4, e3 ? "YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]" : "YYYYYY-MM-DD[T]HH:mm:ss.SSSZ") : d(Date.prototype.toISOString) ? e3 ? this.toDate().toISOString() : new Date(this.valueOf() + 60 * this.utcOffset() * 1e3).toISOString().replace("Z", re2(t4, "Z")) : re2(t4, e3 ? "YYYY-MM-DD[T]HH:mm:ss.SSS[Z]" : "YYYY-MM-DD[T]HH:mm:ss.SSSZ"); + }, i2.inspect = function() { + if (!this.isValid()) + return "moment.invalid(/* " + this._i + " */)"; + var e3, t4 = "moment", n2 = ""; + return this.isLocal() || (t4 = 0 === this.utcOffset() ? "moment.utc" : "moment.parseZone", n2 = "Z"), t4 = "[" + t4 + '("]', e3 = 0 <= this.year() && this.year() <= 9999 ? "YYYY" : "YYYYYY", this.format(t4 + e3 + "-MM-DD[T]HH:mm:ss.SSS" + (n2 + '[")]')); + }, "undefined" != typeof Symbol && null != Symbol.for && (i2[Symbol.for("nodejs.util.inspect.custom")] = function() { + return "Moment<" + this.format() + ">"; + }), i2.toJSON = function() { + return this.isValid() ? this.toISOString() : null; + }, i2.toString = function() { + return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + }, i2.unix = function() { + return Math.floor(this.valueOf() / 1e3); + }, i2.valueOf = function() { + return this._d.valueOf() - 6e4 * (this._offset || 0); + }, i2.creationData = function() { + return { input: this._i, format: this._f, locale: this._locale, isUTC: this._isUTC, strict: this._strict }; + }, i2.eraName = function() { + for (var e3, t4 = this.localeData().eras(), n2 = 0, s2 = t4.length; n2 < s2; ++n2) { + if (e3 = this.clone().startOf("day").valueOf(), t4[n2].since <= e3 && e3 <= t4[n2].until) + return t4[n2].name; + if (t4[n2].until <= e3 && e3 <= t4[n2].since) + return t4[n2].name; + } + return ""; + }, i2.eraNarrow = function() { + for (var e3, t4 = this.localeData().eras(), n2 = 0, s2 = t4.length; n2 < s2; ++n2) { + if (e3 = this.clone().startOf("day").valueOf(), t4[n2].since <= e3 && e3 <= t4[n2].until) + return t4[n2].narrow; + if (t4[n2].until <= e3 && e3 <= t4[n2].since) + return t4[n2].narrow; + } + return ""; + }, i2.eraAbbr = function() { + for (var e3, t4 = this.localeData().eras(), n2 = 0, s2 = t4.length; n2 < s2; ++n2) { + if (e3 = this.clone().startOf("day").valueOf(), t4[n2].since <= e3 && e3 <= t4[n2].until) + return t4[n2].abbr; + if (t4[n2].until <= e3 && e3 <= t4[n2].since) + return t4[n2].abbr; + } + return ""; + }, i2.eraYear = function() { + for (var e3, t4, n2 = this.localeData().eras(), s2 = 0, i3 = n2.length; s2 < i3; ++s2) + if (e3 = n2[s2].since <= n2[s2].until ? 1 : -1, t4 = this.clone().startOf("day").valueOf(), n2[s2].since <= t4 && t4 <= n2[s2].until || n2[s2].until <= t4 && t4 <= n2[s2].since) + return (this.year() - f(n2[s2].since).year()) * e3 + n2[s2].offset; + return this.year(); + }, i2.year = Ie, i2.isLeapYear = function() { + return he(this.year()); + }, i2.weekYear = function(e3) { + return un.call(this, e3, this.week(), this.weekday(), this.localeData()._week.dow, this.localeData()._week.doy); + }, i2.isoWeekYear = function(e3) { + return un.call(this, e3, this.isoWeek(), this.isoWeekday(), 1, 4); + }, i2.quarter = i2.quarters = function(e3) { + return null == e3 ? Math.ceil((this.month() + 1) / 3) : this.month(3 * (e3 - 1) + this.month() % 3); + }, i2.month = Ge, i2.daysInMonth = function() { + return We(this.year(), this.month()); + }, i2.week = i2.weeks = function(e3) { + var t4 = this.localeData().week(this); + return null == e3 ? t4 : this.add(7 * (e3 - t4), "d"); + }, i2.isoWeek = i2.isoWeeks = function(e3) { + var t4 = qe(this, 1, 4).week; + return null == e3 ? t4 : this.add(7 * (e3 - t4), "d"); + }, i2.weeksInYear = function() { + var e3 = this.localeData()._week; + return P(this.year(), e3.dow, e3.doy); + }, i2.weeksInWeekYear = function() { + var e3 = this.localeData()._week; + return P(this.weekYear(), e3.dow, e3.doy); + }, i2.isoWeeksInYear = function() { + return P(this.year(), 1, 4); + }, i2.isoWeeksInISOWeekYear = function() { + return P(this.isoWeekYear(), 1, 4); + }, i2.date = ke, i2.day = i2.days = function(e3) { + if (!this.isValid()) + return null != e3 ? this : NaN; + var t4, n2, s2 = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + return null != e3 ? (t4 = e3, n2 = this.localeData(), e3 = "string" != typeof t4 ? t4 : isNaN(t4) ? "number" == typeof (t4 = n2.weekdaysParse(t4)) ? t4 : null : parseInt(t4, 10), this.add(e3 - s2, "d")) : s2; + }, i2.weekday = function(e3) { + if (!this.isValid()) + return null != e3 ? this : NaN; + var t4 = (this.day() + 7 - this.localeData()._week.dow) % 7; + return null == e3 ? t4 : this.add(e3 - t4, "d"); + }, i2.isoWeekday = function(e3) { + return this.isValid() ? null != e3 ? (t4 = e3, n2 = this.localeData(), n2 = "string" == typeof t4 ? n2.weekdaysParse(t4) % 7 || 7 : isNaN(t4) ? null : t4, this.day(this.day() % 7 ? n2 : n2 - 7)) : this.day() || 7 : null != e3 ? this : NaN; + var t4, n2; + }, i2.dayOfYear = function(e3) { + var t4 = Math.round((this.clone().startOf("day") - this.clone().startOf("year")) / 864e5) + 1; + return null == e3 ? t4 : this.add(e3 - t4, "d"); + }, i2.hour = i2.hours = k, i2.minute = i2.minutes = _e, i2.second = i2.seconds = ve, i2.millisecond = i2.milliseconds = ye, i2.utcOffset = function(e3, t4, n2) { + var s2, i3 = this._offset || 0; + if (!this.isValid()) + return null != e3 ? this : NaN; + if (null == e3) + return this._isUTC ? i3 : Et(this); + if ("string" == typeof e3) { + if (null === (e3 = Vt(Ye, e3))) + return this; + } else + Math.abs(e3) < 16 && !n2 && (e3 *= 60); + return !this._isUTC && t4 && (s2 = Et(this)), this._offset = e3, this._isUTC = true, null != s2 && this.add(s2, "m"), i3 !== e3 && (!t4 || this._changeInProgress ? qt(this, C(e3 - i3, "m"), 1, false) : this._changeInProgress || (this._changeInProgress = true, f.updateOffset(this, true), this._changeInProgress = null)), this; + }, i2.utc = function(e3) { + return this.utcOffset(0, e3); + }, i2.local = function(e3) { + return this._isUTC && (this.utcOffset(0, e3), this._isUTC = false, e3 && this.subtract(Et(this), "m")), this; + }, i2.parseZone = function() { + var e3; + return null != this._tzm ? this.utcOffset(this._tzm, false, true) : "string" == typeof this._i && (null != (e3 = Vt(Se, this._i)) ? this.utcOffset(e3) : this.utcOffset(0, true)), this; + }, i2.hasAlignedHourOffset = function(e3) { + return !!this.isValid() && (e3 = e3 ? W(e3).utcOffset() : 0, (this.utcOffset() - e3) % 60 == 0); + }, i2.isDST = function() { + return this.utcOffset() > this.clone().month(0).utcOffset() || this.utcOffset() > this.clone().month(5).utcOffset(); + }, i2.isLocal = function() { + return !!this.isValid() && !this._isUTC; + }, i2.isUtcOffset = function() { + return !!this.isValid() && this._isUTC; + }, i2.isUtc = At, i2.isUTC = At, i2.zoneAbbr = function() { + return this._isUTC ? "UTC" : ""; + }, i2.zoneName = function() { + return this._isUTC ? "Coordinated Universal Time" : ""; + }, i2.dates = e("dates accessor is deprecated. Use date instead.", ke), i2.months = e("months accessor is deprecated. Use month instead", Ge), i2.years = e("years accessor is deprecated. Use year instead", Ie), i2.zone = e("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/", function(e3, t4) { + return null != e3 ? (this.utcOffset(e3 = "string" != typeof e3 ? -e3 : e3, t4), this) : -this.utcOffset(); + }), i2.isDSTShifted = e("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information", function() { + if (!o(this._isDSTShifted)) + return this._isDSTShifted; + var e3, t4 = {}; + return $(t4, this), (t4 = Nt(t4))._a ? (e3 = (t4._isUTC ? l : W)(t4._a), this._isDSTShifted = this.isValid() && 0 < function(e4, t5, n2) { + for (var s2 = Math.min(e4.length, t5.length), i3 = Math.abs(e4.length - t5.length), r2 = 0, a2 = 0; a2 < s2; a2++) + (n2 && e4[a2] !== t5[a2] || !n2 && g(e4[a2]) !== g(t5[a2])) && r2++; + return r2 + i3; + }(t4._a, e3.toArray())) : this._isDSTShifted = false, this._isDSTShifted; + }); + w2 = K2.prototype; + function cn(e3, t4, n2, s2) { + var i3 = mt(), s2 = l().set(s2, t4); + return i3[n2](s2, e3); + } + function fn(e3, t4, n2) { + if (u(e3) && (t4 = e3, e3 = void 0), e3 = e3 || "", null != t4) + return cn(e3, t4, n2, "month"); + for (var s2 = [], i3 = 0; i3 < 12; i3++) + s2[i3] = cn(e3, i3, n2, "month"); + return s2; + } + function mn(e3, t4, n2, s2) { + t4 = ("boolean" == typeof e3 ? u(t4) && (n2 = t4, t4 = void 0) : (t4 = e3, e3 = false, u(n2 = t4) && (n2 = t4, t4 = void 0)), t4 || ""); + var i3, r2 = mt(), a2 = e3 ? r2._week.dow : 0, o2 = []; + if (null != n2) + return cn(t4, (n2 + a2) % 7, s2, "day"); + for (i3 = 0; i3 < 7; i3++) + o2[i3] = cn(t4, (i3 + a2) % 7, s2, "day"); + return o2; + } + w2.calendar = function(e3, t4, n2) { + return d(e3 = this._calendar[e3] || this._calendar.sameElse) ? e3.call(t4, n2) : e3; + }, w2.longDateFormat = function(e3) { + var t4 = this._longDateFormat[e3], n2 = this._longDateFormat[e3.toUpperCase()]; + return t4 || !n2 ? t4 : (this._longDateFormat[e3] = n2.match(te).map(function(e4) { + return "MMMM" === e4 || "MM" === e4 || "DD" === e4 || "dddd" === e4 ? e4.slice(1) : e4; + }).join(""), this._longDateFormat[e3]); + }, w2.invalidDate = function() { + return this._invalidDate; + }, w2.ordinal = function(e3) { + return this._ordinal.replace("%d", e3); + }, w2.preparse = dn, w2.postformat = dn, w2.relativeTime = function(e3, t4, n2, s2) { + var i3 = this._relativeTime[n2]; + return d(i3) ? i3(e3, t4, n2, s2) : i3.replace(/%d/i, e3); + }, w2.pastFuture = function(e3, t4) { + return d(e3 = this._relativeTime[0 < e3 ? "future" : "past"]) ? e3(t4) : e3.replace(/%s/i, t4); + }, w2.set = function(e3) { + var t4, n2; + for (n2 in e3) + c2(e3, n2) && (d(t4 = e3[n2]) ? this[n2] = t4 : this["_" + n2] = t4); + this._config = e3, this._dayOfMonthOrdinalParseLenient = new RegExp((this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + "|" + /\d{1,2}/.source); + }, w2.eras = function(e3, t4) { + for (var n2, s2 = this._eras || mt("en")._eras, i3 = 0, r2 = s2.length; i3 < r2; ++i3) { + switch (typeof s2[i3].since) { + case "string": + n2 = f(s2[i3].since).startOf("day"), s2[i3].since = n2.valueOf(); + break; + } + switch (typeof s2[i3].until) { + case "undefined": + s2[i3].until = 1 / 0; + break; + case "string": + n2 = f(s2[i3].until).startOf("day").valueOf(), s2[i3].until = n2.valueOf(); + break; + } + } + return s2; + }, w2.erasParse = function(e3, t4, n2) { + var s2, i3, r2, a2, o2, u2 = this.eras(); + for (e3 = e3.toUpperCase(), s2 = 0, i3 = u2.length; s2 < i3; ++s2) + if (r2 = u2[s2].name.toUpperCase(), a2 = u2[s2].abbr.toUpperCase(), o2 = u2[s2].narrow.toUpperCase(), n2) + switch (t4) { + case "N": + case "NN": + case "NNN": + if (a2 === e3) + return u2[s2]; + break; + case "NNNN": + if (r2 === e3) + return u2[s2]; + break; + case "NNNNN": + if (o2 === e3) + return u2[s2]; + break; + } + else if (0 <= [r2, a2, o2].indexOf(e3)) + return u2[s2]; + }, w2.erasConvertYear = function(e3, t4) { + var n2 = e3.since <= e3.until ? 1 : -1; + return void 0 === t4 ? f(e3.since).year() : f(e3.since).year() + (t4 - e3.offset) * n2; + }, w2.erasAbbrRegex = function(e3) { + return c2(this, "_erasAbbrRegex") || an.call(this), e3 ? this._erasAbbrRegex : this._erasRegex; + }, w2.erasNameRegex = function(e3) { + return c2(this, "_erasNameRegex") || an.call(this), e3 ? this._erasNameRegex : this._erasRegex; + }, w2.erasNarrowRegex = function(e3) { + return c2(this, "_erasNarrowRegex") || an.call(this), e3 ? this._erasNarrowRegex : this._erasRegex; + }, w2.months = function(e3, t4) { + return e3 ? (a(this._months) ? this._months : this._months[(this._months.isFormat || He).test(t4) ? "format" : "standalone"])[e3.month()] : a(this._months) ? this._months : this._months.standalone; + }, w2.monthsShort = function(e3, t4) { + return e3 ? (a(this._monthsShort) ? this._monthsShort : this._monthsShort[He.test(t4) ? "format" : "standalone"])[e3.month()] : a(this._monthsShort) ? this._monthsShort : this._monthsShort.standalone; + }, w2.monthsParse = function(e3, t4, n2) { + var s2, i3; + if (this._monthsParseExact) + return function(e4, t5, n3) { + var s3, i4, r2, e4 = e4.toLocaleLowerCase(); + if (!this._monthsParse) + for (this._monthsParse = [], this._longMonthsParse = [], this._shortMonthsParse = [], s3 = 0; s3 < 12; ++s3) + r2 = l([2e3, s3]), this._shortMonthsParse[s3] = this.monthsShort(r2, "").toLocaleLowerCase(), this._longMonthsParse[s3] = this.months(r2, "").toLocaleLowerCase(); + return n3 ? "MMM" === t5 ? -1 !== (i4 = S.call(this._shortMonthsParse, e4)) ? i4 : null : -1 !== (i4 = S.call(this._longMonthsParse, e4)) ? i4 : null : "MMM" === t5 ? -1 !== (i4 = S.call(this._shortMonthsParse, e4)) || -1 !== (i4 = S.call(this._longMonthsParse, e4)) ? i4 : null : -1 !== (i4 = S.call(this._longMonthsParse, e4)) || -1 !== (i4 = S.call(this._shortMonthsParse, e4)) ? i4 : null; + }.call(this, e3, t4, n2); + for (this._monthsParse || (this._monthsParse = [], this._longMonthsParse = [], this._shortMonthsParse = []), s2 = 0; s2 < 12; s2++) { + if (i3 = l([2e3, s2]), n2 && !this._longMonthsParse[s2] && (this._longMonthsParse[s2] = new RegExp("^" + this.months(i3, "").replace(".", "") + "$", "i"), this._shortMonthsParse[s2] = new RegExp("^" + this.monthsShort(i3, "").replace(".", "") + "$", "i")), n2 || this._monthsParse[s2] || (i3 = "^" + this.months(i3, "") + "|^" + this.monthsShort(i3, ""), this._monthsParse[s2] = new RegExp(i3.replace(".", ""), "i")), n2 && "MMMM" === t4 && this._longMonthsParse[s2].test(e3)) + return s2; + if (n2 && "MMM" === t4 && this._shortMonthsParse[s2].test(e3)) + return s2; + if (!n2 && this._monthsParse[s2].test(e3)) + return s2; + } + }, w2.monthsRegex = function(e3) { + return this._monthsParseExact ? (c2(this, "_monthsRegex") || Ee.call(this), e3 ? this._monthsStrictRegex : this._monthsRegex) : (c2(this, "_monthsRegex") || (this._monthsRegex = Le), this._monthsStrictRegex && e3 ? this._monthsStrictRegex : this._monthsRegex); + }, w2.monthsShortRegex = function(e3) { + return this._monthsParseExact ? (c2(this, "_monthsRegex") || Ee.call(this), e3 ? this._monthsShortStrictRegex : this._monthsShortRegex) : (c2(this, "_monthsShortRegex") || (this._monthsShortRegex = Fe), this._monthsShortStrictRegex && e3 ? this._monthsShortStrictRegex : this._monthsShortRegex); + }, w2.week = function(e3) { + return qe(e3, this._week.dow, this._week.doy).week; + }, w2.firstDayOfYear = function() { + return this._week.doy; + }, w2.firstDayOfWeek = function() { + return this._week.dow; + }, w2.weekdays = function(e3, t4) { + return t4 = a(this._weekdays) ? this._weekdays : this._weekdays[e3 && true !== e3 && this._weekdays.isFormat.test(t4) ? "format" : "standalone"], true === e3 ? Be(t4, this._week.dow) : e3 ? t4[e3.day()] : t4; + }, w2.weekdaysMin = function(e3) { + return true === e3 ? Be(this._weekdaysMin, this._week.dow) : e3 ? this._weekdaysMin[e3.day()] : this._weekdaysMin; + }, w2.weekdaysShort = function(e3) { + return true === e3 ? Be(this._weekdaysShort, this._week.dow) : e3 ? this._weekdaysShort[e3.day()] : this._weekdaysShort; + }, w2.weekdaysParse = function(e3, t4, n2) { + var s2, i3; + if (this._weekdaysParseExact) + return function(e4, t5, n3) { + var s3, i4, r2, e4 = e4.toLocaleLowerCase(); + if (!this._weekdaysParse) + for (this._weekdaysParse = [], this._shortWeekdaysParse = [], this._minWeekdaysParse = [], s3 = 0; s3 < 7; ++s3) + r2 = l([2e3, 1]).day(s3), this._minWeekdaysParse[s3] = this.weekdaysMin(r2, "").toLocaleLowerCase(), this._shortWeekdaysParse[s3] = this.weekdaysShort(r2, "").toLocaleLowerCase(), this._weekdaysParse[s3] = this.weekdays(r2, "").toLocaleLowerCase(); + return n3 ? "dddd" === t5 ? -1 !== (i4 = S.call(this._weekdaysParse, e4)) ? i4 : null : "ddd" === t5 ? -1 !== (i4 = S.call(this._shortWeekdaysParse, e4)) ? i4 : null : -1 !== (i4 = S.call(this._minWeekdaysParse, e4)) ? i4 : null : "dddd" === t5 ? -1 !== (i4 = S.call(this._weekdaysParse, e4)) || -1 !== (i4 = S.call(this._shortWeekdaysParse, e4)) || -1 !== (i4 = S.call(this._minWeekdaysParse, e4)) ? i4 : null : "ddd" === t5 ? -1 !== (i4 = S.call(this._shortWeekdaysParse, e4)) || -1 !== (i4 = S.call(this._weekdaysParse, e4)) || -1 !== (i4 = S.call(this._minWeekdaysParse, e4)) ? i4 : null : -1 !== (i4 = S.call(this._minWeekdaysParse, e4)) || -1 !== (i4 = S.call(this._weekdaysParse, e4)) || -1 !== (i4 = S.call(this._shortWeekdaysParse, e4)) ? i4 : null; + }.call(this, e3, t4, n2); + for (this._weekdaysParse || (this._weekdaysParse = [], this._minWeekdaysParse = [], this._shortWeekdaysParse = [], this._fullWeekdaysParse = []), s2 = 0; s2 < 7; s2++) { + if (i3 = l([2e3, 1]).day(s2), n2 && !this._fullWeekdaysParse[s2] && (this._fullWeekdaysParse[s2] = new RegExp("^" + this.weekdays(i3, "").replace(".", "\\.?") + "$", "i"), this._shortWeekdaysParse[s2] = new RegExp("^" + this.weekdaysShort(i3, "").replace(".", "\\.?") + "$", "i"), this._minWeekdaysParse[s2] = new RegExp("^" + this.weekdaysMin(i3, "").replace(".", "\\.?") + "$", "i")), this._weekdaysParse[s2] || (i3 = "^" + this.weekdays(i3, "") + "|^" + this.weekdaysShort(i3, "") + "|^" + this.weekdaysMin(i3, ""), this._weekdaysParse[s2] = new RegExp(i3.replace(".", ""), "i")), n2 && "dddd" === t4 && this._fullWeekdaysParse[s2].test(e3)) + return s2; + if (n2 && "ddd" === t4 && this._shortWeekdaysParse[s2].test(e3)) + return s2; + if (n2 && "dd" === t4 && this._minWeekdaysParse[s2].test(e3)) + return s2; + if (!n2 && this._weekdaysParse[s2].test(e3)) + return s2; + } + }, w2.weekdaysRegex = function(e3) { + return this._weekdaysParseExact ? (c2(this, "_weekdaysRegex") || nt.call(this), e3 ? this._weekdaysStrictRegex : this._weekdaysRegex) : (c2(this, "_weekdaysRegex") || (this._weekdaysRegex = Ke), this._weekdaysStrictRegex && e3 ? this._weekdaysStrictRegex : this._weekdaysRegex); + }, w2.weekdaysShortRegex = function(e3) { + return this._weekdaysParseExact ? (c2(this, "_weekdaysRegex") || nt.call(this), e3 ? this._weekdaysShortStrictRegex : this._weekdaysShortRegex) : (c2(this, "_weekdaysShortRegex") || (this._weekdaysShortRegex = et), this._weekdaysShortStrictRegex && e3 ? this._weekdaysShortStrictRegex : this._weekdaysShortRegex); + }, w2.weekdaysMinRegex = function(e3) { + return this._weekdaysParseExact ? (c2(this, "_weekdaysRegex") || nt.call(this), e3 ? this._weekdaysMinStrictRegex : this._weekdaysMinRegex) : (c2(this, "_weekdaysMinRegex") || (this._weekdaysMinRegex = tt), this._weekdaysMinStrictRegex && e3 ? this._weekdaysMinStrictRegex : this._weekdaysMinRegex); + }, w2.isPM = function(e3) { + return "p" === (e3 + "").toLowerCase().charAt(0); + }, w2.meridiem = function(e3, t4, n2) { + return 11 < e3 ? n2 ? "pm" : "PM" : n2 ? "am" : "AM"; + }, ct("en", { eras: [{ since: "0001-01-01", until: 1 / 0, offset: 1, name: "Anno Domini", narrow: "AD", abbr: "AD" }, { since: "0000-12-31", until: -1 / 0, offset: 1, name: "Before Christ", narrow: "BC", abbr: "BC" }], dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, ordinal: function(e3) { + var t4 = e3 % 10; + return e3 + (1 === g(e3 % 100 / 10) ? "th" : 1 == t4 ? "st" : 2 == t4 ? "nd" : 3 == t4 ? "rd" : "th"); + } }), f.lang = e("moment.lang is deprecated. Use moment.locale instead.", ct), f.langData = e("moment.langData is deprecated. Use moment.localeData instead.", mt); + var _n = Math.abs; + function yn(e3, t4, n2, s2) { + t4 = C(t4, n2); + return e3._milliseconds += s2 * t4._milliseconds, e3._days += s2 * t4._days, e3._months += s2 * t4._months, e3._bubble(); + } + function gn(e3) { + return e3 < 0 ? Math.floor(e3) : Math.ceil(e3); + } + function wn(e3) { + return 4800 * e3 / 146097; + } + function pn(e3) { + return 146097 * e3 / 4800; + } + function kn(e3) { + return function() { + return this.as(e3); + }; + } + pe = kn("ms"), me = kn("s"), Ce = kn("m"), we = kn("h"), ge = kn("d"), Je = kn("w"), k = kn("M"), _e = kn("Q"), ve = kn("y"); + function vn(e3) { + return function() { + return this.isValid() ? this._data[e3] : NaN; + }; + } + var ye = vn("milliseconds"), ke = vn("seconds"), Ie = vn("minutes"), w2 = vn("hours"), Mn = vn("days"), Dn = vn("months"), Sn = vn("years"); + var Yn2 = Math.round, On = { ss: 44, s: 45, m: 45, h: 22, d: 26, w: null, M: 11 }; + function bn(e3, t4, n2, s2) { + var i3 = C(e3).abs(), r2 = Yn2(i3.as("s")), a2 = Yn2(i3.as("m")), o2 = Yn2(i3.as("h")), u2 = Yn2(i3.as("d")), l2 = Yn2(i3.as("M")), h2 = Yn2(i3.as("w")), i3 = Yn2(i3.as("y")), r2 = (r2 <= n2.ss ? ["s", r2] : r2 < n2.s && ["ss", r2]) || a2 <= 1 && ["m"] || a2 < n2.m && ["mm", a2] || o2 <= 1 && ["h"] || o2 < n2.h && ["hh", o2] || u2 <= 1 && ["d"] || u2 < n2.d && ["dd", u2]; + return (r2 = (r2 = null != n2.w ? r2 || h2 <= 1 && ["w"] || h2 < n2.w && ["ww", h2] : r2) || l2 <= 1 && ["M"] || l2 < n2.M && ["MM", l2] || i3 <= 1 && ["y"] || ["yy", i3])[2] = t4, r2[3] = 0 < +e3, r2[4] = s2, function(e4, t5, n3, s3, i4) { + return i4.relativeTime(t5 || 1, !!n3, e4, s3); + }.apply(null, r2); + } + var xn = Math.abs; + function Tn(e3) { + return (0 < e3) - (e3 < 0) || +e3; + } + function Nn() { + if (!this.isValid()) + return this.localeData().invalidDate(); + var e3, t4, n2, s2, i3, r2, a2, o2 = xn(this._milliseconds) / 1e3, u2 = xn(this._days), l2 = xn(this._months), h2 = this.asSeconds(); + return h2 ? (e3 = y2(o2 / 60), t4 = y2(e3 / 60), o2 %= 60, e3 %= 60, n2 = y2(l2 / 12), l2 %= 12, s2 = o2 ? o2.toFixed(3).replace(/\.?0+$/, "") : "", i3 = Tn(this._months) !== Tn(h2) ? "-" : "", r2 = Tn(this._days) !== Tn(h2) ? "-" : "", a2 = Tn(this._milliseconds) !== Tn(h2) ? "-" : "", (h2 < 0 ? "-" : "") + "P" + (n2 ? i3 + n2 + "Y" : "") + (l2 ? i3 + l2 + "M" : "") + (u2 ? r2 + u2 + "D" : "") + (t4 || e3 || o2 ? "T" : "") + (t4 ? a2 + t4 + "H" : "") + (e3 ? a2 + e3 + "M" : "") + (o2 ? a2 + s2 + "S" : "")) : "P0D"; + } + var U = Ct.prototype; + return U.isValid = function() { + return this._isValid; + }, U.abs = function() { + var e3 = this._data; + return this._milliseconds = _n(this._milliseconds), this._days = _n(this._days), this._months = _n(this._months), e3.milliseconds = _n(e3.milliseconds), e3.seconds = _n(e3.seconds), e3.minutes = _n(e3.minutes), e3.hours = _n(e3.hours), e3.months = _n(e3.months), e3.years = _n(e3.years), this; + }, U.add = function(e3, t4) { + return yn(this, e3, t4, 1); + }, U.subtract = function(e3, t4) { + return yn(this, e3, t4, -1); + }, U.as = function(e3) { + if (!this.isValid()) + return NaN; + var t4, n2, s2 = this._milliseconds; + if ("month" === (e3 = _2(e3)) || "quarter" === e3 || "year" === e3) + switch (t4 = this._days + s2 / 864e5, n2 = this._months + wn(t4), e3) { + case "month": + return n2; + case "quarter": + return n2 / 3; + case "year": + return n2 / 12; + } + else + switch (t4 = this._days + Math.round(pn(this._months)), e3) { + case "week": + return t4 / 7 + s2 / 6048e5; + case "day": + return t4 + s2 / 864e5; + case "hour": + return 24 * t4 + s2 / 36e5; + case "minute": + return 1440 * t4 + s2 / 6e4; + case "second": + return 86400 * t4 + s2 / 1e3; + case "millisecond": + return Math.floor(864e5 * t4) + s2; + default: + throw new Error("Unknown unit " + e3); + } + }, U.asMilliseconds = pe, U.asSeconds = me, U.asMinutes = Ce, U.asHours = we, U.asDays = ge, U.asWeeks = Je, U.asMonths = k, U.asQuarters = _e, U.asYears = ve, U.valueOf = function() { + return this.isValid() ? this._milliseconds + 864e5 * this._days + this._months % 12 * 2592e6 + 31536e6 * g(this._months / 12) : NaN; + }, U._bubble = function() { + var e3 = this._milliseconds, t4 = this._days, n2 = this._months, s2 = this._data; + return 0 <= e3 && 0 <= t4 && 0 <= n2 || e3 <= 0 && t4 <= 0 && n2 <= 0 || (e3 += 864e5 * gn(pn(n2) + t4), n2 = t4 = 0), s2.milliseconds = e3 % 1e3, e3 = y2(e3 / 1e3), s2.seconds = e3 % 60, e3 = y2(e3 / 60), s2.minutes = e3 % 60, e3 = y2(e3 / 60), s2.hours = e3 % 24, t4 += y2(e3 / 24), n2 += e3 = y2(wn(t4)), t4 -= gn(pn(e3)), e3 = y2(n2 / 12), n2 %= 12, s2.days = t4, s2.months = n2, s2.years = e3, this; + }, U.clone = function() { + return C(this); + }, U.get = function(e3) { + return e3 = _2(e3), this.isValid() ? this[e3 + "s"]() : NaN; + }, U.milliseconds = ye, U.seconds = ke, U.minutes = Ie, U.hours = w2, U.days = Mn, U.weeks = function() { + return y2(this.days() / 7); + }, U.months = Dn, U.years = Sn, U.humanize = function(e3, t4) { + if (!this.isValid()) + return this.localeData().invalidDate(); + var n2 = false, s2 = On; + return "object" == typeof e3 && (t4 = e3, e3 = false), "boolean" == typeof e3 && (n2 = e3), "object" == typeof t4 && (s2 = Object.assign({}, On, t4), null != t4.s && null == t4.ss && (s2.ss = t4.s - 1)), e3 = this.localeData(), t4 = bn(this, !n2, s2, e3), n2 && (t4 = e3.pastFuture(+this, t4)), e3.postformat(t4); + }, U.toISOString = Nn, U.toString = Nn, U.toJSON = Nn, U.locale = Xt, U.localeData = Kt, U.toIsoString = e("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)", Nn), U.lang = Xe, s("X", 0, 0, "unix"), s("x", 0, 0, "valueOf"), v("x", De), v("X", /[+-]?\d+(\.\d{1,3})?/), D("X", function(e3, t4, n2) { + n2._d = new Date(1e3 * parseFloat(e3)); + }), D("x", function(e3, t4, n2) { + n2._d = new Date(g(e3)); + }), f.version = "2.29.4", H = W, f.fn = i2, f.min = function() { + return Rt("isBefore", [].slice.call(arguments, 0)); + }, f.max = function() { + return Rt("isAfter", [].slice.call(arguments, 0)); + }, f.now = function() { + return Date.now ? Date.now() : +new Date(); + }, f.utc = l, f.unix = function(e3) { + return W(1e3 * e3); + }, f.months = function(e3, t4) { + return fn(e3, t4, "months"); + }, f.isDate = V, f.locale = ct, f.invalid = I, f.duration = C, f.isMoment = h, f.weekdays = function(e3, t4, n2) { + return mn(e3, t4, n2, "weekdays"); + }, f.parseZone = function() { + return W.apply(null, arguments).parseZone(); + }, f.localeData = mt, f.isDuration = Ut, f.monthsShort = function(e3, t4) { + return fn(e3, t4, "monthsShort"); + }, f.weekdaysMin = function(e3, t4, n2) { + return mn(e3, t4, n2, "weekdaysMin"); + }, f.defineLocale = ft, f.updateLocale = function(e3, t4) { + var n2, s2; + return null != t4 ? (s2 = ot, null != R[e3] && null != R[e3].parentLocale ? R[e3].set(X(R[e3]._config, t4)) : (t4 = X(s2 = null != (n2 = dt(e3)) ? n2._config : s2, t4), null == n2 && (t4.abbr = e3), (s2 = new K2(t4)).parentLocale = R[e3], R[e3] = s2), ct(e3)) : null != R[e3] && (null != R[e3].parentLocale ? (R[e3] = R[e3].parentLocale, e3 === ct() && ct(e3)) : null != R[e3] && delete R[e3]), R[e3]; + }, f.locales = function() { + return ee(R); + }, f.weekdaysShort = function(e3, t4, n2) { + return mn(e3, t4, n2, "weekdaysShort"); + }, f.normalizeUnits = _2, f.relativeTimeRounding = function(e3) { + return void 0 === e3 ? Yn2 : "function" == typeof e3 && (Yn2 = e3, true); + }, f.relativeTimeThreshold = function(e3, t4) { + return void 0 !== On[e3] && (void 0 === t4 ? On[e3] : (On[e3] = t4, "s" === e3 && (On.ss = t4 - 1), true)); + }, f.calendarFormat = function(e3, t4) { + return (e3 = e3.diff(t4, "days", true)) < -6 ? "sameElse" : e3 < -1 ? "lastWeek" : e3 < 0 ? "lastDay" : e3 < 1 ? "sameDay" : e3 < 2 ? "nextDay" : e3 < 7 ? "nextWeek" : "sameElse"; + }, f.prototype = i2, f.HTML5_FMT = { DATETIME_LOCAL: "YYYY-MM-DDTHH:mm", DATETIME_LOCAL_SECONDS: "YYYY-MM-DDTHH:mm:ss", DATETIME_LOCAL_MS: "YYYY-MM-DDTHH:mm:ss.SSS", DATE: "YYYY-MM-DD", TIME: "HH:mm", TIME_SECONDS: "HH:mm:ss", TIME_MS: "HH:mm:ss.SSS", WEEK: "GGGG-[W]WW", MONTH: "YYYY-MM" }, f; + }); + })(moment_min); + const moment = moment_min.exports; + const LEVELS = { + trace: 0, + debug: 1, + info: 2, + warn: 3, + error: 4, + fatal: 5 + }; + const log$1 = { + trace: (..._args) => { + }, + debug: (..._args) => { + }, + info: (..._args) => { + }, + warn: (..._args) => { + }, + error: (..._args) => { + }, + fatal: (..._args) => { + } + }; + const setLogLevel$1 = function(level = "fatal") { + let numericLevel = LEVELS.fatal; + if (typeof level === "string") { + level = level.toLowerCase(); + if (level in LEVELS) { + numericLevel = LEVELS[level]; + } + } else if (typeof level === "number") { + numericLevel = level; + } + log$1.trace = () => { + }; + log$1.debug = () => { + }; + log$1.info = () => { + }; + log$1.warn = () => { + }; + log$1.error = () => { + }; + log$1.fatal = () => { + }; + if (numericLevel <= LEVELS.fatal) { + log$1.fatal = console.error ? console.error.bind(console, format$1("FATAL"), "color: orange") : console.log.bind(console, "\x1B[35m", format$1("FATAL")); + } + if (numericLevel <= LEVELS.error) { + log$1.error = console.error ? console.error.bind(console, format$1("ERROR"), "color: orange") : console.log.bind(console, "\x1B[31m", format$1("ERROR")); + } + if (numericLevel <= LEVELS.warn) { + log$1.warn = console.warn ? console.warn.bind(console, format$1("WARN"), "color: orange") : console.log.bind(console, `\x1B[33m`, format$1("WARN")); + } + if (numericLevel <= LEVELS.info) { + log$1.info = console.info ? console.info.bind(console, format$1("INFO"), "color: lightblue") : console.log.bind(console, "\x1B[34m", format$1("INFO")); + } + if (numericLevel <= LEVELS.debug) { + log$1.debug = console.debug ? console.debug.bind(console, format$1("DEBUG"), "color: lightgreen") : console.log.bind(console, "\x1B[32m", format$1("DEBUG")); + } + if (numericLevel <= LEVELS.trace) { + log$1.trace = console.debug ? console.debug.bind(console, format$1("TRACE"), "color: lightgreen") : console.log.bind(console, "\x1B[32m", format$1("TRACE")); + } + }; + const format$1 = (level) => { + const time2 = moment().format("ss.SSS"); + return `%c${time2} : ${level} : `; + }; + var dist = {}; + Object.defineProperty(dist, "__esModule", { value: true }); + var sanitizeUrl_1 = dist.sanitizeUrl = void 0; + var invalidProtocolRegex = /^([^\w]*)(javascript|data|vbscript)/im; + var htmlEntitiesRegex = /&#(\w+)(^\w|;)?/g; + var ctrlCharactersRegex = /[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim; + var urlSchemeRegex = /^([^:]+):/gm; + var relativeFirstCharacters = [".", "/"]; + function isRelativeUrlWithoutProtocol(url) { + return relativeFirstCharacters.indexOf(url[0]) > -1; + } + function decodeHtmlCharacters(str2) { + return str2.replace(htmlEntitiesRegex, function(match, dec) { + return String.fromCharCode(dec); + }); + } + function sanitizeUrl(url) { + var sanitizedUrl = decodeHtmlCharacters(url || "").replace(ctrlCharactersRegex, "").trim(); + if (!sanitizedUrl) { + return "about:blank"; + } + if (isRelativeUrlWithoutProtocol(sanitizedUrl)) { + return sanitizedUrl; + } + var urlSchemeParseResults = sanitizedUrl.match(urlSchemeRegex); + if (!urlSchemeParseResults) { + return sanitizedUrl; + } + var urlScheme = urlSchemeParseResults[0]; + if (invalidProtocolRegex.test(urlScheme)) { + return "about:blank"; + } + return sanitizedUrl; + } + sanitizeUrl_1 = dist.sanitizeUrl = sanitizeUrl; + function ascending$1(a, b) { + return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; + } + function descending$1(a, b) { + return a == null || b == null ? NaN : b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; + } + function bisector(f) { + let compare1, compare2, delta; + if (f.length !== 2) { + compare1 = ascending$1; + compare2 = (d, x2) => ascending$1(f(d), x2); + delta = (d, x2) => f(d) - x2; + } else { + compare1 = f === ascending$1 || f === descending$1 ? f : zero$1; + compare2 = f; + delta = f; + } + function left2(a, x2, lo = 0, hi = a.length) { + if (lo < hi) { + if (compare1(x2, x2) !== 0) + return hi; + do { + const mid = lo + hi >>> 1; + if (compare2(a[mid], x2) < 0) + lo = mid + 1; + else + hi = mid; + } while (lo < hi); + } + return lo; + } + function right2(a, x2, lo = 0, hi = a.length) { + if (lo < hi) { + if (compare1(x2, x2) !== 0) + return hi; + do { + const mid = lo + hi >>> 1; + if (compare2(a[mid], x2) <= 0) + lo = mid + 1; + else + hi = mid; + } while (lo < hi); + } + return lo; + } + function center2(a, x2, lo = 0, hi = a.length) { + const i2 = left2(a, x2, lo, hi - 1); + return i2 > lo && delta(a[i2 - 1], x2) > -delta(a[i2], x2) ? i2 - 1 : i2; + } + return { left: left2, center: center2, right: right2 }; + } + function zero$1() { + return 0; + } + function number$3(x2) { + return x2 === null ? NaN : +x2; + } + const ascendingBisect = bisector(ascending$1); + const bisectRight = ascendingBisect.right; + bisector(number$3).center; + const bisect = bisectRight; + class InternMap extends Map { + constructor(entries, key = keyof) { + super(); + Object.defineProperties(this, { _intern: { value: /* @__PURE__ */ new Map() }, _key: { value: key } }); + if (entries != null) + for (const [key2, value] of entries) + this.set(key2, value); + } + get(key) { + return super.get(intern_get(this, key)); + } + has(key) { + return super.has(intern_get(this, key)); + } + set(key, value) { + return super.set(intern_set(this, key), value); + } + delete(key) { + return super.delete(intern_delete(this, key)); + } + } + function intern_get({ _intern, _key }, value) { + const key = _key(value); + return _intern.has(key) ? _intern.get(key) : value; + } + function intern_set({ _intern, _key }, value) { + const key = _key(value); + if (_intern.has(key)) + return _intern.get(key); + _intern.set(key, value); + return value; + } + function intern_delete({ _intern, _key }, value) { + const key = _key(value); + if (_intern.has(key)) { + value = _intern.get(key); + _intern.delete(key); + } + return value; + } + function keyof(value) { + return value !== null && typeof value === "object" ? value.valueOf() : value; + } + var e10 = Math.sqrt(50), e5 = Math.sqrt(10), e2 = Math.sqrt(2); + function ticks(start2, stop, count) { + var reverse, i2 = -1, n, ticks2, step; + stop = +stop, start2 = +start2, count = +count; + if (start2 === stop && count > 0) + return [start2]; + if (reverse = stop < start2) + n = start2, start2 = stop, stop = n; + if ((step = tickIncrement(start2, stop, count)) === 0 || !isFinite(step)) + return []; + if (step > 0) { + let r0 = Math.round(start2 / step), r1 = Math.round(stop / step); + if (r0 * step < start2) + ++r0; + if (r1 * step > stop) + --r1; + ticks2 = new Array(n = r1 - r0 + 1); + while (++i2 < n) + ticks2[i2] = (r0 + i2) * step; + } else { + step = -step; + let r0 = Math.round(start2 * step), r1 = Math.round(stop * step); + if (r0 / step < start2) + ++r0; + if (r1 / step > stop) + --r1; + ticks2 = new Array(n = r1 - r0 + 1); + while (++i2 < n) + ticks2[i2] = (r0 + i2) / step; + } + if (reverse) + ticks2.reverse(); + return ticks2; + } + function tickIncrement(start2, stop, count) { + var step = (stop - start2) / Math.max(0, count), power = Math.floor(Math.log(step) / Math.LN10), error = step / Math.pow(10, power); + return power >= 0 ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power) : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1); + } + function tickStep(start2, stop, count) { + var step0 = Math.abs(stop - start2) / Math.max(0, count), step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), error = step0 / step1; + if (error >= e10) + step1 *= 10; + else if (error >= e5) + step1 *= 5; + else if (error >= e2) + step1 *= 2; + return stop < start2 ? -step1 : step1; + } + function max$2(values2, valueof) { + let max2; + if (valueof === void 0) { + for (const value of values2) { + if (value != null && (max2 < value || max2 === void 0 && value >= value)) { + max2 = value; + } + } + } else { + let index = -1; + for (let value of values2) { + if ((value = valueof(value, ++index, values2)) != null && (max2 < value || max2 === void 0 && value >= value)) { + max2 = value; + } + } + } + return max2; + } + function min$2(values2, valueof) { + let min2; + if (valueof === void 0) { + for (const value of values2) { + if (value != null && (min2 > value || min2 === void 0 && value >= value)) { + min2 = value; + } + } + } else { + let index = -1; + for (let value of values2) { + if ((value = valueof(value, ++index, values2)) != null && (min2 > value || min2 === void 0 && value >= value)) { + min2 = value; + } + } + } + return min2; + } + function identity$5(x2) { + return x2; + } + var top = 1, right = 2, bottom = 3, left = 4, epsilon$2 = 1e-6; + function translateX(x2) { + return "translate(" + x2 + ",0)"; + } + function translateY(y2) { + return "translate(0," + y2 + ")"; + } + function number$2(scale) { + return (d) => +scale(d); + } + function center(scale, offset) { + offset = Math.max(0, scale.bandwidth() - offset * 2) / 2; + if (scale.round()) + offset = Math.round(offset); + return (d) => +scale(d) + offset; + } + function entering() { + return !this.__axis; + } + function axis(orient, scale) { + var tickArguments = [], tickValues = null, tickFormat2 = null, tickSizeInner = 6, tickSizeOuter = 6, tickPadding = 3, offset = typeof window !== "undefined" && window.devicePixelRatio > 1 ? 0 : 0.5, k = orient === top || orient === left ? -1 : 1, x2 = orient === left || orient === right ? "x" : "y", transform = orient === top || orient === bottom ? translateX : translateY; + function axis2(context) { + var values2 = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain() : tickValues, format2 = tickFormat2 == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$5 : tickFormat2, spacing = Math.max(tickSizeInner, 0) + tickPadding, range2 = scale.range(), range0 = +range2[0] + offset, range1 = +range2[range2.length - 1] + offset, position2 = (scale.bandwidth ? center : number$2)(scale.copy(), offset), selection2 = context.selection ? context.selection() : context, path2 = selection2.selectAll(".domain").data([null]), tick = selection2.selectAll(".tick").data(values2, scale).order(), tickExit = tick.exit(), tickEnter = tick.enter().append("g").attr("class", "tick"), line2 = tick.select("line"), text2 = tick.select("text"); + path2 = path2.merge(path2.enter().insert("path", ".tick").attr("class", "domain").attr("stroke", "currentColor")); + tick = tick.merge(tickEnter); + line2 = line2.merge(tickEnter.append("line").attr("stroke", "currentColor").attr(x2 + "2", k * tickSizeInner)); + text2 = text2.merge(tickEnter.append("text").attr("fill", "currentColor").attr(x2, k * spacing).attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em")); + if (context !== selection2) { + path2 = path2.transition(context); + tick = tick.transition(context); + line2 = line2.transition(context); + text2 = text2.transition(context); + tickExit = tickExit.transition(context).attr("opacity", epsilon$2).attr("transform", function(d) { + return isFinite(d = position2(d)) ? transform(d + offset) : this.getAttribute("transform"); + }); + tickEnter.attr("opacity", epsilon$2).attr("transform", function(d) { + var p = this.parentNode.__axis; + return transform((p && isFinite(p = p(d)) ? p : position2(d)) + offset); + }); + } + tickExit.remove(); + path2.attr("d", orient === left || orient === right ? tickSizeOuter ? "M" + k * tickSizeOuter + "," + range0 + "H" + offset + "V" + range1 + "H" + k * tickSizeOuter : "M" + offset + "," + range0 + "V" + range1 : tickSizeOuter ? "M" + range0 + "," + k * tickSizeOuter + "V" + offset + "H" + range1 + "V" + k * tickSizeOuter : "M" + range0 + "," + offset + "H" + range1); + tick.attr("opacity", 1).attr("transform", function(d) { + return transform(position2(d) + offset); + }); + line2.attr(x2 + "2", k * tickSizeInner); + text2.attr(x2, k * spacing).text(format2); + selection2.filter(entering).attr("fill", "none").attr("font-size", 10).attr("font-family", "sans-serif").attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle"); + selection2.each(function() { + this.__axis = position2; + }); + } + axis2.scale = function(_2) { + return arguments.length ? (scale = _2, axis2) : scale; + }; + axis2.ticks = function() { + return tickArguments = Array.from(arguments), axis2; + }; + axis2.tickArguments = function(_2) { + return arguments.length ? (tickArguments = _2 == null ? [] : Array.from(_2), axis2) : tickArguments.slice(); + }; + axis2.tickValues = function(_2) { + return arguments.length ? (tickValues = _2 == null ? null : Array.from(_2), axis2) : tickValues && tickValues.slice(); + }; + axis2.tickFormat = function(_2) { + return arguments.length ? (tickFormat2 = _2, axis2) : tickFormat2; + }; + axis2.tickSize = function(_2) { + return arguments.length ? (tickSizeInner = tickSizeOuter = +_2, axis2) : tickSizeInner; + }; + axis2.tickSizeInner = function(_2) { + return arguments.length ? (tickSizeInner = +_2, axis2) : tickSizeInner; + }; + axis2.tickSizeOuter = function(_2) { + return arguments.length ? (tickSizeOuter = +_2, axis2) : tickSizeOuter; + }; + axis2.tickPadding = function(_2) { + return arguments.length ? (tickPadding = +_2, axis2) : tickPadding; + }; + axis2.offset = function(_2) { + return arguments.length ? (offset = +_2, axis2) : offset; + }; + return axis2; + } + function axisTop(scale) { + return axis(top, scale); + } + function axisBottom(scale) { + return axis(bottom, scale); + } + var noop$2 = { value: () => { + } }; + function dispatch() { + for (var i2 = 0, n = arguments.length, _2 = {}, t; i2 < n; ++i2) { + if (!(t = arguments[i2] + "") || t in _2 || /[\s.]/.test(t)) + throw new Error("illegal type: " + t); + _2[t] = []; + } + return new Dispatch(_2); + } + function Dispatch(_2) { + this._ = _2; + } + function parseTypenames$1(typenames, types2) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name2 = "", i2 = t.indexOf("."); + if (i2 >= 0) + name2 = t.slice(i2 + 1), t = t.slice(0, i2); + if (t && !types2.hasOwnProperty(t)) + throw new Error("unknown type: " + t); + return { type: t, name: name2 }; + }); + } + Dispatch.prototype = dispatch.prototype = { + constructor: Dispatch, + on: function(typename, callback) { + var _2 = this._, T = parseTypenames$1(typename + "", _2), t, i2 = -1, n = T.length; + if (arguments.length < 2) { + while (++i2 < n) + if ((t = (typename = T[i2]).type) && (t = get$3(_2[t], typename.name))) + return t; + return; + } + if (callback != null && typeof callback !== "function") + throw new Error("invalid callback: " + callback); + while (++i2 < n) { + if (t = (typename = T[i2]).type) + _2[t] = set$3(_2[t], typename.name, callback); + else if (callback == null) + for (t in _2) + _2[t] = set$3(_2[t], typename.name, null); + } + return this; + }, + copy: function() { + var copy2 = {}, _2 = this._; + for (var t in _2) + copy2[t] = _2[t].slice(); + return new Dispatch(copy2); + }, + call: function(type2, that) { + if ((n = arguments.length - 2) > 0) + for (var args = new Array(n), i2 = 0, n, t; i2 < n; ++i2) + args[i2] = arguments[i2 + 2]; + if (!this._.hasOwnProperty(type2)) + throw new Error("unknown type: " + type2); + for (t = this._[type2], i2 = 0, n = t.length; i2 < n; ++i2) + t[i2].value.apply(that, args); + }, + apply: function(type2, that, args) { + if (!this._.hasOwnProperty(type2)) + throw new Error("unknown type: " + type2); + for (var t = this._[type2], i2 = 0, n = t.length; i2 < n; ++i2) + t[i2].value.apply(that, args); + } + }; + function get$3(type2, name2) { + for (var i2 = 0, n = type2.length, c2; i2 < n; ++i2) { + if ((c2 = type2[i2]).name === name2) { + return c2.value; + } + } + } + function set$3(type2, name2, callback) { + for (var i2 = 0, n = type2.length; i2 < n; ++i2) { + if (type2[i2].name === name2) { + type2[i2] = noop$2, type2 = type2.slice(0, i2).concat(type2.slice(i2 + 1)); + break; + } + } + if (callback != null) + type2.push({ name: name2, value: callback }); + return type2; + } + var xhtml = "http://www.w3.org/1999/xhtml"; + const namespaces = { + svg: "http://www.w3.org/2000/svg", + xhtml, + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" + }; + function namespace(name2) { + var prefix = name2 += "", i2 = prefix.indexOf(":"); + if (i2 >= 0 && (prefix = name2.slice(0, i2)) !== "xmlns") + name2 = name2.slice(i2 + 1); + return namespaces.hasOwnProperty(prefix) ? { space: namespaces[prefix], local: name2 } : name2; + } + function creatorInherit(name2) { + return function() { + var document2 = this.ownerDocument, uri = this.namespaceURI; + return uri === xhtml && document2.documentElement.namespaceURI === xhtml ? document2.createElement(name2) : document2.createElementNS(uri, name2); + }; + } + function creatorFixed(fullname) { + return function() { + return this.ownerDocument.createElementNS(fullname.space, fullname.local); + }; + } + function creator(name2) { + var fullname = namespace(name2); + return (fullname.local ? creatorFixed : creatorInherit)(fullname); + } + function none() { + } + function selector(selector2) { + return selector2 == null ? none : function() { + return this.querySelector(selector2); + }; + } + function selection_select(select2) { + if (typeof select2 !== "function") + select2 = selector(select2); + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node2, subnode, i2 = 0; i2 < n; ++i2) { + if ((node2 = group[i2]) && (subnode = select2.call(node2, node2.__data__, i2, group))) { + if ("__data__" in node2) + subnode.__data__ = node2.__data__; + subgroup[i2] = subnode; + } + } + } + return new Selection$1(subgroups, this._parents); + } + function array$1(x2) { + return x2 == null ? [] : Array.isArray(x2) ? x2 : Array.from(x2); + } + function empty() { + return []; + } + function selectorAll(selector2) { + return selector2 == null ? empty : function() { + return this.querySelectorAll(selector2); + }; + } + function arrayAll(select2) { + return function() { + return array$1(select2.apply(this, arguments)); + }; + } + function selection_selectAll(select2) { + if (typeof select2 === "function") + select2 = arrayAll(select2); + else + select2 = selectorAll(select2); + for (var groups = this._groups, m = groups.length, subgroups = [], parents2 = [], j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node2, i2 = 0; i2 < n; ++i2) { + if (node2 = group[i2]) { + subgroups.push(select2.call(node2, node2.__data__, i2, group)); + parents2.push(node2); + } + } + } + return new Selection$1(subgroups, parents2); + } + function matcher(selector2) { + return function() { + return this.matches(selector2); + }; + } + function childMatcher(selector2) { + return function(node2) { + return node2.matches(selector2); + }; + } + var find$2 = Array.prototype.find; + function childFind(match) { + return function() { + return find$2.call(this.children, match); + }; + } + function childFirst() { + return this.firstElementChild; + } + function selection_selectChild(match) { + return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match))); + } + var filter$1 = Array.prototype.filter; + function children() { + return Array.from(this.children); + } + function childrenFilter(match) { + return function() { + return filter$1.call(this.children, match); + }; + } + function selection_selectChildren(match) { + return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match))); + } + function selection_filter(match) { + if (typeof match !== "function") + match = matcher(match); + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node2, i2 = 0; i2 < n; ++i2) { + if ((node2 = group[i2]) && match.call(node2, node2.__data__, i2, group)) { + subgroup.push(node2); + } + } + } + return new Selection$1(subgroups, this._parents); + } + function sparse(update) { + return new Array(update.length); + } + function selection_enter() { + return new Selection$1(this._enter || this._groups.map(sparse), this._parents); + } + function EnterNode(parent, datum2) { + this.ownerDocument = parent.ownerDocument; + this.namespaceURI = parent.namespaceURI; + this._next = null; + this._parent = parent; + this.__data__ = datum2; + } + EnterNode.prototype = { + constructor: EnterNode, + appendChild: function(child) { + return this._parent.insertBefore(child, this._next); + }, + insertBefore: function(child, next2) { + return this._parent.insertBefore(child, next2); + }, + querySelector: function(selector2) { + return this._parent.querySelector(selector2); + }, + querySelectorAll: function(selector2) { + return this._parent.querySelectorAll(selector2); + } + }; + function constant$3(x2) { + return function() { + return x2; + }; + } + function bindIndex(parent, group, enter2, update, exit2, data) { + var i2 = 0, node2, groupLength = group.length, dataLength = data.length; + for (; i2 < dataLength; ++i2) { + if (node2 = group[i2]) { + node2.__data__ = data[i2]; + update[i2] = node2; + } else { + enter2[i2] = new EnterNode(parent, data[i2]); + } + } + for (; i2 < groupLength; ++i2) { + if (node2 = group[i2]) { + exit2[i2] = node2; + } + } + } + function bindKey(parent, group, enter2, update, exit2, data, key) { + var i2, node2, nodeByKeyValue = /* @__PURE__ */ new Map(), groupLength = group.length, dataLength = data.length, keyValues = new Array(groupLength), keyValue; + for (i2 = 0; i2 < groupLength; ++i2) { + if (node2 = group[i2]) { + keyValues[i2] = keyValue = key.call(node2, node2.__data__, i2, group) + ""; + if (nodeByKeyValue.has(keyValue)) { + exit2[i2] = node2; + } else { + nodeByKeyValue.set(keyValue, node2); + } + } + } + for (i2 = 0; i2 < dataLength; ++i2) { + keyValue = key.call(parent, data[i2], i2, data) + ""; + if (node2 = nodeByKeyValue.get(keyValue)) { + update[i2] = node2; + node2.__data__ = data[i2]; + nodeByKeyValue.delete(keyValue); + } else { + enter2[i2] = new EnterNode(parent, data[i2]); + } + } + for (i2 = 0; i2 < groupLength; ++i2) { + if ((node2 = group[i2]) && nodeByKeyValue.get(keyValues[i2]) === node2) { + exit2[i2] = node2; + } + } + } + function datum(node2) { + return node2.__data__; + } + function selection_data(value, key) { + if (!arguments.length) + return Array.from(this, datum); + var bind = key ? bindKey : bindIndex, parents2 = this._parents, groups = this._groups; + if (typeof value !== "function") + value = constant$3(value); + for (var m = groups.length, update = new Array(m), enter2 = new Array(m), exit2 = new Array(m), j = 0; j < m; ++j) { + var parent = parents2[j], group = groups[j], groupLength = group.length, data = arraylike(value.call(parent, parent && parent.__data__, j, parents2)), dataLength = data.length, enterGroup = enter2[j] = new Array(dataLength), updateGroup = update[j] = new Array(dataLength), exitGroup = exit2[j] = new Array(groupLength); + bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); + for (var i0 = 0, i1 = 0, previous, next2; i0 < dataLength; ++i0) { + if (previous = enterGroup[i0]) { + if (i0 >= i1) + i1 = i0 + 1; + while (!(next2 = updateGroup[i1]) && ++i1 < dataLength) + ; + previous._next = next2 || null; + } + } + } + update = new Selection$1(update, parents2); + update._enter = enter2; + update._exit = exit2; + return update; + } + function arraylike(data) { + return typeof data === "object" && "length" in data ? data : Array.from(data); + } + function selection_exit() { + return new Selection$1(this._exit || this._groups.map(sparse), this._parents); + } + function selection_join(onenter, onupdate, onexit) { + var enter2 = this.enter(), update = this, exit2 = this.exit(); + if (typeof onenter === "function") { + enter2 = onenter(enter2); + if (enter2) + enter2 = enter2.selection(); + } else { + enter2 = enter2.append(onenter + ""); + } + if (onupdate != null) { + update = onupdate(update); + if (update) + update = update.selection(); + } + if (onexit == null) + exit2.remove(); + else + onexit(exit2); + return enter2 && update ? enter2.merge(update).order() : update; + } + function selection_merge(context) { + var selection2 = context.selection ? context.selection() : context; + for (var groups0 = this._groups, groups1 = selection2._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge2 = merges[j] = new Array(n), node2, i2 = 0; i2 < n; ++i2) { + if (node2 = group0[i2] || group1[i2]) { + merge2[i2] = node2; + } + } + } + for (; j < m0; ++j) { + merges[j] = groups0[j]; + } + return new Selection$1(merges, this._parents); + } + function selection_order() { + for (var groups = this._groups, j = -1, m = groups.length; ++j < m; ) { + for (var group = groups[j], i2 = group.length - 1, next2 = group[i2], node2; --i2 >= 0; ) { + if (node2 = group[i2]) { + if (next2 && node2.compareDocumentPosition(next2) ^ 4) + next2.parentNode.insertBefore(node2, next2); + next2 = node2; + } + } + } + return this; + } + function selection_sort(compare) { + if (!compare) + compare = ascending; + function compareNode(a, b) { + return a && b ? compare(a.__data__, b.__data__) : !a - !b; + } + for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node2, i2 = 0; i2 < n; ++i2) { + if (node2 = group[i2]) { + sortgroup[i2] = node2; + } + } + sortgroup.sort(compareNode); + } + return new Selection$1(sortgroups, this._parents).order(); + } + function ascending(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; + } + function selection_call() { + var callback = arguments[0]; + arguments[0] = this; + callback.apply(null, arguments); + return this; + } + function selection_nodes() { + return Array.from(this); + } + function selection_node() { + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i2 = 0, n = group.length; i2 < n; ++i2) { + var node2 = group[i2]; + if (node2) + return node2; + } + } + return null; + } + function selection_size() { + let size2 = 0; + for (const node2 of this) + ++size2; + return size2; + } + function selection_empty() { + return !this.node(); + } + function selection_each(callback) { + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i2 = 0, n = group.length, node2; i2 < n; ++i2) { + if (node2 = group[i2]) + callback.call(node2, node2.__data__, i2, group); + } + } + return this; + } + function attrRemove$1(name2) { + return function() { + this.removeAttribute(name2); + }; + } + function attrRemoveNS$1(fullname) { + return function() { + this.removeAttributeNS(fullname.space, fullname.local); + }; + } + function attrConstant$1(name2, value) { + return function() { + this.setAttribute(name2, value); + }; + } + function attrConstantNS$1(fullname, value) { + return function() { + this.setAttributeNS(fullname.space, fullname.local, value); + }; + } + function attrFunction$1(name2, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) + this.removeAttribute(name2); + else + this.setAttribute(name2, v); + }; + } + function attrFunctionNS$1(fullname, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) + this.removeAttributeNS(fullname.space, fullname.local); + else + this.setAttributeNS(fullname.space, fullname.local, v); + }; + } + function selection_attr(name2, value) { + var fullname = namespace(name2); + if (arguments.length < 2) { + var node2 = this.node(); + return fullname.local ? node2.getAttributeNS(fullname.space, fullname.local) : node2.getAttribute(fullname); + } + return this.each((value == null ? fullname.local ? attrRemoveNS$1 : attrRemove$1 : typeof value === "function" ? fullname.local ? attrFunctionNS$1 : attrFunction$1 : fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, value)); + } + function defaultView(node2) { + return node2.ownerDocument && node2.ownerDocument.defaultView || node2.document && node2 || node2.defaultView; + } + function styleRemove$1(name2) { + return function() { + this.style.removeProperty(name2); + }; + } + function styleConstant$1(name2, value, priority) { + return function() { + this.style.setProperty(name2, value, priority); + }; + } + function styleFunction$1(name2, value, priority) { + return function() { + var v = value.apply(this, arguments); + if (v == null) + this.style.removeProperty(name2); + else + this.style.setProperty(name2, v, priority); + }; + } + function selection_style(name2, value, priority) { + return arguments.length > 1 ? this.each((value == null ? styleRemove$1 : typeof value === "function" ? styleFunction$1 : styleConstant$1)(name2, value, priority == null ? "" : priority)) : styleValue(this.node(), name2); + } + function styleValue(node2, name2) { + return node2.style.getPropertyValue(name2) || defaultView(node2).getComputedStyle(node2, null).getPropertyValue(name2); + } + function propertyRemove(name2) { + return function() { + delete this[name2]; + }; + } + function propertyConstant(name2, value) { + return function() { + this[name2] = value; + }; + } + function propertyFunction(name2, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) + delete this[name2]; + else + this[name2] = v; + }; + } + function selection_property(name2, value) { + return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name2, value)) : this.node()[name2]; + } + function classArray(string) { + return string.trim().split(/^|\s+/); + } + function classList(node2) { + return node2.classList || new ClassList(node2); + } + function ClassList(node2) { + this._node = node2; + this._names = classArray(node2.getAttribute("class") || ""); + } + ClassList.prototype = { + add: function(name2) { + var i2 = this._names.indexOf(name2); + if (i2 < 0) { + this._names.push(name2); + this._node.setAttribute("class", this._names.join(" ")); + } + }, + remove: function(name2) { + var i2 = this._names.indexOf(name2); + if (i2 >= 0) { + this._names.splice(i2, 1); + this._node.setAttribute("class", this._names.join(" ")); + } + }, + contains: function(name2) { + return this._names.indexOf(name2) >= 0; + } + }; + function classedAdd(node2, names) { + var list = classList(node2), i2 = -1, n = names.length; + while (++i2 < n) + list.add(names[i2]); + } + function classedRemove(node2, names) { + var list = classList(node2), i2 = -1, n = names.length; + while (++i2 < n) + list.remove(names[i2]); + } + function classedTrue(names) { + return function() { + classedAdd(this, names); + }; + } + function classedFalse(names) { + return function() { + classedRemove(this, names); + }; + } + function classedFunction(names, value) { + return function() { + (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names); + }; + } + function selection_classed(name2, value) { + var names = classArray(name2 + ""); + if (arguments.length < 2) { + var list = classList(this.node()), i2 = -1, n = names.length; + while (++i2 < n) + if (!list.contains(names[i2])) + return false; + return true; + } + return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value)); + } + function textRemove() { + this.textContent = ""; + } + function textConstant$1(value) { + return function() { + this.textContent = value; + }; + } + function textFunction$1(value) { + return function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + }; + } + function selection_text(value) { + return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction$1 : textConstant$1)(value)) : this.node().textContent; + } + function htmlRemove() { + this.innerHTML = ""; + } + function htmlConstant(value) { + return function() { + this.innerHTML = value; + }; + } + function htmlFunction(value) { + return function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + }; + } + function selection_html(value) { + return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML; + } + function raise() { + if (this.nextSibling) + this.parentNode.appendChild(this); + } + function selection_raise() { + return this.each(raise); + } + function lower() { + if (this.previousSibling) + this.parentNode.insertBefore(this, this.parentNode.firstChild); + } + function selection_lower() { + return this.each(lower); + } + function selection_append(name2) { + var create2 = typeof name2 === "function" ? name2 : creator(name2); + return this.select(function() { + return this.appendChild(create2.apply(this, arguments)); + }); + } + function constantNull() { + return null; + } + function selection_insert(name2, before) { + var create2 = typeof name2 === "function" ? name2 : creator(name2), select2 = before == null ? constantNull : typeof before === "function" ? before : selector(before); + return this.select(function() { + return this.insertBefore(create2.apply(this, arguments), select2.apply(this, arguments) || null); + }); + } + function remove() { + var parent = this.parentNode; + if (parent) + parent.removeChild(this); + } + function selection_remove() { + return this.each(remove); + } + function selection_cloneShallow() { + var clone2 = this.cloneNode(false), parent = this.parentNode; + return parent ? parent.insertBefore(clone2, this.nextSibling) : clone2; + } + function selection_cloneDeep() { + var clone2 = this.cloneNode(true), parent = this.parentNode; + return parent ? parent.insertBefore(clone2, this.nextSibling) : clone2; + } + function selection_clone(deep) { + return this.select(deep ? selection_cloneDeep : selection_cloneShallow); + } + function selection_datum(value) { + return arguments.length ? this.property("__data__", value) : this.node().__data__; + } + function contextListener(listener) { + return function(event) { + listener.call(this, event, this.__data__); + }; + } + function parseTypenames(typenames) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name2 = "", i2 = t.indexOf("."); + if (i2 >= 0) + name2 = t.slice(i2 + 1), t = t.slice(0, i2); + return { type: t, name: name2 }; + }); + } + function onRemove(typename) { + return function() { + var on = this.__on; + if (!on) + return; + for (var j = 0, i2 = -1, m = on.length, o; j < m; ++j) { + if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) { + this.removeEventListener(o.type, o.listener, o.options); + } else { + on[++i2] = o; + } + } + if (++i2) + on.length = i2; + else + delete this.__on; + }; + } + function onAdd(typename, value, options2) { + return function() { + var on = this.__on, o, listener = contextListener(value); + if (on) + for (var j = 0, m = on.length; j < m; ++j) { + if ((o = on[j]).type === typename.type && o.name === typename.name) { + this.removeEventListener(o.type, o.listener, o.options); + this.addEventListener(o.type, o.listener = listener, o.options = options2); + o.value = value; + return; + } + } + this.addEventListener(typename.type, listener, options2); + o = { type: typename.type, name: typename.name, value, listener, options: options2 }; + if (!on) + this.__on = [o]; + else + on.push(o); + }; + } + function selection_on(typename, value, options2) { + var typenames = parseTypenames(typename + ""), i2, n = typenames.length, t; + if (arguments.length < 2) { + var on = this.node().__on; + if (on) + for (var j = 0, m = on.length, o; j < m; ++j) { + for (i2 = 0, o = on[j]; i2 < n; ++i2) { + if ((t = typenames[i2]).type === o.type && t.name === o.name) { + return o.value; + } + } + } + return; + } + on = value ? onAdd : onRemove; + for (i2 = 0; i2 < n; ++i2) + this.each(on(typenames[i2], value, options2)); + return this; + } + function dispatchEvent(node2, type2, params) { + var window2 = defaultView(node2), event = window2.CustomEvent; + if (typeof event === "function") { + event = new event(type2, params); + } else { + event = window2.document.createEvent("Event"); + if (params) + event.initEvent(type2, params.bubbles, params.cancelable), event.detail = params.detail; + else + event.initEvent(type2, false, false); + } + node2.dispatchEvent(event); + } + function dispatchConstant(type2, params) { + return function() { + return dispatchEvent(this, type2, params); + }; + } + function dispatchFunction(type2, params) { + return function() { + return dispatchEvent(this, type2, params.apply(this, arguments)); + }; + } + function selection_dispatch(type2, params) { + return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type2, params)); + } + function* selection_iterator() { + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i2 = 0, n = group.length, node2; i2 < n; ++i2) { + if (node2 = group[i2]) + yield node2; + } + } + } + var root$2 = [null]; + function Selection$1(groups, parents2) { + this._groups = groups; + this._parents = parents2; + } + function selection() { + return new Selection$1([[document.documentElement]], root$2); + } + function selection_selection() { + return this; + } + Selection$1.prototype = selection.prototype = { + constructor: Selection$1, + select: selection_select, + selectAll: selection_selectAll, + selectChild: selection_selectChild, + selectChildren: selection_selectChildren, + filter: selection_filter, + data: selection_data, + enter: selection_enter, + exit: selection_exit, + join: selection_join, + merge: selection_merge, + selection: selection_selection, + order: selection_order, + sort: selection_sort, + call: selection_call, + nodes: selection_nodes, + node: selection_node, + size: selection_size, + empty: selection_empty, + each: selection_each, + attr: selection_attr, + style: selection_style, + property: selection_property, + classed: selection_classed, + text: selection_text, + html: selection_html, + raise: selection_raise, + lower: selection_lower, + append: selection_append, + insert: selection_insert, + remove: selection_remove, + clone: selection_clone, + datum: selection_datum, + on: selection_on, + dispatch: selection_dispatch, + [Symbol.iterator]: selection_iterator + }; + function select(selector2) { + return typeof selector2 === "string" ? new Selection$1([[document.querySelector(selector2)]], [document.documentElement]) : new Selection$1([[selector2]], root$2); + } + function selectAll(selector2) { + return typeof selector2 === "string" ? new Selection$1([document.querySelectorAll(selector2)], [document.documentElement]) : new Selection$1([array$1(selector2)], root$2); + } + function define2(constructor, factory, prototype) { + constructor.prototype = factory.prototype = prototype; + prototype.constructor = constructor; + } + function extend$1(parent, definition) { + var prototype = Object.create(parent.prototype); + for (var key in definition) + prototype[key] = definition[key]; + return prototype; + } + function Color$2() { + } + var darker = 0.7; + var brighter = 1 / darker; + var reI = "\\s*([+-]?\\d+)\\s*", reN = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*", reP = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*", reHex = /^#([0-9a-f]{3,8})$/, reRgbInteger = new RegExp(`^rgb\\(${reI},${reI},${reI}\\)$`), reRgbPercent = new RegExp(`^rgb\\(${reP},${reP},${reP}\\)$`), reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`), reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`), reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`), reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`); + var named = { + aliceblue: 15792383, + antiquewhite: 16444375, + aqua: 65535, + aquamarine: 8388564, + azure: 15794175, + beige: 16119260, + bisque: 16770244, + black: 0, + blanchedalmond: 16772045, + blue: 255, + blueviolet: 9055202, + brown: 10824234, + burlywood: 14596231, + cadetblue: 6266528, + chartreuse: 8388352, + chocolate: 13789470, + coral: 16744272, + cornflowerblue: 6591981, + cornsilk: 16775388, + crimson: 14423100, + cyan: 65535, + darkblue: 139, + darkcyan: 35723, + darkgoldenrod: 12092939, + darkgray: 11119017, + darkgreen: 25600, + darkgrey: 11119017, + darkkhaki: 12433259, + darkmagenta: 9109643, + darkolivegreen: 5597999, + darkorange: 16747520, + darkorchid: 10040012, + darkred: 9109504, + darksalmon: 15308410, + darkseagreen: 9419919, + darkslateblue: 4734347, + darkslategray: 3100495, + darkslategrey: 3100495, + darkturquoise: 52945, + darkviolet: 9699539, + deeppink: 16716947, + deepskyblue: 49151, + dimgray: 6908265, + dimgrey: 6908265, + dodgerblue: 2003199, + firebrick: 11674146, + floralwhite: 16775920, + forestgreen: 2263842, + fuchsia: 16711935, + gainsboro: 14474460, + ghostwhite: 16316671, + gold: 16766720, + goldenrod: 14329120, + gray: 8421504, + green: 32768, + greenyellow: 11403055, + grey: 8421504, + honeydew: 15794160, + hotpink: 16738740, + indianred: 13458524, + indigo: 4915330, + ivory: 16777200, + khaki: 15787660, + lavender: 15132410, + lavenderblush: 16773365, + lawngreen: 8190976, + lemonchiffon: 16775885, + lightblue: 11393254, + lightcoral: 15761536, + lightcyan: 14745599, + lightgoldenrodyellow: 16448210, + lightgray: 13882323, + lightgreen: 9498256, + lightgrey: 13882323, + lightpink: 16758465, + lightsalmon: 16752762, + lightseagreen: 2142890, + lightskyblue: 8900346, + lightslategray: 7833753, + lightslategrey: 7833753, + lightsteelblue: 11584734, + lightyellow: 16777184, + lime: 65280, + limegreen: 3329330, + linen: 16445670, + magenta: 16711935, + maroon: 8388608, + mediumaquamarine: 6737322, + mediumblue: 205, + mediumorchid: 12211667, + mediumpurple: 9662683, + mediumseagreen: 3978097, + mediumslateblue: 8087790, + mediumspringgreen: 64154, + mediumturquoise: 4772300, + mediumvioletred: 13047173, + midnightblue: 1644912, + mintcream: 16121850, + mistyrose: 16770273, + moccasin: 16770229, + navajowhite: 16768685, + navy: 128, + oldlace: 16643558, + olive: 8421376, + olivedrab: 7048739, + orange: 16753920, + orangered: 16729344, + orchid: 14315734, + palegoldenrod: 15657130, + palegreen: 10025880, + paleturquoise: 11529966, + palevioletred: 14381203, + papayawhip: 16773077, + peachpuff: 16767673, + peru: 13468991, + pink: 16761035, + plum: 14524637, + powderblue: 11591910, + purple: 8388736, + rebeccapurple: 6697881, + red: 16711680, + rosybrown: 12357519, + royalblue: 4286945, + saddlebrown: 9127187, + salmon: 16416882, + sandybrown: 16032864, + seagreen: 3050327, + seashell: 16774638, + sienna: 10506797, + silver: 12632256, + skyblue: 8900331, + slateblue: 6970061, + slategray: 7372944, + slategrey: 7372944, + snow: 16775930, + springgreen: 65407, + steelblue: 4620980, + tan: 13808780, + teal: 32896, + thistle: 14204888, + tomato: 16737095, + turquoise: 4251856, + violet: 15631086, + wheat: 16113331, + white: 16777215, + whitesmoke: 16119285, + yellow: 16776960, + yellowgreen: 10145074 + }; + define2(Color$2, color, { + copy(channels2) { + return Object.assign(new this.constructor(), this, channels2); + }, + displayable() { + return this.rgb().displayable(); + }, + hex: color_formatHex, + formatHex: color_formatHex, + formatHex8: color_formatHex8, + formatHsl: color_formatHsl, + formatRgb: color_formatRgb, + toString: color_formatRgb + }); + function color_formatHex() { + return this.rgb().formatHex(); + } + function color_formatHex8() { + return this.rgb().formatHex8(); + } + function color_formatHsl() { + return hslConvert(this).formatHsl(); + } + function color_formatRgb() { + return this.rgb().formatRgb(); + } + function color(format2) { + var m, l; + format2 = (format2 + "").trim().toLowerCase(); + return (m = reHex.exec(format2)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) : l === 3 ? new Rgb(m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, (m & 15) << 4 | m & 15, 1) : l === 8 ? rgba$2(m >> 24 & 255, m >> 16 & 255, m >> 8 & 255, (m & 255) / 255) : l === 4 ? rgba$2(m >> 12 & 15 | m >> 8 & 240, m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, ((m & 15) << 4 | m & 15) / 255) : null) : (m = reRgbInteger.exec(format2)) ? new Rgb(m[1], m[2], m[3], 1) : (m = reRgbPercent.exec(format2)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) : (m = reRgbaInteger.exec(format2)) ? rgba$2(m[1], m[2], m[3], m[4]) : (m = reRgbaPercent.exec(format2)) ? rgba$2(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) : (m = reHslPercent.exec(format2)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) : (m = reHslaPercent.exec(format2)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) : named.hasOwnProperty(format2) ? rgbn(named[format2]) : format2 === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null; + } + function rgbn(n) { + return new Rgb(n >> 16 & 255, n >> 8 & 255, n & 255, 1); + } + function rgba$2(r, g, b, a) { + if (a <= 0) + r = g = b = NaN; + return new Rgb(r, g, b, a); + } + function rgbConvert(o) { + if (!(o instanceof Color$2)) + o = color(o); + if (!o) + return new Rgb(); + o = o.rgb(); + return new Rgb(o.r, o.g, o.b, o.opacity); + } + function rgb(r, g, b, opacity) { + return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity); + } + function Rgb(r, g, b, opacity) { + this.r = +r; + this.g = +g; + this.b = +b; + this.opacity = +opacity; + } + define2(Rgb, rgb, extend$1(Color$2, { + brighter(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); + }, + darker(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); + }, + rgb() { + return this; + }, + clamp() { + return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity)); + }, + displayable() { + return -0.5 <= this.r && this.r < 255.5 && (-0.5 <= this.g && this.g < 255.5) && (-0.5 <= this.b && this.b < 255.5) && (0 <= this.opacity && this.opacity <= 1); + }, + hex: rgb_formatHex, + formatHex: rgb_formatHex, + formatHex8: rgb_formatHex8, + formatRgb: rgb_formatRgb, + toString: rgb_formatRgb + })); + function rgb_formatHex() { + return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`; + } + function rgb_formatHex8() { + return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`; + } + function rgb_formatRgb() { + const a = clampa(this.opacity); + return `${a === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? ")" : `, ${a})`}`; + } + function clampa(opacity) { + return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity)); + } + function clampi(value) { + return Math.max(0, Math.min(255, Math.round(value) || 0)); + } + function hex(value) { + value = clampi(value); + return (value < 16 ? "0" : "") + value.toString(16); + } + function hsla(h, s, l, a) { + if (a <= 0) + h = s = l = NaN; + else if (l <= 0 || l >= 1) + h = s = NaN; + else if (s <= 0) + h = NaN; + return new Hsl(h, s, l, a); + } + function hslConvert(o) { + if (o instanceof Hsl) + return new Hsl(o.h, o.s, o.l, o.opacity); + if (!(o instanceof Color$2)) + o = color(o); + if (!o) + return new Hsl(); + if (o instanceof Hsl) + return o; + o = o.rgb(); + var r = o.r / 255, g = o.g / 255, b = o.b / 255, min2 = Math.min(r, g, b), max2 = Math.max(r, g, b), h = NaN, s = max2 - min2, l = (max2 + min2) / 2; + if (s) { + if (r === max2) + h = (g - b) / s + (g < b) * 6; + else if (g === max2) + h = (b - r) / s + 2; + else + h = (r - g) / s + 4; + s /= l < 0.5 ? max2 + min2 : 2 - max2 - min2; + h *= 60; + } else { + s = l > 0 && l < 1 ? 0 : h; + } + return new Hsl(h, s, l, o.opacity); + } + function hsl(h, s, l, opacity) { + return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity); + } + function Hsl(h, s, l, opacity) { + this.h = +h; + this.s = +s; + this.l = +l; + this.opacity = +opacity; + } + define2(Hsl, hsl, extend$1(Color$2, { + brighter(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Hsl(this.h, this.s, this.l * k, this.opacity); + }, + darker(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Hsl(this.h, this.s, this.l * k, this.opacity); + }, + rgb() { + var h = this.h % 360 + (this.h < 0) * 360, s = isNaN(h) || isNaN(this.s) ? 0 : this.s, l = this.l, m2 = l + (l < 0.5 ? l : 1 - l) * s, m1 = 2 * l - m2; + return new Rgb( + hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2), + hsl2rgb(h, m1, m2), + hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), + this.opacity + ); + }, + clamp() { + return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity)); + }, + displayable() { + return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && (0 <= this.l && this.l <= 1) && (0 <= this.opacity && this.opacity <= 1); + }, + formatHsl() { + const a = clampa(this.opacity); + return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`; + } + })); + function clamph(value) { + value = (value || 0) % 360; + return value < 0 ? value + 360 : value; + } + function clampt(value) { + return Math.max(0, Math.min(1, value || 0)); + } + function hsl2rgb(h, m1, m2) { + return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255; + } + const radians = Math.PI / 180; + const degrees$1 = 180 / Math.PI; + const K = 18, Xn = 0.96422, Yn = 1, Zn = 0.82521, t0$1 = 4 / 29, t1$1 = 6 / 29, t2 = 3 * t1$1 * t1$1, t3 = t1$1 * t1$1 * t1$1; + function labConvert(o) { + if (o instanceof Lab) + return new Lab(o.l, o.a, o.b, o.opacity); + if (o instanceof Hcl) + return hcl2lab(o); + if (!(o instanceof Rgb)) + o = rgbConvert(o); + var r = rgb2lrgb(o.r), g = rgb2lrgb(o.g), b = rgb2lrgb(o.b), y2 = xyz2lab((0.2225045 * r + 0.7168786 * g + 0.0606169 * b) / Yn), x2, z; + if (r === g && g === b) + x2 = z = y2; + else { + x2 = xyz2lab((0.4360747 * r + 0.3850649 * g + 0.1430804 * b) / Xn); + z = xyz2lab((0.0139322 * r + 0.0971045 * g + 0.7141733 * b) / Zn); + } + return new Lab(116 * y2 - 16, 500 * (x2 - y2), 200 * (y2 - z), o.opacity); + } + function lab(l, a, b, opacity) { + return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity); + } + function Lab(l, a, b, opacity) { + this.l = +l; + this.a = +a; + this.b = +b; + this.opacity = +opacity; + } + define2(Lab, lab, extend$1(Color$2, { + brighter(k) { + return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity); + }, + darker(k) { + return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity); + }, + rgb() { + var y2 = (this.l + 16) / 116, x2 = isNaN(this.a) ? y2 : y2 + this.a / 500, z = isNaN(this.b) ? y2 : y2 - this.b / 200; + x2 = Xn * lab2xyz(x2); + y2 = Yn * lab2xyz(y2); + z = Zn * lab2xyz(z); + return new Rgb( + lrgb2rgb(3.1338561 * x2 - 1.6168667 * y2 - 0.4906146 * z), + lrgb2rgb(-0.9787684 * x2 + 1.9161415 * y2 + 0.033454 * z), + lrgb2rgb(0.0719453 * x2 - 0.2289914 * y2 + 1.4052427 * z), + this.opacity + ); + } + })); + function xyz2lab(t) { + return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0$1; + } + function lab2xyz(t) { + return t > t1$1 ? t * t * t : t2 * (t - t0$1); + } + function lrgb2rgb(x2) { + return 255 * (x2 <= 31308e-7 ? 12.92 * x2 : 1.055 * Math.pow(x2, 1 / 2.4) - 0.055); + } + function rgb2lrgb(x2) { + return (x2 /= 255) <= 0.04045 ? x2 / 12.92 : Math.pow((x2 + 0.055) / 1.055, 2.4); + } + function hclConvert(o) { + if (o instanceof Hcl) + return new Hcl(o.h, o.c, o.l, o.opacity); + if (!(o instanceof Lab)) + o = labConvert(o); + if (o.a === 0 && o.b === 0) + return new Hcl(NaN, 0 < o.l && o.l < 100 ? 0 : NaN, o.l, o.opacity); + var h = Math.atan2(o.b, o.a) * degrees$1; + return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity); + } + function hcl$1(h, c2, l, opacity) { + return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c2, l, opacity == null ? 1 : opacity); + } + function Hcl(h, c2, l, opacity) { + this.h = +h; + this.c = +c2; + this.l = +l; + this.opacity = +opacity; + } + function hcl2lab(o) { + if (isNaN(o.h)) + return new Lab(o.l, 0, 0, o.opacity); + var h = o.h * radians; + return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity); + } + define2(Hcl, hcl$1, extend$1(Color$2, { + brighter(k) { + return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity); + }, + darker(k) { + return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity); + }, + rgb() { + return hcl2lab(this).rgb(); + } + })); + const constant$2 = (x2) => () => x2; + function linear$1(a, d) { + return function(t) { + return a + t * d; + }; + } + function exponential(a, b, y2) { + return a = Math.pow(a, y2), b = Math.pow(b, y2) - a, y2 = 1 / y2, function(t) { + return Math.pow(a + t * b, y2); + }; + } + function hue(a, b) { + var d = b - a; + return d ? linear$1(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$2(isNaN(a) ? b : a); + } + function gamma(y2) { + return (y2 = +y2) === 1 ? nogamma : function(a, b) { + return b - a ? exponential(a, b, y2) : constant$2(isNaN(a) ? b : a); + }; + } + function nogamma(a, b) { + var d = b - a; + return d ? linear$1(a, d) : constant$2(isNaN(a) ? b : a); + } + const interpolateRgb = function rgbGamma(y2) { + var color2 = gamma(y2); + function rgb$1(start2, end2) { + var r = color2((start2 = rgb(start2)).r, (end2 = rgb(end2)).r), g = color2(start2.g, end2.g), b = color2(start2.b, end2.b), opacity = nogamma(start2.opacity, end2.opacity); + return function(t) { + start2.r = r(t); + start2.g = g(t); + start2.b = b(t); + start2.opacity = opacity(t); + return start2 + ""; + }; + } + rgb$1.gamma = rgbGamma; + return rgb$1; + }(1); + function numberArray(a, b) { + if (!b) + b = []; + var n = a ? Math.min(b.length, a.length) : 0, c2 = b.slice(), i2; + return function(t) { + for (i2 = 0; i2 < n; ++i2) + c2[i2] = a[i2] * (1 - t) + b[i2] * t; + return c2; + }; + } + function isNumberArray(x2) { + return ArrayBuffer.isView(x2) && !(x2 instanceof DataView); + } + function genericArray(a, b) { + var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x2 = new Array(na), c2 = new Array(nb), i2; + for (i2 = 0; i2 < na; ++i2) + x2[i2] = interpolate$1(a[i2], b[i2]); + for (; i2 < nb; ++i2) + c2[i2] = b[i2]; + return function(t) { + for (i2 = 0; i2 < na; ++i2) + c2[i2] = x2[i2](t); + return c2; + }; + } + function date$1(a, b) { + var d = new Date(); + return a = +a, b = +b, function(t) { + return d.setTime(a * (1 - t) + b * t), d; + }; + } + function interpolateNumber(a, b) { + return a = +a, b = +b, function(t) { + return a * (1 - t) + b * t; + }; + } + function object(a, b) { + var i2 = {}, c2 = {}, k; + if (a === null || typeof a !== "object") + a = {}; + if (b === null || typeof b !== "object") + b = {}; + for (k in b) { + if (k in a) { + i2[k] = interpolate$1(a[k], b[k]); + } else { + c2[k] = b[k]; + } + } + return function(t) { + for (k in i2) + c2[k] = i2[k](t); + return c2; + }; + } + var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, reB = new RegExp(reA.source, "g"); + function zero(b) { + return function() { + return b; + }; + } + function one(b) { + return function(t) { + return b(t) + ""; + }; + } + function interpolateString(a, b) { + var bi = reA.lastIndex = reB.lastIndex = 0, am, bm, bs, i2 = -1, s = [], q = []; + a = a + "", b = b + ""; + while ((am = reA.exec(a)) && (bm = reB.exec(b))) { + if ((bs = bm.index) > bi) { + bs = b.slice(bi, bs); + if (s[i2]) + s[i2] += bs; + else + s[++i2] = bs; + } + if ((am = am[0]) === (bm = bm[0])) { + if (s[i2]) + s[i2] += bm; + else + s[++i2] = bm; + } else { + s[++i2] = null; + q.push({ i: i2, x: interpolateNumber(am, bm) }); + } + bi = reB.lastIndex; + } + if (bi < b.length) { + bs = b.slice(bi); + if (s[i2]) + s[i2] += bs; + else + s[++i2] = bs; + } + return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function(t) { + for (var i3 = 0, o; i3 < b; ++i3) + s[(o = q[i3]).i] = o.x(t); + return s.join(""); + }); + } + function interpolate$1(a, b) { + var t = typeof b, c2; + return b == null || t === "boolean" ? constant$2(b) : (t === "number" ? interpolateNumber : t === "string" ? (c2 = color(b)) ? (b = c2, interpolateRgb) : interpolateString : b instanceof color ? interpolateRgb : b instanceof Date ? date$1 : isNumberArray(b) ? numberArray : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object : interpolateNumber)(a, b); + } + function interpolateRound(a, b) { + return a = +a, b = +b, function(t) { + return Math.round(a * (1 - t) + b * t); + }; + } + var degrees = 180 / Math.PI; + var identity$4 = { + translateX: 0, + translateY: 0, + rotate: 0, + skewX: 0, + scaleX: 1, + scaleY: 1 + }; + function decompose(a, b, c2, d, e, f) { + var scaleX, scaleY, skewX; + if (scaleX = Math.sqrt(a * a + b * b)) + a /= scaleX, b /= scaleX; + if (skewX = a * c2 + b * d) + c2 -= a * skewX, d -= b * skewX; + if (scaleY = Math.sqrt(c2 * c2 + d * d)) + c2 /= scaleY, d /= scaleY, skewX /= scaleY; + if (a * d < b * c2) + a = -a, b = -b, skewX = -skewX, scaleX = -scaleX; + return { + translateX: e, + translateY: f, + rotate: Math.atan2(b, a) * degrees, + skewX: Math.atan(skewX) * degrees, + scaleX, + scaleY + }; + } + var svgNode; + function parseCss(value) { + const m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + ""); + return m.isIdentity ? identity$4 : decompose(m.a, m.b, m.c, m.d, m.e, m.f); + } + function parseSvg(value) { + if (value == null) + return identity$4; + if (!svgNode) + svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g"); + svgNode.setAttribute("transform", value); + if (!(value = svgNode.transform.baseVal.consolidate())) + return identity$4; + value = value.matrix; + return decompose(value.a, value.b, value.c, value.d, value.e, value.f); + } + function interpolateTransform(parse2, pxComma, pxParen, degParen) { + function pop(s) { + return s.length ? s.pop() + " " : ""; + } + function translate(xa, ya, xb, yb, s, q) { + if (xa !== xb || ya !== yb) { + var i2 = s.push("translate(", null, pxComma, null, pxParen); + q.push({ i: i2 - 4, x: interpolateNumber(xa, xb) }, { i: i2 - 2, x: interpolateNumber(ya, yb) }); + } else if (xb || yb) { + s.push("translate(" + xb + pxComma + yb + pxParen); + } + } + function rotate(a, b, s, q) { + if (a !== b) { + if (a - b > 180) + b += 360; + else if (b - a > 180) + a += 360; + q.push({ i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: interpolateNumber(a, b) }); + } else if (b) { + s.push(pop(s) + "rotate(" + b + degParen); + } + } + function skewX(a, b, s, q) { + if (a !== b) { + q.push({ i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: interpolateNumber(a, b) }); + } else if (b) { + s.push(pop(s) + "skewX(" + b + degParen); + } + } + function scale(xa, ya, xb, yb, s, q) { + if (xa !== xb || ya !== yb) { + var i2 = s.push(pop(s) + "scale(", null, ",", null, ")"); + q.push({ i: i2 - 4, x: interpolateNumber(xa, xb) }, { i: i2 - 2, x: interpolateNumber(ya, yb) }); + } else if (xb !== 1 || yb !== 1) { + s.push(pop(s) + "scale(" + xb + "," + yb + ")"); + } + } + return function(a, b) { + var s = [], q = []; + a = parse2(a), b = parse2(b); + translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q); + rotate(a.rotate, b.rotate, s, q); + skewX(a.skewX, b.skewX, s, q); + scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q); + a = b = null; + return function(t) { + var i2 = -1, n = q.length, o; + while (++i2 < n) + s[(o = q[i2]).i] = o.x(t); + return s.join(""); + }; + }; + } + var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)"); + var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")"); + function hcl(hue2) { + return function(start2, end2) { + var h = hue2((start2 = hcl$1(start2)).h, (end2 = hcl$1(end2)).h), c2 = nogamma(start2.c, end2.c), l = nogamma(start2.l, end2.l), opacity = nogamma(start2.opacity, end2.opacity); + return function(t) { + start2.h = h(t); + start2.c = c2(t); + start2.l = l(t); + start2.opacity = opacity(t); + return start2 + ""; + }; + }; + } + const interpolateHcl = hcl(hue); + var frame = 0, timeout$1 = 0, interval = 0, pokeDelay = 1e3, taskHead, taskTail, clockLast = 0, clockNow = 0, clockSkew = 0, clock = typeof performance === "object" && performance.now ? performance : Date, setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { + setTimeout(f, 17); + }; + function now$2() { + return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew); + } + function clearNow() { + clockNow = 0; + } + function Timer() { + this._call = this._time = this._next = null; + } + Timer.prototype = timer.prototype = { + constructor: Timer, + restart: function(callback, delay, time2) { + if (typeof callback !== "function") + throw new TypeError("callback is not a function"); + time2 = (time2 == null ? now$2() : +time2) + (delay == null ? 0 : +delay); + if (!this._next && taskTail !== this) { + if (taskTail) + taskTail._next = this; + else + taskHead = this; + taskTail = this; + } + this._call = callback; + this._time = time2; + sleep(); + }, + stop: function() { + if (this._call) { + this._call = null; + this._time = Infinity; + sleep(); + } + } + }; + function timer(callback, delay, time2) { + var t = new Timer(); + t.restart(callback, delay, time2); + return t; + } + function timerFlush() { + now$2(); + ++frame; + var t = taskHead, e; + while (t) { + if ((e = clockNow - t._time) >= 0) + t._call.call(void 0, e); + t = t._next; + } + --frame; + } + function wake() { + clockNow = (clockLast = clock.now()) + clockSkew; + frame = timeout$1 = 0; + try { + timerFlush(); + } finally { + frame = 0; + nap(); + clockNow = 0; + } + } + function poke() { + var now2 = clock.now(), delay = now2 - clockLast; + if (delay > pokeDelay) + clockSkew -= delay, clockLast = now2; + } + function nap() { + var t02, t12 = taskHead, t22, time2 = Infinity; + while (t12) { + if (t12._call) { + if (time2 > t12._time) + time2 = t12._time; + t02 = t12, t12 = t12._next; + } else { + t22 = t12._next, t12._next = null; + t12 = t02 ? t02._next = t22 : taskHead = t22; + } + } + taskTail = t02; + sleep(time2); + } + function sleep(time2) { + if (frame) + return; + if (timeout$1) + timeout$1 = clearTimeout(timeout$1); + var delay = time2 - clockNow; + if (delay > 24) { + if (time2 < Infinity) + timeout$1 = setTimeout(wake, time2 - clock.now() - clockSkew); + if (interval) + interval = clearInterval(interval); + } else { + if (!interval) + clockLast = clock.now(), interval = setInterval(poke, pokeDelay); + frame = 1, setFrame(wake); + } + } + function timeout(callback, delay, time2) { + var t = new Timer(); + delay = delay == null ? 0 : +delay; + t.restart((elapsed) => { + t.stop(); + callback(elapsed + delay); + }, delay, time2); + return t; + } + var emptyOn = dispatch("start", "end", "cancel", "interrupt"); + var emptyTween = []; + var CREATED = 0; + var SCHEDULED = 1; + var STARTING = 2; + var STARTED = 3; + var RUNNING = 4; + var ENDING = 5; + var ENDED = 6; + function schedule(node2, name2, id2, index, group, timing) { + var schedules = node2.__transition; + if (!schedules) + node2.__transition = {}; + else if (id2 in schedules) + return; + create$1(node2, id2, { + name: name2, + index, + group, + on: emptyOn, + tween: emptyTween, + time: timing.time, + delay: timing.delay, + duration: timing.duration, + ease: timing.ease, + timer: null, + state: CREATED + }); + } + function init$1(node2, id2) { + var schedule2 = get$2(node2, id2); + if (schedule2.state > CREATED) + throw new Error("too late; already scheduled"); + return schedule2; + } + function set$2(node2, id2) { + var schedule2 = get$2(node2, id2); + if (schedule2.state > STARTED) + throw new Error("too late; already running"); + return schedule2; + } + function get$2(node2, id2) { + var schedule2 = node2.__transition; + if (!schedule2 || !(schedule2 = schedule2[id2])) + throw new Error("transition not found"); + return schedule2; + } + function create$1(node2, id2, self2) { + var schedules = node2.__transition, tween; + schedules[id2] = self2; + self2.timer = timer(schedule2, 0, self2.time); + function schedule2(elapsed) { + self2.state = SCHEDULED; + self2.timer.restart(start2, self2.delay, self2.time); + if (self2.delay <= elapsed) + start2(elapsed - self2.delay); + } + function start2(elapsed) { + var i2, j, n, o; + if (self2.state !== SCHEDULED) + return stop(); + for (i2 in schedules) { + o = schedules[i2]; + if (o.name !== self2.name) + continue; + if (o.state === STARTED) + return timeout(start2); + if (o.state === RUNNING) { + o.state = ENDED; + o.timer.stop(); + o.on.call("interrupt", node2, node2.__data__, o.index, o.group); + delete schedules[i2]; + } else if (+i2 < id2) { + o.state = ENDED; + o.timer.stop(); + o.on.call("cancel", node2, node2.__data__, o.index, o.group); + delete schedules[i2]; + } + } + timeout(function() { + if (self2.state === STARTED) { + self2.state = RUNNING; + self2.timer.restart(tick, self2.delay, self2.time); + tick(elapsed); + } + }); + self2.state = STARTING; + self2.on.call("start", node2, node2.__data__, self2.index, self2.group); + if (self2.state !== STARTING) + return; + self2.state = STARTED; + tween = new Array(n = self2.tween.length); + for (i2 = 0, j = -1; i2 < n; ++i2) { + if (o = self2.tween[i2].value.call(node2, node2.__data__, self2.index, self2.group)) { + tween[++j] = o; + } + } + tween.length = j + 1; + } + function tick(elapsed) { + var t = elapsed < self2.duration ? self2.ease.call(null, elapsed / self2.duration) : (self2.timer.restart(stop), self2.state = ENDING, 1), i2 = -1, n = tween.length; + while (++i2 < n) { + tween[i2].call(node2, t); + } + if (self2.state === ENDING) { + self2.on.call("end", node2, node2.__data__, self2.index, self2.group); + stop(); + } + } + function stop() { + self2.state = ENDED; + self2.timer.stop(); + delete schedules[id2]; + for (var i2 in schedules) + return; + delete node2.__transition; + } + } + function interrupt(node2, name2) { + var schedules = node2.__transition, schedule2, active, empty2 = true, i2; + if (!schedules) + return; + name2 = name2 == null ? null : name2 + ""; + for (i2 in schedules) { + if ((schedule2 = schedules[i2]).name !== name2) { + empty2 = false; + continue; + } + active = schedule2.state > STARTING && schedule2.state < ENDING; + schedule2.state = ENDED; + schedule2.timer.stop(); + schedule2.on.call(active ? "interrupt" : "cancel", node2, node2.__data__, schedule2.index, schedule2.group); + delete schedules[i2]; + } + if (empty2) + delete node2.__transition; + } + function selection_interrupt(name2) { + return this.each(function() { + interrupt(this, name2); + }); + } + function tweenRemove(id2, name2) { + var tween0, tween1; + return function() { + var schedule2 = set$2(this, id2), tween = schedule2.tween; + if (tween !== tween0) { + tween1 = tween0 = tween; + for (var i2 = 0, n = tween1.length; i2 < n; ++i2) { + if (tween1[i2].name === name2) { + tween1 = tween1.slice(); + tween1.splice(i2, 1); + break; + } + } + } + schedule2.tween = tween1; + }; + } + function tweenFunction(id2, name2, value) { + var tween0, tween1; + if (typeof value !== "function") + throw new Error(); + return function() { + var schedule2 = set$2(this, id2), tween = schedule2.tween; + if (tween !== tween0) { + tween1 = (tween0 = tween).slice(); + for (var t = { name: name2, value }, i2 = 0, n = tween1.length; i2 < n; ++i2) { + if (tween1[i2].name === name2) { + tween1[i2] = t; + break; + } + } + if (i2 === n) + tween1.push(t); + } + schedule2.tween = tween1; + }; + } + function transition_tween(name2, value) { + var id2 = this._id; + name2 += ""; + if (arguments.length < 2) { + var tween = get$2(this.node(), id2).tween; + for (var i2 = 0, n = tween.length, t; i2 < n; ++i2) { + if ((t = tween[i2]).name === name2) { + return t.value; + } + } + return null; + } + return this.each((value == null ? tweenRemove : tweenFunction)(id2, name2, value)); + } + function tweenValue(transition, name2, value) { + var id2 = transition._id; + transition.each(function() { + var schedule2 = set$2(this, id2); + (schedule2.value || (schedule2.value = {}))[name2] = value.apply(this, arguments); + }); + return function(node2) { + return get$2(node2, id2).value[name2]; + }; + } + function interpolate(a, b) { + var c2; + return (typeof b === "number" ? interpolateNumber : b instanceof color ? interpolateRgb : (c2 = color(b)) ? (b = c2, interpolateRgb) : interpolateString)(a, b); + } + function attrRemove(name2) { + return function() { + this.removeAttribute(name2); + }; + } + function attrRemoveNS(fullname) { + return function() { + this.removeAttributeNS(fullname.space, fullname.local); + }; + } + function attrConstant(name2, interpolate2, value1) { + var string00, string1 = value1 + "", interpolate0; + return function() { + var string0 = this.getAttribute(name2); + return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate2(string00 = string0, value1); + }; + } + function attrConstantNS(fullname, interpolate2, value1) { + var string00, string1 = value1 + "", interpolate0; + return function() { + var string0 = this.getAttributeNS(fullname.space, fullname.local); + return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate2(string00 = string0, value1); + }; + } + function attrFunction(name2, interpolate2, value) { + var string00, string10, interpolate0; + return function() { + var string0, value1 = value(this), string1; + if (value1 == null) + return void this.removeAttribute(name2); + string0 = this.getAttribute(name2); + string1 = value1 + ""; + return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate2(string00 = string0, value1)); + }; + } + function attrFunctionNS(fullname, interpolate2, value) { + var string00, string10, interpolate0; + return function() { + var string0, value1 = value(this), string1; + if (value1 == null) + return void this.removeAttributeNS(fullname.space, fullname.local); + string0 = this.getAttributeNS(fullname.space, fullname.local); + string1 = value1 + ""; + return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate2(string00 = string0, value1)); + }; + } + function transition_attr(name2, value) { + var fullname = namespace(name2), i2 = fullname === "transform" ? interpolateTransformSvg : interpolate; + return this.attrTween(name2, typeof value === "function" ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i2, tweenValue(this, "attr." + name2, value)) : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname) : (fullname.local ? attrConstantNS : attrConstant)(fullname, i2, value)); + } + function attrInterpolate(name2, i2) { + return function(t) { + this.setAttribute(name2, i2.call(this, t)); + }; + } + function attrInterpolateNS(fullname, i2) { + return function(t) { + this.setAttributeNS(fullname.space, fullname.local, i2.call(this, t)); + }; + } + function attrTweenNS(fullname, value) { + var t02, i0; + function tween() { + var i2 = value.apply(this, arguments); + if (i2 !== i0) + t02 = (i0 = i2) && attrInterpolateNS(fullname, i2); + return t02; + } + tween._value = value; + return tween; + } + function attrTween(name2, value) { + var t02, i0; + function tween() { + var i2 = value.apply(this, arguments); + if (i2 !== i0) + t02 = (i0 = i2) && attrInterpolate(name2, i2); + return t02; + } + tween._value = value; + return tween; + } + function transition_attrTween(name2, value) { + var key = "attr." + name2; + if (arguments.length < 2) + return (key = this.tween(key)) && key._value; + if (value == null) + return this.tween(key, null); + if (typeof value !== "function") + throw new Error(); + var fullname = namespace(name2); + return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value)); + } + function delayFunction(id2, value) { + return function() { + init$1(this, id2).delay = +value.apply(this, arguments); + }; + } + function delayConstant(id2, value) { + return value = +value, function() { + init$1(this, id2).delay = value; + }; + } + function transition_delay(value) { + var id2 = this._id; + return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id2, value)) : get$2(this.node(), id2).delay; + } + function durationFunction(id2, value) { + return function() { + set$2(this, id2).duration = +value.apply(this, arguments); + }; + } + function durationConstant(id2, value) { + return value = +value, function() { + set$2(this, id2).duration = value; + }; + } + function transition_duration(value) { + var id2 = this._id; + return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id2, value)) : get$2(this.node(), id2).duration; + } + function easeConstant(id2, value) { + if (typeof value !== "function") + throw new Error(); + return function() { + set$2(this, id2).ease = value; + }; + } + function transition_ease(value) { + var id2 = this._id; + return arguments.length ? this.each(easeConstant(id2, value)) : get$2(this.node(), id2).ease; + } + function easeVarying(id2, value) { + return function() { + var v = value.apply(this, arguments); + if (typeof v !== "function") + throw new Error(); + set$2(this, id2).ease = v; + }; + } + function transition_easeVarying(value) { + if (typeof value !== "function") + throw new Error(); + return this.each(easeVarying(this._id, value)); + } + function transition_filter(match) { + if (typeof match !== "function") + match = matcher(match); + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node2, i2 = 0; i2 < n; ++i2) { + if ((node2 = group[i2]) && match.call(node2, node2.__data__, i2, group)) { + subgroup.push(node2); + } + } + } + return new Transition(subgroups, this._parents, this._name, this._id); + } + function transition_merge(transition) { + if (transition._id !== this._id) + throw new Error(); + for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge2 = merges[j] = new Array(n), node2, i2 = 0; i2 < n; ++i2) { + if (node2 = group0[i2] || group1[i2]) { + merge2[i2] = node2; + } + } + } + for (; j < m0; ++j) { + merges[j] = groups0[j]; + } + return new Transition(merges, this._parents, this._name, this._id); + } + function start$1(name2) { + return (name2 + "").trim().split(/^|\s+/).every(function(t) { + var i2 = t.indexOf("."); + if (i2 >= 0) + t = t.slice(0, i2); + return !t || t === "start"; + }); + } + function onFunction(id2, name2, listener) { + var on0, on1, sit = start$1(name2) ? init$1 : set$2; + return function() { + var schedule2 = sit(this, id2), on = schedule2.on; + if (on !== on0) + (on1 = (on0 = on).copy()).on(name2, listener); + schedule2.on = on1; + }; + } + function transition_on(name2, listener) { + var id2 = this._id; + return arguments.length < 2 ? get$2(this.node(), id2).on.on(name2) : this.each(onFunction(id2, name2, listener)); + } + function removeFunction(id2) { + return function() { + var parent = this.parentNode; + for (var i2 in this.__transition) + if (+i2 !== id2) + return; + if (parent) + parent.removeChild(this); + }; + } + function transition_remove() { + return this.on("end.remove", removeFunction(this._id)); + } + function transition_select(select2) { + var name2 = this._name, id2 = this._id; + if (typeof select2 !== "function") + select2 = selector(select2); + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node2, subnode, i2 = 0; i2 < n; ++i2) { + if ((node2 = group[i2]) && (subnode = select2.call(node2, node2.__data__, i2, group))) { + if ("__data__" in node2) + subnode.__data__ = node2.__data__; + subgroup[i2] = subnode; + schedule(subgroup[i2], name2, id2, i2, subgroup, get$2(node2, id2)); + } + } + } + return new Transition(subgroups, this._parents, name2, id2); + } + function transition_selectAll(select2) { + var name2 = this._name, id2 = this._id; + if (typeof select2 !== "function") + select2 = selectorAll(select2); + for (var groups = this._groups, m = groups.length, subgroups = [], parents2 = [], j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node2, i2 = 0; i2 < n; ++i2) { + if (node2 = group[i2]) { + for (var children2 = select2.call(node2, node2.__data__, i2, group), child, inherit2 = get$2(node2, id2), k = 0, l = children2.length; k < l; ++k) { + if (child = children2[k]) { + schedule(child, name2, id2, k, children2, inherit2); + } + } + subgroups.push(children2); + parents2.push(node2); + } + } + } + return new Transition(subgroups, parents2, name2, id2); + } + var Selection = selection.prototype.constructor; + function transition_selection() { + return new Selection(this._groups, this._parents); + } + function styleNull(name2, interpolate2) { + var string00, string10, interpolate0; + return function() { + var string0 = styleValue(this, name2), string1 = (this.style.removeProperty(name2), styleValue(this, name2)); + return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate2(string00 = string0, string10 = string1); + }; + } + function styleRemove(name2) { + return function() { + this.style.removeProperty(name2); + }; + } + function styleConstant(name2, interpolate2, value1) { + var string00, string1 = value1 + "", interpolate0; + return function() { + var string0 = styleValue(this, name2); + return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate2(string00 = string0, value1); + }; + } + function styleFunction(name2, interpolate2, value) { + var string00, string10, interpolate0; + return function() { + var string0 = styleValue(this, name2), value1 = value(this), string1 = value1 + ""; + if (value1 == null) + string1 = value1 = (this.style.removeProperty(name2), styleValue(this, name2)); + return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate2(string00 = string0, value1)); + }; + } + function styleMaybeRemove(id2, name2) { + var on0, on1, listener0, key = "style." + name2, event = "end." + key, remove2; + return function() { + var schedule2 = set$2(this, id2), on = schedule2.on, listener = schedule2.value[key] == null ? remove2 || (remove2 = styleRemove(name2)) : void 0; + if (on !== on0 || listener0 !== listener) + (on1 = (on0 = on).copy()).on(event, listener0 = listener); + schedule2.on = on1; + }; + } + function transition_style(name2, value, priority) { + var i2 = (name2 += "") === "transform" ? interpolateTransformCss : interpolate; + return value == null ? this.styleTween(name2, styleNull(name2, i2)).on("end.style." + name2, styleRemove(name2)) : typeof value === "function" ? this.styleTween(name2, styleFunction(name2, i2, tweenValue(this, "style." + name2, value))).each(styleMaybeRemove(this._id, name2)) : this.styleTween(name2, styleConstant(name2, i2, value), priority).on("end.style." + name2, null); + } + function styleInterpolate(name2, i2, priority) { + return function(t) { + this.style.setProperty(name2, i2.call(this, t), priority); + }; + } + function styleTween(name2, value, priority) { + var t, i0; + function tween() { + var i2 = value.apply(this, arguments); + if (i2 !== i0) + t = (i0 = i2) && styleInterpolate(name2, i2, priority); + return t; + } + tween._value = value; + return tween; + } + function transition_styleTween(name2, value, priority) { + var key = "style." + (name2 += ""); + if (arguments.length < 2) + return (key = this.tween(key)) && key._value; + if (value == null) + return this.tween(key, null); + if (typeof value !== "function") + throw new Error(); + return this.tween(key, styleTween(name2, value, priority == null ? "" : priority)); + } + function textConstant(value) { + return function() { + this.textContent = value; + }; + } + function textFunction(value) { + return function() { + var value1 = value(this); + this.textContent = value1 == null ? "" : value1; + }; + } + function transition_text(value) { + return this.tween("text", typeof value === "function" ? textFunction(tweenValue(this, "text", value)) : textConstant(value == null ? "" : value + "")); + } + function textInterpolate(i2) { + return function(t) { + this.textContent = i2.call(this, t); + }; + } + function textTween(value) { + var t02, i0; + function tween() { + var i2 = value.apply(this, arguments); + if (i2 !== i0) + t02 = (i0 = i2) && textInterpolate(i2); + return t02; + } + tween._value = value; + return tween; + } + function transition_textTween(value) { + var key = "text"; + if (arguments.length < 1) + return (key = this.tween(key)) && key._value; + if (value == null) + return this.tween(key, null); + if (typeof value !== "function") + throw new Error(); + return this.tween(key, textTween(value)); + } + function transition_transition() { + var name2 = this._name, id0 = this._id, id1 = newId(); + for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node2, i2 = 0; i2 < n; ++i2) { + if (node2 = group[i2]) { + var inherit2 = get$2(node2, id0); + schedule(node2, name2, id1, i2, group, { + time: inherit2.time + inherit2.delay + inherit2.duration, + delay: 0, + duration: inherit2.duration, + ease: inherit2.ease + }); + } + } + } + return new Transition(groups, this._parents, name2, id1); + } + function transition_end() { + var on0, on1, that = this, id2 = that._id, size2 = that.size(); + return new Promise(function(resolve, reject) { + var cancel = { value: reject }, end2 = { value: function() { + if (--size2 === 0) + resolve(); + } }; + that.each(function() { + var schedule2 = set$2(this, id2), on = schedule2.on; + if (on !== on0) { + on1 = (on0 = on).copy(); + on1._.cancel.push(cancel); + on1._.interrupt.push(cancel); + on1._.end.push(end2); + } + schedule2.on = on1; + }); + if (size2 === 0) + resolve(); + }); + } + var id = 0; + function Transition(groups, parents2, name2, id2) { + this._groups = groups; + this._parents = parents2; + this._name = name2; + this._id = id2; + } + function newId() { + return ++id; + } + var selection_prototype = selection.prototype; + Transition.prototype = { + constructor: Transition, + select: transition_select, + selectAll: transition_selectAll, + selectChild: selection_prototype.selectChild, + selectChildren: selection_prototype.selectChildren, + filter: transition_filter, + merge: transition_merge, + selection: transition_selection, + transition: transition_transition, + call: selection_prototype.call, + nodes: selection_prototype.nodes, + node: selection_prototype.node, + size: selection_prototype.size, + empty: selection_prototype.empty, + each: selection_prototype.each, + on: transition_on, + attr: transition_attr, + attrTween: transition_attrTween, + style: transition_style, + styleTween: transition_styleTween, + text: transition_text, + textTween: transition_textTween, + remove: transition_remove, + tween: transition_tween, + delay: transition_delay, + duration: transition_duration, + ease: transition_ease, + easeVarying: transition_easeVarying, + end: transition_end, + [Symbol.iterator]: selection_prototype[Symbol.iterator] + }; + function cubicInOut(t) { + return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2; + } + var defaultTiming = { + time: null, + delay: 0, + duration: 250, + ease: cubicInOut + }; + function inherit(node2, id2) { + var timing; + while (!(timing = node2.__transition) || !(timing = timing[id2])) { + if (!(node2 = node2.parentNode)) { + throw new Error(`transition ${id2} not found`); + } + } + return timing; + } + function selection_transition(name2) { + var id2, timing; + if (name2 instanceof Transition) { + id2 = name2._id, name2 = name2._name; + } else { + id2 = newId(), (timing = defaultTiming).time = now$2(), name2 = name2 == null ? null : name2 + ""; + } + for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node2, i2 = 0; i2 < n; ++i2) { + if (node2 = group[i2]) { + schedule(node2, name2, id2, i2, group, timing || inherit(node2, id2)); + } + } + } + return new Transition(groups, this._parents, name2, id2); + } + selection.prototype.interrupt = selection_interrupt; + selection.prototype.transition = selection_transition; + const pi$1 = Math.PI, tau$1 = 2 * pi$1, epsilon$1 = 1e-6, tauEpsilon = tau$1 - epsilon$1; + function Path() { + this._x0 = this._y0 = this._x1 = this._y1 = null; + this._ = ""; + } + function path() { + return new Path(); + } + Path.prototype = path.prototype = { + constructor: Path, + moveTo: function(x2, y2) { + this._ += "M" + (this._x0 = this._x1 = +x2) + "," + (this._y0 = this._y1 = +y2); + }, + closePath: function() { + if (this._x1 !== null) { + this._x1 = this._x0, this._y1 = this._y0; + this._ += "Z"; + } + }, + lineTo: function(x2, y2) { + this._ += "L" + (this._x1 = +x2) + "," + (this._y1 = +y2); + }, + quadraticCurveTo: function(x1, y1, x2, y2) { + this._ += "Q" + +x1 + "," + +y1 + "," + (this._x1 = +x2) + "," + (this._y1 = +y2); + }, + bezierCurveTo: function(x1, y1, x2, y2, x3, y3) { + this._ += "C" + +x1 + "," + +y1 + "," + +x2 + "," + +y2 + "," + (this._x1 = +x3) + "," + (this._y1 = +y3); + }, + arcTo: function(x1, y1, x2, y2, r) { + x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r; + var x0 = this._x1, y0 = this._y1, x21 = x2 - x1, y21 = y2 - y1, x01 = x0 - x1, y01 = y0 - y1, l01_2 = x01 * x01 + y01 * y01; + if (r < 0) + throw new Error("negative radius: " + r); + if (this._x1 === null) { + this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1); + } else if (!(l01_2 > epsilon$1)) + ; + else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$1) || !r) { + this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1); + } else { + var x20 = x2 - x0, y20 = y2 - y0, l21_2 = x21 * x21 + y21 * y21, l20_2 = x20 * x20 + y20 * y20, l21 = Math.sqrt(l21_2), l01 = Math.sqrt(l01_2), l = r * Math.tan((pi$1 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2), t01 = l / l01, t21 = l / l21; + if (Math.abs(t01 - 1) > epsilon$1) { + this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01); + } + this._ += "A" + r + "," + r + ",0,0," + +(y01 * x20 > x01 * y20) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21); + } + }, + arc: function(x2, y2, r, a0, a1, ccw) { + x2 = +x2, y2 = +y2, r = +r, ccw = !!ccw; + var dx = r * Math.cos(a0), dy = r * Math.sin(a0), x0 = x2 + dx, y0 = y2 + dy, cw = 1 ^ ccw, da = ccw ? a0 - a1 : a1 - a0; + if (r < 0) + throw new Error("negative radius: " + r); + if (this._x1 === null) { + this._ += "M" + x0 + "," + y0; + } else if (Math.abs(this._x1 - x0) > epsilon$1 || Math.abs(this._y1 - y0) > epsilon$1) { + this._ += "L" + x0 + "," + y0; + } + if (!r) + return; + if (da < 0) + da = da % tau$1 + tau$1; + if (da > tauEpsilon) { + this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x2 - dx) + "," + (y2 - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0); + } else if (da > epsilon$1) { + this._ += "A" + r + "," + r + ",0," + +(da >= pi$1) + "," + cw + "," + (this._x1 = x2 + r * Math.cos(a1)) + "," + (this._y1 = y2 + r * Math.sin(a1)); + } + }, + rect: function(x2, y2, w2, h) { + this._ += "M" + (this._x0 = this._x1 = +x2) + "," + (this._y0 = this._y1 = +y2) + "h" + +w2 + "v" + +h + "h" + -w2 + "Z"; + }, + toString: function() { + return this._; + } + }; + function responseText(response) { + if (!response.ok) + throw new Error(response.status + " " + response.statusText); + return response.text(); + } + function text$1(input, init2) { + return fetch(input, init2).then(responseText); + } + function parser$c(type2) { + return (input, init2) => text$1(input, init2).then((text2) => new DOMParser().parseFromString(text2, type2)); + } + var svg$2 = parser$c("image/svg+xml"); + function formatDecimal(x2) { + return Math.abs(x2 = Math.round(x2)) >= 1e21 ? x2.toLocaleString("en").replace(/,/g, "") : x2.toString(10); + } + function formatDecimalParts(x2, p) { + if ((i2 = (x2 = p ? x2.toExponential(p - 1) : x2.toExponential()).indexOf("e")) < 0) + return null; + var i2, coefficient = x2.slice(0, i2); + return [ + coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, + +x2.slice(i2 + 1) + ]; + } + function exponent(x2) { + return x2 = formatDecimalParts(Math.abs(x2)), x2 ? x2[1] : NaN; + } + function formatGroup(grouping, thousands) { + return function(value, width2) { + var i2 = value.length, t = [], j = 0, g = grouping[0], length2 = 0; + while (i2 > 0 && g > 0) { + if (length2 + g + 1 > width2) + g = Math.max(1, width2 - length2); + t.push(value.substring(i2 -= g, i2 + g)); + if ((length2 += g + 1) > width2) + break; + g = grouping[j = (j + 1) % grouping.length]; + } + return t.reverse().join(thousands); + }; + } + function formatNumerals(numerals) { + return function(value) { + return value.replace(/[0-9]/g, function(i2) { + return numerals[+i2]; + }); + }; + } + var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i; + function formatSpecifier(specifier) { + if (!(match = re.exec(specifier))) + throw new Error("invalid format: " + specifier); + var match; + return new FormatSpecifier({ + fill: match[1], + align: match[2], + sign: match[3], + symbol: match[4], + zero: match[5], + width: match[6], + comma: match[7], + precision: match[8] && match[8].slice(1), + trim: match[9], + type: match[10] + }); + } + formatSpecifier.prototype = FormatSpecifier.prototype; + function FormatSpecifier(specifier) { + this.fill = specifier.fill === void 0 ? " " : specifier.fill + ""; + this.align = specifier.align === void 0 ? ">" : specifier.align + ""; + this.sign = specifier.sign === void 0 ? "-" : specifier.sign + ""; + this.symbol = specifier.symbol === void 0 ? "" : specifier.symbol + ""; + this.zero = !!specifier.zero; + this.width = specifier.width === void 0 ? void 0 : +specifier.width; + this.comma = !!specifier.comma; + this.precision = specifier.precision === void 0 ? void 0 : +specifier.precision; + this.trim = !!specifier.trim; + this.type = specifier.type === void 0 ? "" : specifier.type + ""; + } + FormatSpecifier.prototype.toString = function() { + return this.fill + this.align + this.sign + this.symbol + (this.zero ? "0" : "") + (this.width === void 0 ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") + (this.precision === void 0 ? "" : "." + Math.max(0, this.precision | 0)) + (this.trim ? "~" : "") + this.type; + }; + function formatTrim(s) { + out: + for (var n = s.length, i2 = 1, i0 = -1, i1; i2 < n; ++i2) { + switch (s[i2]) { + case ".": + i0 = i1 = i2; + break; + case "0": + if (i0 === 0) + i0 = i2; + i1 = i2; + break; + default: + if (!+s[i2]) + break out; + if (i0 > 0) + i0 = 0; + break; + } + } + return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s; + } + var prefixExponent; + function formatPrefixAuto(x2, p) { + var d = formatDecimalParts(x2, p); + if (!d) + return x2 + ""; + var coefficient = d[0], exponent2 = d[1], i2 = exponent2 - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent2 / 3))) * 3) + 1, n = coefficient.length; + return i2 === n ? coefficient : i2 > n ? coefficient + new Array(i2 - n + 1).join("0") : i2 > 0 ? coefficient.slice(0, i2) + "." + coefficient.slice(i2) : "0." + new Array(1 - i2).join("0") + formatDecimalParts(x2, Math.max(0, p + i2 - 1))[0]; + } + function formatRounded(x2, p) { + var d = formatDecimalParts(x2, p); + if (!d) + return x2 + ""; + var coefficient = d[0], exponent2 = d[1]; + return exponent2 < 0 ? "0." + new Array(-exponent2).join("0") + coefficient : coefficient.length > exponent2 + 1 ? coefficient.slice(0, exponent2 + 1) + "." + coefficient.slice(exponent2 + 1) : coefficient + new Array(exponent2 - coefficient.length + 2).join("0"); + } + const formatTypes = { + "%": (x2, p) => (x2 * 100).toFixed(p), + "b": (x2) => Math.round(x2).toString(2), + "c": (x2) => x2 + "", + "d": formatDecimal, + "e": (x2, p) => x2.toExponential(p), + "f": (x2, p) => x2.toFixed(p), + "g": (x2, p) => x2.toPrecision(p), + "o": (x2) => Math.round(x2).toString(8), + "p": (x2, p) => formatRounded(x2 * 100, p), + "r": formatRounded, + "s": formatPrefixAuto, + "X": (x2) => Math.round(x2).toString(16).toUpperCase(), + "x": (x2) => Math.round(x2).toString(16) + }; + function identity$3(x2) { + return x2; + } + var map$2 = Array.prototype.map, prefixes = ["y", "z", "a", "f", "p", "n", "\xB5", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"]; + function formatLocale$1(locale2) { + var group = locale2.grouping === void 0 || locale2.thousands === void 0 ? identity$3 : formatGroup(map$2.call(locale2.grouping, Number), locale2.thousands + ""), currencyPrefix = locale2.currency === void 0 ? "" : locale2.currency[0] + "", currencySuffix = locale2.currency === void 0 ? "" : locale2.currency[1] + "", decimal = locale2.decimal === void 0 ? "." : locale2.decimal + "", numerals = locale2.numerals === void 0 ? identity$3 : formatNumerals(map$2.call(locale2.numerals, String)), percent = locale2.percent === void 0 ? "%" : locale2.percent + "", minus = locale2.minus === void 0 ? "\u2212" : locale2.minus + "", nan = locale2.nan === void 0 ? "NaN" : locale2.nan + ""; + function newFormat(specifier) { + specifier = formatSpecifier(specifier); + var fill = specifier.fill, align = specifier.align, sign2 = specifier.sign, symbol = specifier.symbol, zero2 = specifier.zero, width2 = specifier.width, comma = specifier.comma, precision = specifier.precision, trim2 = specifier.trim, type2 = specifier.type; + if (type2 === "n") + comma = true, type2 = "g"; + else if (!formatTypes[type2]) + precision === void 0 && (precision = 12), trim2 = true, type2 = "g"; + if (zero2 || fill === "0" && align === "=") + zero2 = true, fill = "0", align = "="; + var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type2) ? "0" + type2.toLowerCase() : "", suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type2) ? percent : ""; + var formatType = formatTypes[type2], maybeSuffix = /[defgprs%]/.test(type2); + precision = precision === void 0 ? 6 : /[gprs]/.test(type2) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision)); + function format2(value) { + var valuePrefix = prefix, valueSuffix = suffix, i2, n, c2; + if (type2 === "c") { + valueSuffix = formatType(value) + valueSuffix; + value = ""; + } else { + value = +value; + var valueNegative = value < 0 || 1 / value < 0; + value = isNaN(value) ? nan : formatType(Math.abs(value), precision); + if (trim2) + value = formatTrim(value); + if (valueNegative && +value === 0 && sign2 !== "+") + valueNegative = false; + valuePrefix = (valueNegative ? sign2 === "(" ? sign2 : minus : sign2 === "-" || sign2 === "(" ? "" : sign2) + valuePrefix; + valueSuffix = (type2 === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign2 === "(" ? ")" : ""); + if (maybeSuffix) { + i2 = -1, n = value.length; + while (++i2 < n) { + if (c2 = value.charCodeAt(i2), 48 > c2 || c2 > 57) { + valueSuffix = (c2 === 46 ? decimal + value.slice(i2 + 1) : value.slice(i2)) + valueSuffix; + value = value.slice(0, i2); + break; + } + } + } + } + if (comma && !zero2) + value = group(value, Infinity); + var length2 = valuePrefix.length + value.length + valueSuffix.length, padding2 = length2 < width2 ? new Array(width2 - length2 + 1).join(fill) : ""; + if (comma && zero2) + value = group(padding2 + value, padding2.length ? width2 - valueSuffix.length : Infinity), padding2 = ""; + switch (align) { + case "<": + value = valuePrefix + value + valueSuffix + padding2; + break; + case "=": + value = valuePrefix + padding2 + value + valueSuffix; + break; + case "^": + value = padding2.slice(0, length2 = padding2.length >> 1) + valuePrefix + value + valueSuffix + padding2.slice(length2); + break; + default: + value = padding2 + valuePrefix + value + valueSuffix; + break; + } + return numerals(value); + } + format2.toString = function() { + return specifier + ""; + }; + return format2; + } + function formatPrefix2(specifier, value) { + var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)), e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3, k = Math.pow(10, -e), prefix = prefixes[8 + e / 3]; + return function(value2) { + return f(k * value2) + prefix; + }; + } + return { + format: newFormat, + formatPrefix: formatPrefix2 + }; + } + var locale$1; + var format; + var formatPrefix; + defaultLocale$1({ + thousands: ",", + grouping: [3], + currency: ["$", ""] + }); + function defaultLocale$1(definition) { + locale$1 = formatLocale$1(definition); + format = locale$1.format; + formatPrefix = locale$1.formatPrefix; + return locale$1; + } + function precisionFixed(step) { + return Math.max(0, -exponent(Math.abs(step))); + } + function precisionPrefix(step, value) { + return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step))); + } + function precisionRound(step, max2) { + step = Math.abs(step), max2 = Math.abs(max2) - step; + return Math.max(0, exponent(max2) - exponent(step)) + 1; + } + function initRange(domain, range2) { + switch (arguments.length) { + case 0: + break; + case 1: + this.range(domain); + break; + default: + this.range(range2).domain(domain); + break; + } + return this; + } + const implicit = Symbol("implicit"); + function ordinal() { + var index = new InternMap(), domain = [], range2 = [], unknown = implicit; + function scale(d) { + let i2 = index.get(d); + if (i2 === void 0) { + if (unknown !== implicit) + return unknown; + index.set(d, i2 = domain.push(d) - 1); + } + return range2[i2 % range2.length]; + } + scale.domain = function(_2) { + if (!arguments.length) + return domain.slice(); + domain = [], index = new InternMap(); + for (const value of _2) { + if (index.has(value)) + continue; + index.set(value, domain.push(value) - 1); + } + return scale; + }; + scale.range = function(_2) { + return arguments.length ? (range2 = Array.from(_2), scale) : range2.slice(); + }; + scale.unknown = function(_2) { + return arguments.length ? (unknown = _2, scale) : unknown; + }; + scale.copy = function() { + return ordinal(domain, range2).unknown(unknown); + }; + initRange.apply(scale, arguments); + return scale; + } + function constants(x2) { + return function() { + return x2; + }; + } + function number$1(x2) { + return +x2; + } + var unit$1 = [0, 1]; + function identity$2(x2) { + return x2; + } + function normalize(a, b) { + return (b -= a = +a) ? function(x2) { + return (x2 - a) / b; + } : constants(isNaN(b) ? NaN : 0.5); + } + function clamper(a, b) { + var t; + if (a > b) + t = a, a = b, b = t; + return function(x2) { + return Math.max(a, Math.min(b, x2)); + }; + } + function bimap(domain, range2, interpolate2) { + var d0 = domain[0], d1 = domain[1], r0 = range2[0], r1 = range2[1]; + if (d1 < d0) + d0 = normalize(d1, d0), r0 = interpolate2(r1, r0); + else + d0 = normalize(d0, d1), r0 = interpolate2(r0, r1); + return function(x2) { + return r0(d0(x2)); + }; + } + function polymap(domain, range2, interpolate2) { + var j = Math.min(domain.length, range2.length) - 1, d = new Array(j), r = new Array(j), i2 = -1; + if (domain[j] < domain[0]) { + domain = domain.slice().reverse(); + range2 = range2.slice().reverse(); + } + while (++i2 < j) { + d[i2] = normalize(domain[i2], domain[i2 + 1]); + r[i2] = interpolate2(range2[i2], range2[i2 + 1]); + } + return function(x2) { + var i3 = bisect(domain, x2, 1, j) - 1; + return r[i3](d[i3](x2)); + }; + } + function copy$1(source, target) { + return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown()); + } + function transformer() { + var domain = unit$1, range2 = unit$1, interpolate2 = interpolate$1, transform, untransform, unknown, clamp = identity$2, piecewise, output, input; + function rescale() { + var n = Math.min(domain.length, range2.length); + if (clamp !== identity$2) + clamp = clamper(domain[0], domain[n - 1]); + piecewise = n > 2 ? polymap : bimap; + output = input = null; + return scale; + } + function scale(x2) { + return x2 == null || isNaN(x2 = +x2) ? unknown : (output || (output = piecewise(domain.map(transform), range2, interpolate2)))(transform(clamp(x2))); + } + scale.invert = function(y2) { + return clamp(untransform((input || (input = piecewise(range2, domain.map(transform), interpolateNumber)))(y2))); + }; + scale.domain = function(_2) { + return arguments.length ? (domain = Array.from(_2, number$1), rescale()) : domain.slice(); + }; + scale.range = function(_2) { + return arguments.length ? (range2 = Array.from(_2), rescale()) : range2.slice(); + }; + scale.rangeRound = function(_2) { + return range2 = Array.from(_2), interpolate2 = interpolateRound, rescale(); + }; + scale.clamp = function(_2) { + return arguments.length ? (clamp = _2 ? true : identity$2, rescale()) : clamp !== identity$2; + }; + scale.interpolate = function(_2) { + return arguments.length ? (interpolate2 = _2, rescale()) : interpolate2; + }; + scale.unknown = function(_2) { + return arguments.length ? (unknown = _2, scale) : unknown; + }; + return function(t, u) { + transform = t, untransform = u; + return rescale(); + }; + } + function continuous() { + return transformer()(identity$2, identity$2); + } + function tickFormat(start2, stop, count, specifier) { + var step = tickStep(start2, stop, count), precision; + specifier = formatSpecifier(specifier == null ? ",f" : specifier); + switch (specifier.type) { + case "s": { + var value = Math.max(Math.abs(start2), Math.abs(stop)); + if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) + specifier.precision = precision; + return formatPrefix(specifier, value); + } + case "": + case "e": + case "g": + case "p": + case "r": { + if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start2), Math.abs(stop))))) + specifier.precision = precision - (specifier.type === "e"); + break; + } + case "f": + case "%": { + if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) + specifier.precision = precision - (specifier.type === "%") * 2; + break; + } + } + return format(specifier); + } + function linearish(scale) { + var domain = scale.domain; + scale.ticks = function(count) { + var d = domain(); + return ticks(d[0], d[d.length - 1], count == null ? 10 : count); + }; + scale.tickFormat = function(count, specifier) { + var d = domain(); + return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier); + }; + scale.nice = function(count) { + if (count == null) + count = 10; + var d = domain(); + var i0 = 0; + var i1 = d.length - 1; + var start2 = d[i0]; + var stop = d[i1]; + var prestep; + var step; + var maxIter = 10; + if (stop < start2) { + step = start2, start2 = stop, stop = step; + step = i0, i0 = i1, i1 = step; + } + while (maxIter-- > 0) { + step = tickIncrement(start2, stop, count); + if (step === prestep) { + d[i0] = start2; + d[i1] = stop; + return domain(d); + } else if (step > 0) { + start2 = Math.floor(start2 / step) * step; + stop = Math.ceil(stop / step) * step; + } else if (step < 0) { + start2 = Math.ceil(start2 * step) / step; + stop = Math.floor(stop * step) / step; + } else { + break; + } + prestep = step; + } + return scale; + }; + return scale; + } + function linear() { + var scale = continuous(); + scale.copy = function() { + return copy$1(scale, linear()); + }; + initRange.apply(scale, arguments); + return linearish(scale); + } + function nice(domain, interval2) { + domain = domain.slice(); + var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], t; + if (x1 < x0) { + t = i0, i0 = i1, i1 = t; + t = x0, x0 = x1, x1 = t; + } + domain[i0] = interval2.floor(x0); + domain[i1] = interval2.ceil(x1); + return domain; + } + var t0 = new Date(), t1 = new Date(); + function newInterval(floori, offseti, count, field) { + function interval2(date2) { + return floori(date2 = arguments.length === 0 ? new Date() : new Date(+date2)), date2; + } + interval2.floor = function(date2) { + return floori(date2 = new Date(+date2)), date2; + }; + interval2.ceil = function(date2) { + return floori(date2 = new Date(date2 - 1)), offseti(date2, 1), floori(date2), date2; + }; + interval2.round = function(date2) { + var d0 = interval2(date2), d1 = interval2.ceil(date2); + return date2 - d0 < d1 - date2 ? d0 : d1; + }; + interval2.offset = function(date2, step) { + return offseti(date2 = new Date(+date2), step == null ? 1 : Math.floor(step)), date2; + }; + interval2.range = function(start2, stop, step) { + var range2 = [], previous; + start2 = interval2.ceil(start2); + step = step == null ? 1 : Math.floor(step); + if (!(start2 < stop) || !(step > 0)) + return range2; + do + range2.push(previous = new Date(+start2)), offseti(start2, step), floori(start2); + while (previous < start2 && start2 < stop); + return range2; + }; + interval2.filter = function(test) { + return newInterval(function(date2) { + if (date2 >= date2) + while (floori(date2), !test(date2)) + date2.setTime(date2 - 1); + }, function(date2, step) { + if (date2 >= date2) { + if (step < 0) + while (++step <= 0) { + while (offseti(date2, -1), !test(date2)) { + } + } + else + while (--step >= 0) { + while (offseti(date2, 1), !test(date2)) { + } + } + } + }); + }; + if (count) { + interval2.count = function(start2, end2) { + t0.setTime(+start2), t1.setTime(+end2); + floori(t0), floori(t1); + return Math.floor(count(t0, t1)); + }; + interval2.every = function(step) { + step = Math.floor(step); + return !isFinite(step) || !(step > 0) ? null : !(step > 1) ? interval2 : interval2.filter(field ? function(d) { + return field(d) % step === 0; + } : function(d) { + return interval2.count(0, d) % step === 0; + }); + }; + } + return interval2; + } + var millisecond = newInterval(function() { + }, function(date2, step) { + date2.setTime(+date2 + step); + }, function(start2, end2) { + return end2 - start2; + }); + millisecond.every = function(k) { + k = Math.floor(k); + if (!isFinite(k) || !(k > 0)) + return null; + if (!(k > 1)) + return millisecond; + return newInterval(function(date2) { + date2.setTime(Math.floor(date2 / k) * k); + }, function(date2, step) { + date2.setTime(+date2 + step * k); + }, function(start2, end2) { + return (end2 - start2) / k; + }); + }; + const millisecond$1 = millisecond; + millisecond.range; + const durationSecond = 1e3; + const durationMinute = durationSecond * 60; + const durationHour = durationMinute * 60; + const durationDay = durationHour * 24; + const durationWeek = durationDay * 7; + const durationMonth = durationDay * 30; + const durationYear = durationDay * 365; + var second = newInterval(function(date2) { + date2.setTime(date2 - date2.getMilliseconds()); + }, function(date2, step) { + date2.setTime(+date2 + step * durationSecond); + }, function(start2, end2) { + return (end2 - start2) / durationSecond; + }, function(date2) { + return date2.getUTCSeconds(); + }); + const utcSecond = second; + second.range; + var minute = newInterval(function(date2) { + date2.setTime(date2 - date2.getMilliseconds() - date2.getSeconds() * durationSecond); + }, function(date2, step) { + date2.setTime(+date2 + step * durationMinute); + }, function(start2, end2) { + return (end2 - start2) / durationMinute; + }, function(date2) { + return date2.getMinutes(); + }); + const timeMinute = minute; + minute.range; + var hour = newInterval(function(date2) { + date2.setTime(date2 - date2.getMilliseconds() - date2.getSeconds() * durationSecond - date2.getMinutes() * durationMinute); + }, function(date2, step) { + date2.setTime(+date2 + step * durationHour); + }, function(start2, end2) { + return (end2 - start2) / durationHour; + }, function(date2) { + return date2.getHours(); + }); + const timeHour = hour; + hour.range; + var day = newInterval( + (date2) => date2.setHours(0, 0, 0, 0), + (date2, step) => date2.setDate(date2.getDate() + step), + (start2, end2) => (end2 - start2 - (end2.getTimezoneOffset() - start2.getTimezoneOffset()) * durationMinute) / durationDay, + (date2) => date2.getDate() - 1 + ); + const timeDay = day; + day.range; + function weekday(i2) { + return newInterval(function(date2) { + date2.setDate(date2.getDate() - (date2.getDay() + 7 - i2) % 7); + date2.setHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setDate(date2.getDate() + step * 7); + }, function(start2, end2) { + return (end2 - start2 - (end2.getTimezoneOffset() - start2.getTimezoneOffset()) * durationMinute) / durationWeek; + }); + } + var sunday = weekday(0); + var monday = weekday(1); + var tuesday = weekday(2); + var wednesday = weekday(3); + var thursday = weekday(4); + var friday = weekday(5); + var saturday = weekday(6); + sunday.range; + monday.range; + tuesday.range; + wednesday.range; + thursday.range; + friday.range; + saturday.range; + var month = newInterval(function(date2) { + date2.setDate(1); + date2.setHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setMonth(date2.getMonth() + step); + }, function(start2, end2) { + return end2.getMonth() - start2.getMonth() + (end2.getFullYear() - start2.getFullYear()) * 12; + }, function(date2) { + return date2.getMonth(); + }); + const timeMonth = month; + month.range; + var year = newInterval(function(date2) { + date2.setMonth(0, 1); + date2.setHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setFullYear(date2.getFullYear() + step); + }, function(start2, end2) { + return end2.getFullYear() - start2.getFullYear(); + }, function(date2) { + return date2.getFullYear(); + }); + year.every = function(k) { + return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date2) { + date2.setFullYear(Math.floor(date2.getFullYear() / k) * k); + date2.setMonth(0, 1); + date2.setHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setFullYear(date2.getFullYear() + step * k); + }); + }; + const timeYear = year; + year.range; + var utcMinute = newInterval(function(date2) { + date2.setUTCSeconds(0, 0); + }, function(date2, step) { + date2.setTime(+date2 + step * durationMinute); + }, function(start2, end2) { + return (end2 - start2) / durationMinute; + }, function(date2) { + return date2.getUTCMinutes(); + }); + const utcMinute$1 = utcMinute; + utcMinute.range; + var utcHour = newInterval(function(date2) { + date2.setUTCMinutes(0, 0, 0); + }, function(date2, step) { + date2.setTime(+date2 + step * durationHour); + }, function(start2, end2) { + return (end2 - start2) / durationHour; + }, function(date2) { + return date2.getUTCHours(); + }); + const utcHour$1 = utcHour; + utcHour.range; + var utcDay = newInterval(function(date2) { + date2.setUTCHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setUTCDate(date2.getUTCDate() + step); + }, function(start2, end2) { + return (end2 - start2) / durationDay; + }, function(date2) { + return date2.getUTCDate() - 1; + }); + const utcDay$1 = utcDay; + utcDay.range; + function utcWeekday(i2) { + return newInterval(function(date2) { + date2.setUTCDate(date2.getUTCDate() - (date2.getUTCDay() + 7 - i2) % 7); + date2.setUTCHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setUTCDate(date2.getUTCDate() + step * 7); + }, function(start2, end2) { + return (end2 - start2) / durationWeek; + }); + } + var utcSunday = utcWeekday(0); + var utcMonday = utcWeekday(1); + var utcTuesday = utcWeekday(2); + var utcWednesday = utcWeekday(3); + var utcThursday = utcWeekday(4); + var utcFriday = utcWeekday(5); + var utcSaturday = utcWeekday(6); + utcSunday.range; + utcMonday.range; + utcTuesday.range; + utcWednesday.range; + utcThursday.range; + utcFriday.range; + utcSaturday.range; + var utcMonth = newInterval(function(date2) { + date2.setUTCDate(1); + date2.setUTCHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setUTCMonth(date2.getUTCMonth() + step); + }, function(start2, end2) { + return end2.getUTCMonth() - start2.getUTCMonth() + (end2.getUTCFullYear() - start2.getUTCFullYear()) * 12; + }, function(date2) { + return date2.getUTCMonth(); + }); + const utcMonth$1 = utcMonth; + utcMonth.range; + var utcYear = newInterval(function(date2) { + date2.setUTCMonth(0, 1); + date2.setUTCHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setUTCFullYear(date2.getUTCFullYear() + step); + }, function(start2, end2) { + return end2.getUTCFullYear() - start2.getUTCFullYear(); + }, function(date2) { + return date2.getUTCFullYear(); + }); + utcYear.every = function(k) { + return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date2) { + date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / k) * k); + date2.setUTCMonth(0, 1); + date2.setUTCHours(0, 0, 0, 0); + }, function(date2, step) { + date2.setUTCFullYear(date2.getUTCFullYear() + step * k); + }); + }; + const utcYear$1 = utcYear; + utcYear.range; + function ticker(year2, month2, week, day2, hour2, minute2) { + const tickIntervals = [ + [utcSecond, 1, durationSecond], + [utcSecond, 5, 5 * durationSecond], + [utcSecond, 15, 15 * durationSecond], + [utcSecond, 30, 30 * durationSecond], + [minute2, 1, durationMinute], + [minute2, 5, 5 * durationMinute], + [minute2, 15, 15 * durationMinute], + [minute2, 30, 30 * durationMinute], + [hour2, 1, durationHour], + [hour2, 3, 3 * durationHour], + [hour2, 6, 6 * durationHour], + [hour2, 12, 12 * durationHour], + [day2, 1, durationDay], + [day2, 2, 2 * durationDay], + [week, 1, durationWeek], + [month2, 1, durationMonth], + [month2, 3, 3 * durationMonth], + [year2, 1, durationYear] + ]; + function ticks2(start2, stop, count) { + const reverse = stop < start2; + if (reverse) + [start2, stop] = [stop, start2]; + const interval2 = count && typeof count.range === "function" ? count : tickInterval2(start2, stop, count); + const ticks3 = interval2 ? interval2.range(start2, +stop + 1) : []; + return reverse ? ticks3.reverse() : ticks3; + } + function tickInterval2(start2, stop, count) { + const target = Math.abs(stop - start2) / count; + const i2 = bisector(([, , step2]) => step2).right(tickIntervals, target); + if (i2 === tickIntervals.length) + return year2.every(tickStep(start2 / durationYear, stop / durationYear, count)); + if (i2 === 0) + return millisecond$1.every(Math.max(tickStep(start2, stop, count), 1)); + const [t, step] = tickIntervals[target / tickIntervals[i2 - 1][2] < tickIntervals[i2][2] / target ? i2 - 1 : i2]; + return t.every(step); + } + return [ticks2, tickInterval2]; + } + ticker(utcYear$1, utcMonth$1, utcSunday, utcDay$1, utcHour$1, utcMinute$1); + const [timeTicks, timeTickInterval] = ticker(timeYear, timeMonth, sunday, timeDay, timeHour, timeMinute); + function localDate(d) { + if (0 <= d.y && d.y < 100) { + var date2 = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L); + date2.setFullYear(d.y); + return date2; + } + return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L); + } + function utcDate(d) { + if (0 <= d.y && d.y < 100) { + var date2 = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L)); + date2.setUTCFullYear(d.y); + return date2; + } + return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L)); + } + function newDate(y2, m, d) { + return { y: y2, m, d, H: 0, M: 0, S: 0, L: 0 }; + } + function formatLocale(locale2) { + var locale_dateTime = locale2.dateTime, locale_date = locale2.date, locale_time = locale2.time, locale_periods = locale2.periods, locale_weekdays = locale2.days, locale_shortWeekdays = locale2.shortDays, locale_months = locale2.months, locale_shortMonths = locale2.shortMonths; + var periodRe = formatRe(locale_periods), periodLookup = formatLookup(locale_periods), weekdayRe = formatRe(locale_weekdays), weekdayLookup = formatLookup(locale_weekdays), shortWeekdayRe = formatRe(locale_shortWeekdays), shortWeekdayLookup = formatLookup(locale_shortWeekdays), monthRe = formatRe(locale_months), monthLookup = formatLookup(locale_months), shortMonthRe = formatRe(locale_shortMonths), shortMonthLookup = formatLookup(locale_shortMonths); + var formats = { + "a": formatShortWeekday, + "A": formatWeekday, + "b": formatShortMonth, + "B": formatMonth, + "c": null, + "d": formatDayOfMonth, + "e": formatDayOfMonth, + "f": formatMicroseconds, + "g": formatYearISO, + "G": formatFullYearISO, + "H": formatHour24, + "I": formatHour12, + "j": formatDayOfYear, + "L": formatMilliseconds, + "m": formatMonthNumber, + "M": formatMinutes, + "p": formatPeriod, + "q": formatQuarter, + "Q": formatUnixTimestamp, + "s": formatUnixTimestampSeconds, + "S": formatSeconds, + "u": formatWeekdayNumberMonday, + "U": formatWeekNumberSunday, + "V": formatWeekNumberISO, + "w": formatWeekdayNumberSunday, + "W": formatWeekNumberMonday, + "x": null, + "X": null, + "y": formatYear, + "Y": formatFullYear, + "Z": formatZone, + "%": formatLiteralPercent + }; + var utcFormats = { + "a": formatUTCShortWeekday, + "A": formatUTCWeekday, + "b": formatUTCShortMonth, + "B": formatUTCMonth, + "c": null, + "d": formatUTCDayOfMonth, + "e": formatUTCDayOfMonth, + "f": formatUTCMicroseconds, + "g": formatUTCYearISO, + "G": formatUTCFullYearISO, + "H": formatUTCHour24, + "I": formatUTCHour12, + "j": formatUTCDayOfYear, + "L": formatUTCMilliseconds, + "m": formatUTCMonthNumber, + "M": formatUTCMinutes, + "p": formatUTCPeriod, + "q": formatUTCQuarter, + "Q": formatUnixTimestamp, + "s": formatUnixTimestampSeconds, + "S": formatUTCSeconds, + "u": formatUTCWeekdayNumberMonday, + "U": formatUTCWeekNumberSunday, + "V": formatUTCWeekNumberISO, + "w": formatUTCWeekdayNumberSunday, + "W": formatUTCWeekNumberMonday, + "x": null, + "X": null, + "y": formatUTCYear, + "Y": formatUTCFullYear, + "Z": formatUTCZone, + "%": formatLiteralPercent + }; + var parses = { + "a": parseShortWeekday, + "A": parseWeekday, + "b": parseShortMonth, + "B": parseMonth, + "c": parseLocaleDateTime, + "d": parseDayOfMonth, + "e": parseDayOfMonth, + "f": parseMicroseconds, + "g": parseYear, + "G": parseFullYear, + "H": parseHour24, + "I": parseHour24, + "j": parseDayOfYear, + "L": parseMilliseconds, + "m": parseMonthNumber, + "M": parseMinutes, + "p": parsePeriod, + "q": parseQuarter, + "Q": parseUnixTimestamp, + "s": parseUnixTimestampSeconds, + "S": parseSeconds, + "u": parseWeekdayNumberMonday, + "U": parseWeekNumberSunday, + "V": parseWeekNumberISO, + "w": parseWeekdayNumberSunday, + "W": parseWeekNumberMonday, + "x": parseLocaleDate, + "X": parseLocaleTime, + "y": parseYear, + "Y": parseFullYear, + "Z": parseZone, + "%": parseLiteralPercent + }; + formats.x = newFormat(locale_date, formats); + formats.X = newFormat(locale_time, formats); + formats.c = newFormat(locale_dateTime, formats); + utcFormats.x = newFormat(locale_date, utcFormats); + utcFormats.X = newFormat(locale_time, utcFormats); + utcFormats.c = newFormat(locale_dateTime, utcFormats); + function newFormat(specifier, formats2) { + return function(date2) { + var string = [], i2 = -1, j = 0, n = specifier.length, c2, pad2, format2; + if (!(date2 instanceof Date)) + date2 = new Date(+date2); + while (++i2 < n) { + if (specifier.charCodeAt(i2) === 37) { + string.push(specifier.slice(j, i2)); + if ((pad2 = pads[c2 = specifier.charAt(++i2)]) != null) + c2 = specifier.charAt(++i2); + else + pad2 = c2 === "e" ? " " : "0"; + if (format2 = formats2[c2]) + c2 = format2(date2, pad2); + string.push(c2); + j = i2 + 1; + } + } + string.push(specifier.slice(j, i2)); + return string.join(""); + }; + } + function newParse(specifier, Z) { + return function(string) { + var d = newDate(1900, void 0, 1), i2 = parseSpecifier(d, specifier, string += "", 0), week, day2; + if (i2 != string.length) + return null; + if ("Q" in d) + return new Date(d.Q); + if ("s" in d) + return new Date(d.s * 1e3 + ("L" in d ? d.L : 0)); + if (Z && !("Z" in d)) + d.Z = 0; + if ("p" in d) + d.H = d.H % 12 + d.p * 12; + if (d.m === void 0) + d.m = "q" in d ? d.q : 0; + if ("V" in d) { + if (d.V < 1 || d.V > 53) + return null; + if (!("w" in d)) + d.w = 1; + if ("Z" in d) { + week = utcDate(newDate(d.y, 0, 1)), day2 = week.getUTCDay(); + week = day2 > 4 || day2 === 0 ? utcMonday.ceil(week) : utcMonday(week); + week = utcDay$1.offset(week, (d.V - 1) * 7); + d.y = week.getUTCFullYear(); + d.m = week.getUTCMonth(); + d.d = week.getUTCDate() + (d.w + 6) % 7; + } else { + week = localDate(newDate(d.y, 0, 1)), day2 = week.getDay(); + week = day2 > 4 || day2 === 0 ? monday.ceil(week) : monday(week); + week = timeDay.offset(week, (d.V - 1) * 7); + d.y = week.getFullYear(); + d.m = week.getMonth(); + d.d = week.getDate() + (d.w + 6) % 7; + } + } else if ("W" in d || "U" in d) { + if (!("w" in d)) + d.w = "u" in d ? d.u % 7 : "W" in d ? 1 : 0; + day2 = "Z" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay(); + d.m = 0; + d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day2 + 5) % 7 : d.w + d.U * 7 - (day2 + 6) % 7; + } + if ("Z" in d) { + d.H += d.Z / 100 | 0; + d.M += d.Z % 100; + return utcDate(d); + } + return localDate(d); + }; + } + function parseSpecifier(d, specifier, string, j) { + var i2 = 0, n = specifier.length, m = string.length, c2, parse2; + while (i2 < n) { + if (j >= m) + return -1; + c2 = specifier.charCodeAt(i2++); + if (c2 === 37) { + c2 = specifier.charAt(i2++); + parse2 = parses[c2 in pads ? specifier.charAt(i2++) : c2]; + if (!parse2 || (j = parse2(d, string, j)) < 0) + return -1; + } else if (c2 != string.charCodeAt(j++)) { + return -1; + } + } + return j; + } + function parsePeriod(d, string, i2) { + var n = periodRe.exec(string.slice(i2)); + return n ? (d.p = periodLookup.get(n[0].toLowerCase()), i2 + n[0].length) : -1; + } + function parseShortWeekday(d, string, i2) { + var n = shortWeekdayRe.exec(string.slice(i2)); + return n ? (d.w = shortWeekdayLookup.get(n[0].toLowerCase()), i2 + n[0].length) : -1; + } + function parseWeekday(d, string, i2) { + var n = weekdayRe.exec(string.slice(i2)); + return n ? (d.w = weekdayLookup.get(n[0].toLowerCase()), i2 + n[0].length) : -1; + } + function parseShortMonth(d, string, i2) { + var n = shortMonthRe.exec(string.slice(i2)); + return n ? (d.m = shortMonthLookup.get(n[0].toLowerCase()), i2 + n[0].length) : -1; + } + function parseMonth(d, string, i2) { + var n = monthRe.exec(string.slice(i2)); + return n ? (d.m = monthLookup.get(n[0].toLowerCase()), i2 + n[0].length) : -1; + } + function parseLocaleDateTime(d, string, i2) { + return parseSpecifier(d, locale_dateTime, string, i2); + } + function parseLocaleDate(d, string, i2) { + return parseSpecifier(d, locale_date, string, i2); + } + function parseLocaleTime(d, string, i2) { + return parseSpecifier(d, locale_time, string, i2); + } + function formatShortWeekday(d) { + return locale_shortWeekdays[d.getDay()]; + } + function formatWeekday(d) { + return locale_weekdays[d.getDay()]; + } + function formatShortMonth(d) { + return locale_shortMonths[d.getMonth()]; + } + function formatMonth(d) { + return locale_months[d.getMonth()]; + } + function formatPeriod(d) { + return locale_periods[+(d.getHours() >= 12)]; + } + function formatQuarter(d) { + return 1 + ~~(d.getMonth() / 3); + } + function formatUTCShortWeekday(d) { + return locale_shortWeekdays[d.getUTCDay()]; + } + function formatUTCWeekday(d) { + return locale_weekdays[d.getUTCDay()]; + } + function formatUTCShortMonth(d) { + return locale_shortMonths[d.getUTCMonth()]; + } + function formatUTCMonth(d) { + return locale_months[d.getUTCMonth()]; + } + function formatUTCPeriod(d) { + return locale_periods[+(d.getUTCHours() >= 12)]; + } + function formatUTCQuarter(d) { + return 1 + ~~(d.getUTCMonth() / 3); + } + return { + format: function(specifier) { + var f = newFormat(specifier += "", formats); + f.toString = function() { + return specifier; + }; + return f; + }, + parse: function(specifier) { + var p = newParse(specifier += "", false); + p.toString = function() { + return specifier; + }; + return p; + }, + utcFormat: function(specifier) { + var f = newFormat(specifier += "", utcFormats); + f.toString = function() { + return specifier; + }; + return f; + }, + utcParse: function(specifier) { + var p = newParse(specifier += "", true); + p.toString = function() { + return specifier; + }; + return p; + } + }; + } + var pads = { "-": "", "_": " ", "0": "0" }, numberRe = /^\s*\d+/, percentRe = /^%/, requoteRe = /[\\^$*+?|[\]().{}]/g; + function pad(value, fill, width2) { + var sign2 = value < 0 ? "-" : "", string = (sign2 ? -value : value) + "", length2 = string.length; + return sign2 + (length2 < width2 ? new Array(width2 - length2 + 1).join(fill) + string : string); + } + function requote(s) { + return s.replace(requoteRe, "\\$&"); + } + function formatRe(names) { + return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i"); + } + function formatLookup(names) { + return new Map(names.map((name2, i2) => [name2.toLowerCase(), i2])); + } + function parseWeekdayNumberSunday(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 1)); + return n ? (d.w = +n[0], i2 + n[0].length) : -1; + } + function parseWeekdayNumberMonday(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 1)); + return n ? (d.u = +n[0], i2 + n[0].length) : -1; + } + function parseWeekNumberSunday(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.U = +n[0], i2 + n[0].length) : -1; + } + function parseWeekNumberISO(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.V = +n[0], i2 + n[0].length) : -1; + } + function parseWeekNumberMonday(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.W = +n[0], i2 + n[0].length) : -1; + } + function parseFullYear(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 4)); + return n ? (d.y = +n[0], i2 + n[0].length) : -1; + } + function parseYear(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2e3), i2 + n[0].length) : -1; + } + function parseZone(d, string, i2) { + var n = /^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(string.slice(i2, i2 + 6)); + return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i2 + n[0].length) : -1; + } + function parseQuarter(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 1)); + return n ? (d.q = n[0] * 3 - 3, i2 + n[0].length) : -1; + } + function parseMonthNumber(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.m = n[0] - 1, i2 + n[0].length) : -1; + } + function parseDayOfMonth(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.d = +n[0], i2 + n[0].length) : -1; + } + function parseDayOfYear(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 3)); + return n ? (d.m = 0, d.d = +n[0], i2 + n[0].length) : -1; + } + function parseHour24(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.H = +n[0], i2 + n[0].length) : -1; + } + function parseMinutes(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.M = +n[0], i2 + n[0].length) : -1; + } + function parseSeconds(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 2)); + return n ? (d.S = +n[0], i2 + n[0].length) : -1; + } + function parseMilliseconds(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 3)); + return n ? (d.L = +n[0], i2 + n[0].length) : -1; + } + function parseMicroseconds(d, string, i2) { + var n = numberRe.exec(string.slice(i2, i2 + 6)); + return n ? (d.L = Math.floor(n[0] / 1e3), i2 + n[0].length) : -1; + } + function parseLiteralPercent(d, string, i2) { + var n = percentRe.exec(string.slice(i2, i2 + 1)); + return n ? i2 + n[0].length : -1; + } + function parseUnixTimestamp(d, string, i2) { + var n = numberRe.exec(string.slice(i2)); + return n ? (d.Q = +n[0], i2 + n[0].length) : -1; + } + function parseUnixTimestampSeconds(d, string, i2) { + var n = numberRe.exec(string.slice(i2)); + return n ? (d.s = +n[0], i2 + n[0].length) : -1; + } + function formatDayOfMonth(d, p) { + return pad(d.getDate(), p, 2); + } + function formatHour24(d, p) { + return pad(d.getHours(), p, 2); + } + function formatHour12(d, p) { + return pad(d.getHours() % 12 || 12, p, 2); + } + function formatDayOfYear(d, p) { + return pad(1 + timeDay.count(timeYear(d), d), p, 3); + } + function formatMilliseconds(d, p) { + return pad(d.getMilliseconds(), p, 3); + } + function formatMicroseconds(d, p) { + return formatMilliseconds(d, p) + "000"; + } + function formatMonthNumber(d, p) { + return pad(d.getMonth() + 1, p, 2); + } + function formatMinutes(d, p) { + return pad(d.getMinutes(), p, 2); + } + function formatSeconds(d, p) { + return pad(d.getSeconds(), p, 2); + } + function formatWeekdayNumberMonday(d) { + var day2 = d.getDay(); + return day2 === 0 ? 7 : day2; + } + function formatWeekNumberSunday(d, p) { + return pad(sunday.count(timeYear(d) - 1, d), p, 2); + } + function dISO(d) { + var day2 = d.getDay(); + return day2 >= 4 || day2 === 0 ? thursday(d) : thursday.ceil(d); + } + function formatWeekNumberISO(d, p) { + d = dISO(d); + return pad(thursday.count(timeYear(d), d) + (timeYear(d).getDay() === 4), p, 2); + } + function formatWeekdayNumberSunday(d) { + return d.getDay(); + } + function formatWeekNumberMonday(d, p) { + return pad(monday.count(timeYear(d) - 1, d), p, 2); + } + function formatYear(d, p) { + return pad(d.getFullYear() % 100, p, 2); + } + function formatYearISO(d, p) { + d = dISO(d); + return pad(d.getFullYear() % 100, p, 2); + } + function formatFullYear(d, p) { + return pad(d.getFullYear() % 1e4, p, 4); + } + function formatFullYearISO(d, p) { + var day2 = d.getDay(); + d = day2 >= 4 || day2 === 0 ? thursday(d) : thursday.ceil(d); + return pad(d.getFullYear() % 1e4, p, 4); + } + function formatZone(d) { + var z = d.getTimezoneOffset(); + return (z > 0 ? "-" : (z *= -1, "+")) + pad(z / 60 | 0, "0", 2) + pad(z % 60, "0", 2); + } + function formatUTCDayOfMonth(d, p) { + return pad(d.getUTCDate(), p, 2); + } + function formatUTCHour24(d, p) { + return pad(d.getUTCHours(), p, 2); + } + function formatUTCHour12(d, p) { + return pad(d.getUTCHours() % 12 || 12, p, 2); + } + function formatUTCDayOfYear(d, p) { + return pad(1 + utcDay$1.count(utcYear$1(d), d), p, 3); + } + function formatUTCMilliseconds(d, p) { + return pad(d.getUTCMilliseconds(), p, 3); + } + function formatUTCMicroseconds(d, p) { + return formatUTCMilliseconds(d, p) + "000"; + } + function formatUTCMonthNumber(d, p) { + return pad(d.getUTCMonth() + 1, p, 2); + } + function formatUTCMinutes(d, p) { + return pad(d.getUTCMinutes(), p, 2); + } + function formatUTCSeconds(d, p) { + return pad(d.getUTCSeconds(), p, 2); + } + function formatUTCWeekdayNumberMonday(d) { + var dow = d.getUTCDay(); + return dow === 0 ? 7 : dow; + } + function formatUTCWeekNumberSunday(d, p) { + return pad(utcSunday.count(utcYear$1(d) - 1, d), p, 2); + } + function UTCdISO(d) { + var day2 = d.getUTCDay(); + return day2 >= 4 || day2 === 0 ? utcThursday(d) : utcThursday.ceil(d); + } + function formatUTCWeekNumberISO(d, p) { + d = UTCdISO(d); + return pad(utcThursday.count(utcYear$1(d), d) + (utcYear$1(d).getUTCDay() === 4), p, 2); + } + function formatUTCWeekdayNumberSunday(d) { + return d.getUTCDay(); + } + function formatUTCWeekNumberMonday(d, p) { + return pad(utcMonday.count(utcYear$1(d) - 1, d), p, 2); + } + function formatUTCYear(d, p) { + return pad(d.getUTCFullYear() % 100, p, 2); + } + function formatUTCYearISO(d, p) { + d = UTCdISO(d); + return pad(d.getUTCFullYear() % 100, p, 2); + } + function formatUTCFullYear(d, p) { + return pad(d.getUTCFullYear() % 1e4, p, 4); + } + function formatUTCFullYearISO(d, p) { + var day2 = d.getUTCDay(); + d = day2 >= 4 || day2 === 0 ? utcThursday(d) : utcThursday.ceil(d); + return pad(d.getUTCFullYear() % 1e4, p, 4); + } + function formatUTCZone() { + return "+0000"; + } + function formatLiteralPercent() { + return "%"; + } + function formatUnixTimestamp(d) { + return +d; + } + function formatUnixTimestampSeconds(d) { + return Math.floor(+d / 1e3); + } + var locale; + var timeFormat; + defaultLocale({ + dateTime: "%x, %X", + date: "%-m/%-d/%Y", + time: "%-I:%M:%S %p", + periods: ["AM", "PM"], + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] + }); + function defaultLocale(definition) { + locale = formatLocale(definition); + timeFormat = locale.format; + locale.parse; + locale.utcFormat; + locale.utcParse; + return locale; + } + function date(t) { + return new Date(t); + } + function number(t) { + return t instanceof Date ? +t : +new Date(+t); + } + function calendar(ticks2, tickInterval2, year2, month2, week, day2, hour2, minute2, second2, format2) { + var scale = continuous(), invert2 = scale.invert, domain = scale.domain; + var formatMillisecond = format2(".%L"), formatSecond = format2(":%S"), formatMinute = format2("%I:%M"), formatHour = format2("%I %p"), formatDay = format2("%a %d"), formatWeek = format2("%b %d"), formatMonth = format2("%B"), formatYear2 = format2("%Y"); + function tickFormat2(date2) { + return (second2(date2) < date2 ? formatMillisecond : minute2(date2) < date2 ? formatSecond : hour2(date2) < date2 ? formatMinute : day2(date2) < date2 ? formatHour : month2(date2) < date2 ? week(date2) < date2 ? formatDay : formatWeek : year2(date2) < date2 ? formatMonth : formatYear2)(date2); + } + scale.invert = function(y2) { + return new Date(invert2(y2)); + }; + scale.domain = function(_2) { + return arguments.length ? domain(Array.from(_2, number)) : domain().map(date); + }; + scale.ticks = function(interval2) { + var d = domain(); + return ticks2(d[0], d[d.length - 1], interval2 == null ? 10 : interval2); + }; + scale.tickFormat = function(count, specifier) { + return specifier == null ? tickFormat2 : format2(specifier); + }; + scale.nice = function(interval2) { + var d = domain(); + if (!interval2 || typeof interval2.range !== "function") + interval2 = tickInterval2(d[0], d[d.length - 1], interval2 == null ? 10 : interval2); + return interval2 ? domain(nice(d, interval2)) : scale; + }; + scale.copy = function() { + return copy$1(scale, calendar(ticks2, tickInterval2, year2, month2, week, day2, hour2, minute2, second2, format2)); + }; + return scale; + } + function time$1() { + return initRange.apply(calendar(timeTicks, timeTickInterval, timeYear, timeMonth, sunday, timeDay, timeHour, timeMinute, utcSecond, timeFormat).domain([new Date(2e3, 0, 1), new Date(2e3, 0, 2)]), arguments); + } + function constant$1(x2) { + return function constant2() { + return x2; + }; + } + const abs$1 = Math.abs; + const atan2 = Math.atan2; + const cos = Math.cos; + const max$1 = Math.max; + const min$1 = Math.min; + const sin = Math.sin; + const sqrt = Math.sqrt; + const epsilon = 1e-12; + const pi = Math.PI; + const halfPi = pi / 2; + const tau = 2 * pi; + function acos(x2) { + return x2 > 1 ? 0 : x2 < -1 ? pi : Math.acos(x2); + } + function asin(x2) { + return x2 >= 1 ? halfPi : x2 <= -1 ? -halfPi : Math.asin(x2); + } + function arcInnerRadius(d) { + return d.innerRadius; + } + function arcOuterRadius(d) { + return d.outerRadius; + } + function arcStartAngle(d) { + return d.startAngle; + } + function arcEndAngle(d) { + return d.endAngle; + } + function arcPadAngle(d) { + return d && d.padAngle; + } + function intersect$1(x0, y0, x1, y1, x2, y2, x3, y3) { + var x10 = x1 - x0, y10 = y1 - y0, x32 = x3 - x2, y32 = y3 - y2, t = y32 * x10 - x32 * y10; + if (t * t < epsilon) + return; + t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t; + return [x0 + t * x10, y0 + t * y10]; + } + function cornerTangents(x0, y0, x1, y1, r1, rc, cw) { + var x01 = x0 - x1, y01 = y0 - y1, lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x11 = x0 + ox, y11 = y0 + oy, x10 = x1 + ox, y10 = y1 + oy, x00 = (x11 + x10) / 2, y00 = (y11 + y10) / 2, dx = x10 - x11, dy = y10 - y11, d2 = dx * dx + dy * dy, r = r1 - rc, D = x11 * y10 - x10 * y11, d = (dy < 0 ? -1 : 1) * sqrt(max$1(0, r * r * d2 - D * D)), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x00, dy0 = cy0 - y00, dx1 = cx1 - x00, dy1 = cy1 - y00; + if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) + cx0 = cx1, cy0 = cy1; + return { + cx: cx0, + cy: cy0, + x01: -ox, + y01: -oy, + x11: cx0 * (r1 / r - 1), + y11: cy0 * (r1 / r - 1) + }; + } + function d3arc() { + var innerRadius = arcInnerRadius, outerRadius = arcOuterRadius, cornerRadius = constant$1(0), padRadius = null, startAngle = arcStartAngle, endAngle = arcEndAngle, padAngle = arcPadAngle, context = null; + function arc() { + var buffer, r, r0 = +innerRadius.apply(this, arguments), r1 = +outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) - halfPi, a1 = endAngle.apply(this, arguments) - halfPi, da = abs$1(a1 - a0), cw = a1 > a0; + if (!context) + context = buffer = path(); + if (r1 < r0) + r = r1, r1 = r0, r0 = r; + if (!(r1 > epsilon)) + context.moveTo(0, 0); + else if (da > tau - epsilon) { + context.moveTo(r1 * cos(a0), r1 * sin(a0)); + context.arc(0, 0, r1, a0, a1, !cw); + if (r0 > epsilon) { + context.moveTo(r0 * cos(a1), r0 * sin(a1)); + context.arc(0, 0, r0, a1, a0, cw); + } + } else { + var a01 = a0, a11 = a1, a00 = a0, a10 = a1, da0 = da, da1 = da, ap = padAngle.apply(this, arguments) / 2, rp = ap > epsilon && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)), rc = min$1(abs$1(r1 - r0) / 2, +cornerRadius.apply(this, arguments)), rc0 = rc, rc1 = rc, t02, t12; + if (rp > epsilon) { + var p0 = asin(rp / r0 * sin(ap)), p1 = asin(rp / r1 * sin(ap)); + if ((da0 -= p0 * 2) > epsilon) + p0 *= cw ? 1 : -1, a00 += p0, a10 -= p0; + else + da0 = 0, a00 = a10 = (a0 + a1) / 2; + if ((da1 -= p1 * 2) > epsilon) + p1 *= cw ? 1 : -1, a01 += p1, a11 -= p1; + else + da1 = 0, a01 = a11 = (a0 + a1) / 2; + } + var x01 = r1 * cos(a01), y01 = r1 * sin(a01), x10 = r0 * cos(a10), y10 = r0 * sin(a10); + if (rc > epsilon) { + var x11 = r1 * cos(a11), y11 = r1 * sin(a11), x00 = r0 * cos(a00), y00 = r0 * sin(a00), oc; + if (da < pi && (oc = intersect$1(x01, y01, x00, y00, x11, y11, x10, y10))) { + var ax = x01 - oc[0], ay = y01 - oc[1], bx = x11 - oc[0], by = y11 - oc[1], kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2), lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]); + rc0 = min$1(rc, (r0 - lc) / (kc - 1)); + rc1 = min$1(rc, (r1 - lc) / (kc + 1)); + } + } + if (!(da1 > epsilon)) + context.moveTo(x01, y01); + else if (rc1 > epsilon) { + t02 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw); + t12 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw); + context.moveTo(t02.cx + t02.x01, t02.cy + t02.y01); + if (rc1 < rc) + context.arc(t02.cx, t02.cy, rc1, atan2(t02.y01, t02.x01), atan2(t12.y01, t12.x01), !cw); + else { + context.arc(t02.cx, t02.cy, rc1, atan2(t02.y01, t02.x01), atan2(t02.y11, t02.x11), !cw); + context.arc(0, 0, r1, atan2(t02.cy + t02.y11, t02.cx + t02.x11), atan2(t12.cy + t12.y11, t12.cx + t12.x11), !cw); + context.arc(t12.cx, t12.cy, rc1, atan2(t12.y11, t12.x11), atan2(t12.y01, t12.x01), !cw); + } + } else + context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw); + if (!(r0 > epsilon) || !(da0 > epsilon)) + context.lineTo(x10, y10); + else if (rc0 > epsilon) { + t02 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw); + t12 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw); + context.lineTo(t02.cx + t02.x01, t02.cy + t02.y01); + if (rc0 < rc) + context.arc(t02.cx, t02.cy, rc0, atan2(t02.y01, t02.x01), atan2(t12.y01, t12.x01), !cw); + else { + context.arc(t02.cx, t02.cy, rc0, atan2(t02.y01, t02.x01), atan2(t02.y11, t02.x11), !cw); + context.arc(0, 0, r0, atan2(t02.cy + t02.y11, t02.cx + t02.x11), atan2(t12.cy + t12.y11, t12.cx + t12.x11), cw); + context.arc(t12.cx, t12.cy, rc0, atan2(t12.y11, t12.x11), atan2(t12.y01, t12.x01), !cw); + } + } else + context.arc(0, 0, r0, a10, a00, cw); + } + context.closePath(); + if (buffer) + return context = null, buffer + "" || null; + } + arc.centroid = function() { + var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2; + return [cos(a) * r, sin(a) * r]; + }; + arc.innerRadius = function(_2) { + return arguments.length ? (innerRadius = typeof _2 === "function" ? _2 : constant$1(+_2), arc) : innerRadius; + }; + arc.outerRadius = function(_2) { + return arguments.length ? (outerRadius = typeof _2 === "function" ? _2 : constant$1(+_2), arc) : outerRadius; + }; + arc.cornerRadius = function(_2) { + return arguments.length ? (cornerRadius = typeof _2 === "function" ? _2 : constant$1(+_2), arc) : cornerRadius; + }; + arc.padRadius = function(_2) { + return arguments.length ? (padRadius = _2 == null ? null : typeof _2 === "function" ? _2 : constant$1(+_2), arc) : padRadius; + }; + arc.startAngle = function(_2) { + return arguments.length ? (startAngle = typeof _2 === "function" ? _2 : constant$1(+_2), arc) : startAngle; + }; + arc.endAngle = function(_2) { + return arguments.length ? (endAngle = typeof _2 === "function" ? _2 : constant$1(+_2), arc) : endAngle; + }; + arc.padAngle = function(_2) { + return arguments.length ? (padAngle = typeof _2 === "function" ? _2 : constant$1(+_2), arc) : padAngle; + }; + arc.context = function(_2) { + return arguments.length ? (context = _2 == null ? null : _2, arc) : context; + }; + return arc; + } + function array(x2) { + return typeof x2 === "object" && "length" in x2 ? x2 : Array.from(x2); + } + function Linear(context) { + this._context = context; + } + Linear.prototype = { + areaStart: function() { + this._line = 0; + }, + areaEnd: function() { + this._line = NaN; + }, + lineStart: function() { + this._point = 0; + }, + lineEnd: function() { + if (this._line || this._line !== 0 && this._point === 1) + this._context.closePath(); + this._line = 1 - this._line; + }, + point: function(x2, y2) { + x2 = +x2, y2 = +y2; + switch (this._point) { + case 0: + this._point = 1; + this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2); + break; + case 1: + this._point = 2; + default: + this._context.lineTo(x2, y2); + break; + } + } + }; + function curveLinear(context) { + return new Linear(context); + } + function x(p) { + return p[0]; + } + function y(p) { + return p[1]; + } + function line$1(x$1, y$1) { + var defined = constant$1(true), context = null, curve = curveLinear, output = null; + x$1 = typeof x$1 === "function" ? x$1 : x$1 === void 0 ? x : constant$1(x$1); + y$1 = typeof y$1 === "function" ? y$1 : y$1 === void 0 ? y : constant$1(y$1); + function line2(data) { + var i2, n = (data = array(data)).length, d, defined0 = false, buffer; + if (context == null) + output = curve(buffer = path()); + for (i2 = 0; i2 <= n; ++i2) { + if (!(i2 < n && defined(d = data[i2], i2, data)) === defined0) { + if (defined0 = !defined0) + output.lineStart(); + else + output.lineEnd(); + } + if (defined0) + output.point(+x$1(d, i2, data), +y$1(d, i2, data)); + } + if (buffer) + return output = null, buffer + "" || null; + } + line2.x = function(_2) { + return arguments.length ? (x$1 = typeof _2 === "function" ? _2 : constant$1(+_2), line2) : x$1; + }; + line2.y = function(_2) { + return arguments.length ? (y$1 = typeof _2 === "function" ? _2 : constant$1(+_2), line2) : y$1; + }; + line2.defined = function(_2) { + return arguments.length ? (defined = typeof _2 === "function" ? _2 : constant$1(!!_2), line2) : defined; + }; + line2.curve = function(_2) { + return arguments.length ? (curve = _2, context != null && (output = curve(context)), line2) : curve; + }; + line2.context = function(_2) { + return arguments.length ? (_2 == null ? context = output = null : output = curve(context = _2), line2) : context; + }; + return line2; + } + function descending(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; + } + function identity$1(d) { + return d; + } + function d3pie() { + var value = identity$1, sortValues = descending, sort2 = null, startAngle = constant$1(0), endAngle = constant$1(tau), padAngle = constant$1(0); + function pie(data) { + var i2, n = (data = array(data)).length, j, k, sum = 0, index = new Array(n), arcs = new Array(n), a0 = +startAngle.apply(this, arguments), da = Math.min(tau, Math.max(-tau, endAngle.apply(this, arguments) - a0)), a1, p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)), pa = p * (da < 0 ? -1 : 1), v; + for (i2 = 0; i2 < n; ++i2) { + if ((v = arcs[index[i2] = i2] = +value(data[i2], i2, data)) > 0) { + sum += v; + } + } + if (sortValues != null) + index.sort(function(i3, j2) { + return sortValues(arcs[i3], arcs[j2]); + }); + else if (sort2 != null) + index.sort(function(i3, j2) { + return sort2(data[i3], data[j2]); + }); + for (i2 = 0, k = sum ? (da - n * pa) / sum : 0; i2 < n; ++i2, a0 = a1) { + j = index[i2], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = { + data: data[j], + index: i2, + value: v, + startAngle: a0, + endAngle: a1, + padAngle: p + }; + } + return arcs; + } + pie.value = function(_2) { + return arguments.length ? (value = typeof _2 === "function" ? _2 : constant$1(+_2), pie) : value; + }; + pie.sortValues = function(_2) { + return arguments.length ? (sortValues = _2, sort2 = null, pie) : sortValues; + }; + pie.sort = function(_2) { + return arguments.length ? (sort2 = _2, sortValues = null, pie) : sort2; + }; + pie.startAngle = function(_2) { + return arguments.length ? (startAngle = typeof _2 === "function" ? _2 : constant$1(+_2), pie) : startAngle; + }; + pie.endAngle = function(_2) { + return arguments.length ? (endAngle = typeof _2 === "function" ? _2 : constant$1(+_2), pie) : endAngle; + }; + pie.padAngle = function(_2) { + return arguments.length ? (padAngle = typeof _2 === "function" ? _2 : constant$1(+_2), pie) : padAngle; + }; + return pie; + } + function noop$1() { + } + function point$2(that, x2, y2) { + that._context.bezierCurveTo( + (2 * that._x0 + that._x1) / 3, + (2 * that._y0 + that._y1) / 3, + (that._x0 + 2 * that._x1) / 3, + (that._y0 + 2 * that._y1) / 3, + (that._x0 + 4 * that._x1 + x2) / 6, + (that._y0 + 4 * that._y1 + y2) / 6 + ); + } + function Basis(context) { + this._context = context; + } + Basis.prototype = { + areaStart: function() { + this._line = 0; + }, + areaEnd: function() { + this._line = NaN; + }, + lineStart: function() { + this._x0 = this._x1 = this._y0 = this._y1 = NaN; + this._point = 0; + }, + lineEnd: function() { + switch (this._point) { + case 3: + point$2(this, this._x1, this._y1); + case 2: + this._context.lineTo(this._x1, this._y1); + break; + } + if (this._line || this._line !== 0 && this._point === 1) + this._context.closePath(); + this._line = 1 - this._line; + }, + point: function(x2, y2) { + x2 = +x2, y2 = +y2; + switch (this._point) { + case 0: + this._point = 1; + this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2); + break; + case 1: + this._point = 2; + break; + case 2: + this._point = 3; + this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); + default: + point$2(this, x2, y2); + break; + } + this._x0 = this._x1, this._x1 = x2; + this._y0 = this._y1, this._y1 = y2; + } + }; + function curveBasis(context) { + return new Basis(context); + } + function BasisClosed(context) { + this._context = context; + } + BasisClosed.prototype = { + areaStart: noop$1, + areaEnd: noop$1, + lineStart: function() { + this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN; + this._point = 0; + }, + lineEnd: function() { + switch (this._point) { + case 1: { + this._context.moveTo(this._x2, this._y2); + this._context.closePath(); + break; + } + case 2: { + this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3); + this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3); + this._context.closePath(); + break; + } + case 3: { + this.point(this._x2, this._y2); + this.point(this._x3, this._y3); + this.point(this._x4, this._y4); + break; + } + } + }, + point: function(x2, y2) { + x2 = +x2, y2 = +y2; + switch (this._point) { + case 0: + this._point = 1; + this._x2 = x2, this._y2 = y2; + break; + case 1: + this._point = 2; + this._x3 = x2, this._y3 = y2; + break; + case 2: + this._point = 3; + this._x4 = x2, this._y4 = y2; + this._context.moveTo((this._x0 + 4 * this._x1 + x2) / 6, (this._y0 + 4 * this._y1 + y2) / 6); + break; + default: + point$2(this, x2, y2); + break; + } + this._x0 = this._x1, this._x1 = x2; + this._y0 = this._y1, this._y1 = y2; + } + }; + function curveBasisClosed(context) { + return new BasisClosed(context); + } + function BasisOpen(context) { + this._context = context; + } + BasisOpen.prototype = { + areaStart: function() { + this._line = 0; + }, + areaEnd: function() { + this._line = NaN; + }, + lineStart: function() { + this._x0 = this._x1 = this._y0 = this._y1 = NaN; + this._point = 0; + }, + lineEnd: function() { + if (this._line || this._line !== 0 && this._point === 3) + this._context.closePath(); + this._line = 1 - this._line; + }, + point: function(x2, y2) { + x2 = +x2, y2 = +y2; + switch (this._point) { + case 0: + this._point = 1; + break; + case 1: + this._point = 2; + break; + case 2: + this._point = 3; + var x0 = (this._x0 + 4 * this._x1 + x2) / 6, y0 = (this._y0 + 4 * this._y1 + y2) / 6; + this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); + break; + case 3: + this._point = 4; + default: + point$2(this, x2, y2); + break; + } + this._x0 = this._x1, this._x1 = x2; + this._y0 = this._y1, this._y1 = y2; + } + }; + function curveBasisOpen(context) { + return new BasisOpen(context); + } + function LinearClosed(context) { + this._context = context; + } + LinearClosed.prototype = { + areaStart: noop$1, + areaEnd: noop$1, + lineStart: function() { + this._point = 0; + }, + lineEnd: function() { + if (this._point) + this._context.closePath(); + }, + point: function(x2, y2) { + x2 = +x2, y2 = +y2; + if (this._point) + this._context.lineTo(x2, y2); + else + this._point = 1, this._context.moveTo(x2, y2); + } + }; + function curveLinearClosed(context) { + return new LinearClosed(context); + } + function sign(x2) { + return x2 < 0 ? -1 : 1; + } + function slope3(that, x2, y2) { + var h0 = that._x1 - that._x0, h1 = x2 - that._x1, s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0), s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0), p = (s0 * h1 + s1 * h0) / (h0 + h1); + return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0; + } + function slope2(that, t) { + var h = that._x1 - that._x0; + return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t; + } + function point$1(that, t02, t12) { + var x0 = that._x0, y0 = that._y0, x1 = that._x1, y1 = that._y1, dx = (x1 - x0) / 3; + that._context.bezierCurveTo(x0 + dx, y0 + dx * t02, x1 - dx, y1 - dx * t12, x1, y1); + } + function MonotoneX(context) { + this._context = context; + } + MonotoneX.prototype = { + areaStart: function() { + this._line = 0; + }, + areaEnd: function() { + this._line = NaN; + }, + lineStart: function() { + this._x0 = this._x1 = this._y0 = this._y1 = this._t0 = NaN; + this._point = 0; + }, + lineEnd: function() { + switch (this._point) { + case 2: + this._context.lineTo(this._x1, this._y1); + break; + case 3: + point$1(this, this._t0, slope2(this, this._t0)); + break; + } + if (this._line || this._line !== 0 && this._point === 1) + this._context.closePath(); + this._line = 1 - this._line; + }, + point: function(x2, y2) { + var t12 = NaN; + x2 = +x2, y2 = +y2; + if (x2 === this._x1 && y2 === this._y1) + return; + switch (this._point) { + case 0: + this._point = 1; + this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2); + break; + case 1: + this._point = 2; + break; + case 2: + this._point = 3; + point$1(this, slope2(this, t12 = slope3(this, x2, y2)), t12); + break; + default: + point$1(this, this._t0, t12 = slope3(this, x2, y2)); + break; + } + this._x0 = this._x1, this._x1 = x2; + this._y0 = this._y1, this._y1 = y2; + this._t0 = t12; + } + }; + function MonotoneY(context) { + this._context = new ReflectContext(context); + } + (MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x2, y2) { + MonotoneX.prototype.point.call(this, y2, x2); + }; + function ReflectContext(context) { + this._context = context; + } + ReflectContext.prototype = { + moveTo: function(x2, y2) { + this._context.moveTo(y2, x2); + }, + closePath: function() { + this._context.closePath(); + }, + lineTo: function(x2, y2) { + this._context.lineTo(y2, x2); + }, + bezierCurveTo: function(x1, y1, x2, y2, x3, y3) { + this._context.bezierCurveTo(y1, x1, y2, x2, y3, x3); + } + }; + function monotoneX(context) { + return new MonotoneX(context); + } + function monotoneY(context) { + return new MonotoneY(context); + } + function Natural(context) { + this._context = context; + } + Natural.prototype = { + areaStart: function() { + this._line = 0; + }, + areaEnd: function() { + this._line = NaN; + }, + lineStart: function() { + this._x = []; + this._y = []; + }, + lineEnd: function() { + var x2 = this._x, y2 = this._y, n = x2.length; + if (n) { + this._line ? this._context.lineTo(x2[0], y2[0]) : this._context.moveTo(x2[0], y2[0]); + if (n === 2) { + this._context.lineTo(x2[1], y2[1]); + } else { + var px = controlPoints(x2), py = controlPoints(y2); + for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) { + this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x2[i1], y2[i1]); + } + } + } + if (this._line || this._line !== 0 && n === 1) + this._context.closePath(); + this._line = 1 - this._line; + this._x = this._y = null; + }, + point: function(x2, y2) { + this._x.push(+x2); + this._y.push(+y2); + } + }; + function controlPoints(x2) { + var i2, n = x2.length - 1, m, a = new Array(n), b = new Array(n), r = new Array(n); + a[0] = 0, b[0] = 2, r[0] = x2[0] + 2 * x2[1]; + for (i2 = 1; i2 < n - 1; ++i2) + a[i2] = 1, b[i2] = 4, r[i2] = 4 * x2[i2] + 2 * x2[i2 + 1]; + a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x2[n - 1] + x2[n]; + for (i2 = 1; i2 < n; ++i2) + m = a[i2] / b[i2 - 1], b[i2] -= m, r[i2] -= m * r[i2 - 1]; + a[n - 1] = r[n - 1] / b[n - 1]; + for (i2 = n - 2; i2 >= 0; --i2) + a[i2] = (r[i2] - a[i2 + 1]) / b[i2]; + b[n - 1] = (x2[n] + a[n - 1]) / 2; + for (i2 = 0; i2 < n - 1; ++i2) + b[i2] = 2 * x2[i2 + 1] - a[i2 + 1]; + return [a, b]; + } + function curveNatural(context) { + return new Natural(context); + } + function Step(context, t) { + this._context = context; + this._t = t; + } + Step.prototype = { + areaStart: function() { + this._line = 0; + }, + areaEnd: function() { + this._line = NaN; + }, + lineStart: function() { + this._x = this._y = NaN; + this._point = 0; + }, + lineEnd: function() { + if (0 < this._t && this._t < 1 && this._point === 2) + this._context.lineTo(this._x, this._y); + if (this._line || this._line !== 0 && this._point === 1) + this._context.closePath(); + if (this._line >= 0) + this._t = 1 - this._t, this._line = 1 - this._line; + }, + point: function(x2, y2) { + x2 = +x2, y2 = +y2; + switch (this._point) { + case 0: + this._point = 1; + this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2); + break; + case 1: + this._point = 2; + default: { + if (this._t <= 0) { + this._context.lineTo(this._x, y2); + this._context.lineTo(x2, y2); + } else { + var x1 = this._x * (1 - this._t) + x2 * this._t; + this._context.lineTo(x1, this._y); + this._context.lineTo(x1, y2); + } + break; + } + } + this._x = x2, this._y = y2; + } + }; + function curveStep(context) { + return new Step(context, 0.5); + } + function stepBefore(context) { + return new Step(context, 0); + } + function stepAfter(context) { + return new Step(context, 1); + } + function Transform(k, x2, y2) { + this.k = k; + this.x = x2; + this.y = y2; + } + Transform.prototype = { + constructor: Transform, + scale: function(k) { + return k === 1 ? this : new Transform(this.k * k, this.x, this.y); + }, + translate: function(x2, y2) { + return x2 === 0 & y2 === 0 ? this : new Transform(this.k, this.x + this.k * x2, this.y + this.k * y2); + }, + apply: function(point2) { + return [point2[0] * this.k + this.x, point2[1] * this.k + this.y]; + }, + applyX: function(x2) { + return x2 * this.k + this.x; + }, + applyY: function(y2) { + return y2 * this.k + this.y; + }, + invert: function(location2) { + return [(location2[0] - this.x) / this.k, (location2[1] - this.y) / this.k]; + }, + invertX: function(x2) { + return (x2 - this.x) / this.k; + }, + invertY: function(y2) { + return (y2 - this.y) / this.k; + }, + rescaleX: function(x2) { + return x2.copy().domain(x2.range().map(this.invertX, this).map(x2.invert, x2)); + }, + rescaleY: function(y2) { + return y2.copy().domain(y2.range().map(this.invertY, this).map(y2.invert, y2)); + }, + toString: function() { + return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")"; + } + }; + new Transform(1, 0, 0); + Transform.prototype; + /*! @license DOMPurify 2.4.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.4.1/LICENSE */ + function _typeof(obj) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj2) { + return typeof obj2; + } : function(obj2) { + return obj2 && "function" == typeof Symbol && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2; + }, _typeof(obj); + } + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf2(o2, p2) { + o2.__proto__ = p2; + return o2; + }; + return _setPrototypeOf(o, p); + } + function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) + return false; + if (Reflect.construct.sham) + return false; + if (typeof Proxy === "function") + return true; + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() { + })); + return true; + } catch (e) { + return false; + } + } + function _construct(Parent, args, Class) { + if (_isNativeReflectConstruct()) { + _construct = Reflect.construct; + } else { + _construct = function _construct2(Parent2, args2, Class2) { + var a = [null]; + a.push.apply(a, args2); + var Constructor = Function.bind.apply(Parent2, a); + var instance = new Constructor(); + if (Class2) + _setPrototypeOf(instance, Class2.prototype); + return instance; + }; + } + return _construct.apply(null, arguments); + } + function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); + } + function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) + return _arrayLikeToArray(arr); + } + function _iterableToArray(iter) { + if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) + return Array.from(iter); + } + function _unsupportedIterableToArray(o, minLen) { + if (!o) + return; + if (typeof o === "string") + return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) + n = o.constructor.name; + if (n === "Map" || n === "Set") + return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) + return _arrayLikeToArray(o, minLen); + } + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) + len = arr.length; + for (var i2 = 0, arr2 = new Array(len); i2 < len; i2++) + arr2[i2] = arr[i2]; + return arr2; + } + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + var hasOwnProperty$g = Object.hasOwnProperty, setPrototypeOf = Object.setPrototypeOf, isFrozen = Object.isFrozen, getPrototypeOf = Object.getPrototypeOf, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + var freeze = Object.freeze, seal = Object.seal, create = Object.create; + var _ref = typeof Reflect !== "undefined" && Reflect, apply$2 = _ref.apply, construct = _ref.construct; + if (!apply$2) { + apply$2 = function apply2(fun, thisValue, args) { + return fun.apply(thisValue, args); + }; + } + if (!freeze) { + freeze = function freeze2(x2) { + return x2; + }; + } + if (!seal) { + seal = function seal2(x2) { + return x2; + }; + } + if (!construct) { + construct = function construct2(Func, args) { + return _construct(Func, _toConsumableArray(args)); + }; + } + var arrayForEach = unapply(Array.prototype.forEach); + var arrayPop = unapply(Array.prototype.pop); + var arrayPush$1 = unapply(Array.prototype.push); + var stringToLowerCase = unapply(String.prototype.toLowerCase); + var stringToString = unapply(String.prototype.toString); + var stringMatch = unapply(String.prototype.match); + var stringReplace = unapply(String.prototype.replace); + var stringIndexOf = unapply(String.prototype.indexOf); + var stringTrim = unapply(String.prototype.trim); + var regExpTest = unapply(RegExp.prototype.test); + var typeErrorCreate = unconstruct(TypeError); + function unapply(func) { + return function(thisArg) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + return apply$2(func, thisArg, args); + }; + } + function unconstruct(func) { + return function() { + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + return construct(func, args); + }; + } + function addToSet(set2, array2, transformCaseFunc) { + transformCaseFunc = transformCaseFunc ? transformCaseFunc : stringToLowerCase; + if (setPrototypeOf) { + setPrototypeOf(set2, null); + } + var l = array2.length; + while (l--) { + var element = array2[l]; + if (typeof element === "string") { + var lcElement = transformCaseFunc(element); + if (lcElement !== element) { + if (!isFrozen(array2)) { + array2[l] = lcElement; + } + element = lcElement; + } + } + set2[element] = true; + } + return set2; + } + function clone$2(object2) { + var newObject = create(null); + var property2; + for (property2 in object2) { + if (apply$2(hasOwnProperty$g, object2, [property2])) { + newObject[property2] = object2[property2]; + } + } + return newObject; + } + function lookupGetter(object2, prop) { + while (object2 !== null) { + var desc = getOwnPropertyDescriptor(object2, prop); + if (desc) { + if (desc.get) { + return unapply(desc.get); + } + if (typeof desc.value === "function") { + return unapply(desc.value); + } + } + object2 = getPrototypeOf(object2); + } + function fallbackValue(element) { + console.warn("fallback value for", element); + return null; + } + return fallbackValue; + } + var html$1 = freeze(["a", "abbr", "acronym", "address", "area", "article", "aside", "audio", "b", "bdi", "bdo", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "content", "data", "datalist", "dd", "decorator", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "element", "em", "fieldset", "figcaption", "figure", "font", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "map", "mark", "marquee", "menu", "menuitem", "meter", "nav", "nobr", "ol", "optgroup", "option", "output", "p", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "section", "select", "shadow", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"]); + var svg$1 = freeze(["svg", "a", "altglyph", "altglyphdef", "altglyphitem", "animatecolor", "animatemotion", "animatetransform", "circle", "clippath", "defs", "desc", "ellipse", "filter", "font", "g", "glyph", "glyphref", "hkern", "image", "line", "lineargradient", "marker", "mask", "metadata", "mpath", "path", "pattern", "polygon", "polyline", "radialgradient", "rect", "stop", "style", "switch", "symbol", "text", "textpath", "title", "tref", "tspan", "view", "vkern"]); + var svgFilters = freeze(["feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence"]); + var svgDisallowed = freeze(["animate", "color-profile", "cursor", "discard", "fedropshadow", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignobject", "hatch", "hatchpath", "mesh", "meshgradient", "meshpatch", "meshrow", "missing-glyph", "script", "set", "solidcolor", "unknown", "use"]); + var mathMl$1 = freeze(["math", "menclose", "merror", "mfenced", "mfrac", "mglyph", "mi", "mlabeledtr", "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom", "mroot", "mrow", "ms", "mspace", "msqrt", "mstyle", "msub", "msup", "msubsup", "mtable", "mtd", "mtext", "mtr", "munder", "munderover"]); + var mathMlDisallowed = freeze(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]); + var text = freeze(["#text"]); + var html = freeze(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "nonce", "noshade", "novalidate", "nowrap", "open", "optimum", "pattern", "placeholder", "playsinline", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "xmlns", "slot"]); + var svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dur", "edgemode", "elevation", "end", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]); + var mathMl = freeze(["accent", "accentunder", "align", "bevelled", "close", "columnsalign", "columnlines", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lspace", "lquote", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]); + var xml = freeze(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]); + var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); + var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm); + var TMPLIT_EXPR = seal(/\${[\w\W]*}/gm); + var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); + var ARIA_ATTR = seal(/^aria-[\-\w]+$/); + var IS_ALLOWED_URI = seal( + /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i + ); + var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); + var ATTR_WHITESPACE = seal( + /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g + ); + var DOCTYPE_NAME = seal(/^html$/i); + var getGlobal = function getGlobal2() { + return typeof window === "undefined" ? null : window; + }; + var _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTypes, document2) { + if (_typeof(trustedTypes) !== "object" || typeof trustedTypes.createPolicy !== "function") { + return null; + } + var suffix = null; + var ATTR_NAME = "data-tt-policy-suffix"; + if (document2.currentScript && document2.currentScript.hasAttribute(ATTR_NAME)) { + suffix = document2.currentScript.getAttribute(ATTR_NAME); + } + var policyName = "dompurify" + (suffix ? "#" + suffix : ""); + try { + return trustedTypes.createPolicy(policyName, { + createHTML: function createHTML(html2) { + return html2; + }, + createScriptURL: function createScriptURL(scriptUrl) { + return scriptUrl; + } + }); + } catch (_2) { + console.warn("TrustedTypes policy " + policyName + " could not be created."); + return null; + } + }; + function createDOMPurify() { + var window2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal(); + var DOMPurify = function DOMPurify2(root2) { + return createDOMPurify(root2); + }; + DOMPurify.version = "2.4.1"; + DOMPurify.removed = []; + if (!window2 || !window2.document || window2.document.nodeType !== 9) { + DOMPurify.isSupported = false; + return DOMPurify; + } + var originalDocument = window2.document; + var document2 = window2.document; + var DocumentFragment = window2.DocumentFragment, HTMLTemplateElement = window2.HTMLTemplateElement, Node = window2.Node, Element = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap, NamedNodeMap = _window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap, HTMLFormElement = window2.HTMLFormElement, DOMParser2 = window2.DOMParser, trustedTypes = window2.trustedTypes; + var ElementPrototype = Element.prototype; + var cloneNode = lookupGetter(ElementPrototype, "cloneNode"); + var getNextSibling = lookupGetter(ElementPrototype, "nextSibling"); + var getChildNodes = lookupGetter(ElementPrototype, "childNodes"); + var getParentNode = lookupGetter(ElementPrototype, "parentNode"); + if (typeof HTMLTemplateElement === "function") { + var template = document2.createElement("template"); + if (template.content && template.content.ownerDocument) { + document2 = template.content.ownerDocument; + } + } + var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument); + var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML("") : ""; + var _document = document2, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName; + var importNode = originalDocument.importNode; + var documentMode = {}; + try { + documentMode = clone$2(document2).documentMode ? document2.documentMode : {}; + } catch (_2) { + } + var hooks = {}; + DOMPurify.isSupported = typeof getParentNode === "function" && implementation && typeof implementation.createHTMLDocument !== "undefined" && documentMode !== 9; + var MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, TMPLIT_EXPR$1 = TMPLIT_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE; + var IS_ALLOWED_URI$1 = IS_ALLOWED_URI; + var ALLOWED_TAGS = null; + var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text))); + var ALLOWED_ATTR = null; + var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml))); + var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, { + tagNameCheck: { + writable: true, + configurable: false, + enumerable: true, + value: null + }, + attributeNameCheck: { + writable: true, + configurable: false, + enumerable: true, + value: null + }, + allowCustomizedBuiltInElements: { + writable: true, + configurable: false, + enumerable: true, + value: false + } + })); + var FORBID_TAGS = null; + var FORBID_ATTR = null; + var ALLOW_ARIA_ATTR = true; + var ALLOW_DATA_ATTR = true; + var ALLOW_UNKNOWN_PROTOCOLS = false; + var SAFE_FOR_TEMPLATES = false; + var WHOLE_DOCUMENT = false; + var SET_CONFIG = false; + var FORCE_BODY = false; + var RETURN_DOM = false; + var RETURN_DOM_FRAGMENT = false; + var RETURN_TRUSTED_TYPE = false; + var SANITIZE_DOM = true; + var SANITIZE_NAMED_PROPS = false; + var SANITIZE_NAMED_PROPS_PREFIX = "user-content-"; + var KEEP_CONTENT = true; + var IN_PLACE = false; + var USE_PROFILES = {}; + var FORBID_CONTENTS = null; + var DEFAULT_FORBID_CONTENTS = addToSet({}, ["annotation-xml", "audio", "colgroup", "desc", "foreignobject", "head", "iframe", "math", "mi", "mn", "mo", "ms", "mtext", "noembed", "noframes", "noscript", "plaintext", "script", "style", "svg", "template", "thead", "title", "video", "xmp"]); + var DATA_URI_TAGS = null; + var DEFAULT_DATA_URI_TAGS = addToSet({}, ["audio", "video", "img", "source", "image", "track"]); + var URI_SAFE_ATTRIBUTES = null; + var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ["alt", "class", "for", "id", "label", "name", "pattern", "placeholder", "role", "summary", "title", "value", "style", "xmlns"]); + var MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML"; + var SVG_NAMESPACE = "http://www.w3.org/2000/svg"; + var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; + var NAMESPACE = HTML_NAMESPACE; + var IS_EMPTY_INPUT = false; + var ALLOWED_NAMESPACES = null; + var DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString); + var PARSER_MEDIA_TYPE; + var SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"]; + var DEFAULT_PARSER_MEDIA_TYPE = "text/html"; + var transformCaseFunc; + var CONFIG = null; + var formElement = document2.createElement("form"); + var isRegexOrFunction = function isRegexOrFunction2(testValue) { + return testValue instanceof RegExp || testValue instanceof Function; + }; + var _parseConfig = function _parseConfig2(cfg) { + if (CONFIG && CONFIG === cfg) { + return; + } + if (!cfg || _typeof(cfg) !== "object") { + cfg = {}; + } + cfg = clone$2(cfg); + PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; + transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? stringToString : stringToLowerCase; + ALLOWED_TAGS = "ALLOWED_TAGS" in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS; + ALLOWED_ATTR = "ALLOWED_ATTR" in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR; + ALLOWED_NAMESPACES = "ALLOWED_NAMESPACES" in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES; + URI_SAFE_ATTRIBUTES = "ADD_URI_SAFE_ATTR" in cfg ? addToSet( + clone$2(DEFAULT_URI_SAFE_ATTRIBUTES), + cfg.ADD_URI_SAFE_ATTR, + transformCaseFunc + ) : DEFAULT_URI_SAFE_ATTRIBUTES; + DATA_URI_TAGS = "ADD_DATA_URI_TAGS" in cfg ? addToSet( + clone$2(DEFAULT_DATA_URI_TAGS), + cfg.ADD_DATA_URI_TAGS, + transformCaseFunc + ) : DEFAULT_DATA_URI_TAGS; + FORBID_CONTENTS = "FORBID_CONTENTS" in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS; + FORBID_TAGS = "FORBID_TAGS" in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {}; + FORBID_ATTR = "FORBID_ATTR" in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {}; + USE_PROFILES = "USE_PROFILES" in cfg ? cfg.USE_PROFILES : false; + ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; + ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; + ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; + SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; + WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; + RETURN_DOM = cfg.RETURN_DOM || false; + RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; + RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; + FORCE_BODY = cfg.FORCE_BODY || false; + SANITIZE_DOM = cfg.SANITIZE_DOM !== false; + SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; + KEEP_CONTENT = cfg.KEEP_CONTENT !== false; + IN_PLACE = cfg.IN_PLACE || false; + IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1; + NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE; + if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) { + CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck; + } + if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) { + CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck; + } + if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === "boolean") { + CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements; + } + if (SAFE_FOR_TEMPLATES) { + ALLOW_DATA_ATTR = false; + } + if (RETURN_DOM_FRAGMENT) { + RETURN_DOM = true; + } + if (USE_PROFILES) { + ALLOWED_TAGS = addToSet({}, _toConsumableArray(text)); + ALLOWED_ATTR = []; + if (USE_PROFILES.html === true) { + addToSet(ALLOWED_TAGS, html$1); + addToSet(ALLOWED_ATTR, html); + } + if (USE_PROFILES.svg === true) { + addToSet(ALLOWED_TAGS, svg$1); + addToSet(ALLOWED_ATTR, svg); + addToSet(ALLOWED_ATTR, xml); + } + if (USE_PROFILES.svgFilters === true) { + addToSet(ALLOWED_TAGS, svgFilters); + addToSet(ALLOWED_ATTR, svg); + addToSet(ALLOWED_ATTR, xml); + } + if (USE_PROFILES.mathMl === true) { + addToSet(ALLOWED_TAGS, mathMl$1); + addToSet(ALLOWED_ATTR, mathMl); + addToSet(ALLOWED_ATTR, xml); + } + } + if (cfg.ADD_TAGS) { + if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { + ALLOWED_TAGS = clone$2(ALLOWED_TAGS); + } + addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc); + } + if (cfg.ADD_ATTR) { + if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { + ALLOWED_ATTR = clone$2(ALLOWED_ATTR); + } + addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc); + } + if (cfg.ADD_URI_SAFE_ATTR) { + addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc); + } + if (cfg.FORBID_CONTENTS) { + if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { + FORBID_CONTENTS = clone$2(FORBID_CONTENTS); + } + addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc); + } + if (KEEP_CONTENT) { + ALLOWED_TAGS["#text"] = true; + } + if (WHOLE_DOCUMENT) { + addToSet(ALLOWED_TAGS, ["html", "head", "body"]); + } + if (ALLOWED_TAGS.table) { + addToSet(ALLOWED_TAGS, ["tbody"]); + delete FORBID_TAGS.tbody; + } + if (freeze) { + freeze(cfg); + } + CONFIG = cfg; + }; + var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ["mi", "mo", "mn", "ms", "mtext"]); + var HTML_INTEGRATION_POINTS = addToSet({}, ["foreignobject", "desc", "title", "annotation-xml"]); + var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ["title", "style", "font", "a", "script"]); + var ALL_SVG_TAGS = addToSet({}, svg$1); + addToSet(ALL_SVG_TAGS, svgFilters); + addToSet(ALL_SVG_TAGS, svgDisallowed); + var ALL_MATHML_TAGS = addToSet({}, mathMl$1); + addToSet(ALL_MATHML_TAGS, mathMlDisallowed); + var _checkValidNamespace = function _checkValidNamespace2(element) { + var parent = getParentNode(element); + if (!parent || !parent.tagName) { + parent = { + namespaceURI: NAMESPACE, + tagName: "template" + }; + } + var tagName = stringToLowerCase(element.tagName); + var parentTagName = stringToLowerCase(parent.tagName); + if (!ALLOWED_NAMESPACES[element.namespaceURI]) { + return false; + } + if (element.namespaceURI === SVG_NAMESPACE) { + if (parent.namespaceURI === HTML_NAMESPACE) { + return tagName === "svg"; + } + if (parent.namespaceURI === MATHML_NAMESPACE) { + return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); + } + return Boolean(ALL_SVG_TAGS[tagName]); + } + if (element.namespaceURI === MATHML_NAMESPACE) { + if (parent.namespaceURI === HTML_NAMESPACE) { + return tagName === "math"; + } + if (parent.namespaceURI === SVG_NAMESPACE) { + return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName]; + } + return Boolean(ALL_MATHML_TAGS[tagName]); + } + if (element.namespaceURI === HTML_NAMESPACE) { + if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) { + return false; + } + if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) { + return false; + } + return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]); + } + if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[element.namespaceURI]) { + return true; + } + return false; + }; + var _forceRemove = function _forceRemove2(node2) { + arrayPush$1(DOMPurify.removed, { + element: node2 + }); + try { + node2.parentNode.removeChild(node2); + } catch (_2) { + try { + node2.outerHTML = emptyHTML; + } catch (_3) { + node2.remove(); + } + } + }; + var _removeAttribute = function _removeAttribute2(name2, node2) { + try { + arrayPush$1(DOMPurify.removed, { + attribute: node2.getAttributeNode(name2), + from: node2 + }); + } catch (_2) { + arrayPush$1(DOMPurify.removed, { + attribute: null, + from: node2 + }); + } + node2.removeAttribute(name2); + if (name2 === "is" && !ALLOWED_ATTR[name2]) { + if (RETURN_DOM || RETURN_DOM_FRAGMENT) { + try { + _forceRemove(node2); + } catch (_2) { + } + } else { + try { + node2.setAttribute(name2, ""); + } catch (_2) { + } + } + } + }; + var _initDocument = function _initDocument2(dirty) { + var doc; + var leadingWhitespace; + if (FORCE_BODY) { + dirty = "" + dirty; + } else { + var matches = stringMatch(dirty, /^[\r\n\t ]+/); + leadingWhitespace = matches && matches[0]; + } + if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && NAMESPACE === HTML_NAMESPACE) { + dirty = '' + dirty + ""; + } + var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty; + if (NAMESPACE === HTML_NAMESPACE) { + try { + doc = new DOMParser2().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE); + } catch (_2) { + } + } + if (!doc || !doc.documentElement) { + doc = implementation.createDocument(NAMESPACE, "template", null); + try { + doc.documentElement.innerHTML = IS_EMPTY_INPUT ? "" : dirtyPayload; + } catch (_2) { + } + } + var body = doc.body || doc.documentElement; + if (dirty && leadingWhitespace) { + body.insertBefore(document2.createTextNode(leadingWhitespace), body.childNodes[0] || null); + } + if (NAMESPACE === HTML_NAMESPACE) { + return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0]; + } + return WHOLE_DOCUMENT ? doc.documentElement : body; + }; + var _createIterator = function _createIterator2(root2) { + return createNodeIterator.call( + root2.ownerDocument || root2, + root2, + NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, + null, + false + ); + }; + var _isClobbered = function _isClobbered2(elm) { + return elm instanceof HTMLFormElement && (typeof elm.nodeName !== "string" || typeof elm.textContent !== "string" || typeof elm.removeChild !== "function" || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== "function" || typeof elm.setAttribute !== "function" || typeof elm.namespaceURI !== "string" || typeof elm.insertBefore !== "function" || typeof elm.hasChildNodes !== "function"); + }; + var _isNode = function _isNode2(object2) { + return _typeof(Node) === "object" ? object2 instanceof Node : object2 && _typeof(object2) === "object" && typeof object2.nodeType === "number" && typeof object2.nodeName === "string"; + }; + var _executeHook = function _executeHook2(entryPoint, currentNode, data) { + if (!hooks[entryPoint]) { + return; + } + arrayForEach(hooks[entryPoint], function(hook) { + hook.call(DOMPurify, currentNode, data, CONFIG); + }); + }; + var _sanitizeElements = function _sanitizeElements2(currentNode) { + var content; + _executeHook("beforeSanitizeElements", currentNode, null); + if (_isClobbered(currentNode)) { + _forceRemove(currentNode); + return true; + } + if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) { + _forceRemove(currentNode); + return true; + } + var tagName = transformCaseFunc(currentNode.nodeName); + _executeHook("uponSanitizeElement", currentNode, { + tagName, + allowedTags: ALLOWED_TAGS + }); + if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) { + _forceRemove(currentNode); + return true; + } + if (tagName === "select" && regExpTest(/