-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.json
More file actions
1 lines (1 loc) · 86 KB
/
index.json
File metadata and controls
1 lines (1 loc) · 86 KB
1
[{"authors":["admin"],"categories":null,"content":"I retired in May 2024 from my position in the Department of Statistics at the University of Florida.\n","date":1740703822,"expirydate":-62135596800,"kind":"term","lang":"en","lastmod":1740704138,"objectID":"2525497d367e79493fd32b198b28f040","permalink":"https://presnell.github.io/author/brett-presnell/","publishdate":"0001-01-01T00:00:00Z","relpermalink":"/author/brett-presnell/","section":"authors","summary":"I retired in May 2024 from my position in the Department of Statistics at the University of Florida.","tags":null,"title":"Brett Presnell","type":"authors"},{"authors":null,"categories":null,"content":"Why Is This Here? This is a placeholder for an introductory statistical computing course that I developed and taught at UF. I am retired now, but a student asked that I make the syllabus permanently available on the web as an HTML file (all the course materials are in UF\u0026rsquo;s elearning platform (Canvas), but eventually this will no longer be visible to the students).\nCourse Description An introduction to statistical computing and programming with data. Topics include basic programming in R; data types and data structures in R; importing and cleaning data; specifying statistical models in R; statistical graphics; statistical simulation using pseudo-random numbers; reproducible research and the documentation of statisical analyses.\nSyllabus And here is a printable/PDF version.\n","date":1716397200,"expirydate":-62135596800,"kind":"section","lang":"en","lastmod":1716397200,"objectID":"5b2c57a4b69c3751e0f79b3c8e80f7eb","permalink":"https://presnell.github.io/teaching/sta3100-202401/","publishdate":"2024-05-22T17:00:00Z","relpermalink":"/teaching/sta3100-202401/","section":"teaching","summary":"An introductory course in statistical computing and programming with R.","tags":null,"title":"Overview","type":"docs"},{"authors":null,"categories":null,"content":"Philosophy The course sequence STA 7466-7467 seeks to provide PhD students in statistics and closely related areas with a thorough working knowledge of measure theoretic probability. Using the concepts and methods covered in this course, statistical problems which might otherwise be treated as a series of special cases can be reduced to their essentials, faciltating rigorous and often simpler proofs of more powerful results. Mastery of these concepts and methods is thus critical for advanced work in mathematical statistics.\nSyllabus Prerequisites Basic real analysis/advanced calculus (at the level of MAA 5228, MAA 6236, or equivalent). A solid grasp of real analysis will be essential.\n Some knowledge of basic probability and mathematical statistics will be very helpful (at a minimum at the level of STA 4321-4322 or STA 5325-5328, and preferably at the level of STA 6326-6327.)\n STA 7466 is required for STA 7467.\n Please see the instructor if in doubt about the prerequisites.\nInstructor Brett Presnell Time \u0026amp; Location M, W, F, Period 8 (3:00 PM - 3:50 PM) in FLO 0230 Canvas You can find the course website in Canvas by logging into UF\u0026rsquo;s elearning website using your gatorlink username and password. The course notes, assignments, and so forth can be found there.\n","date":1536451200,"expirydate":-62135596800,"kind":"section","lang":"en","lastmod":1536451200,"objectID":"748aa7640e1459d62ae8bf03df82c19a","permalink":"https://presnell.github.io/teaching/sta7466-7467/","publishdate":"2018-09-09T00:00:00Z","relpermalink":"/teaching/sta7466-7467/","section":"teaching","summary":"The first course in a two-course sequence on measure theoretic probability.","tags":null,"title":"Overview","type":"docs"},{"authors":["Brett Presnell"],"categories":[],"content":" General Comments Our water heater is installed on the back of the house behind the laundry room. It should be descaled and flushed once a year. My target date for doing this is February 1 (the water heater was installed around the beginning of February, 2021).\n You will need a small pump (I purchased this 1/6 horsepower utility pump), a pair of washing machine hoses or similar, a garden hose, 2 gallons of distilled vinegar, a Philips screwdriver (preferably with a magnetized tip), and possibly a large set of slip-joint pliers.\n The cold water inlet is on the righthand side of the water heater; the hot water outlet is on the lefthand side; and the recirculation inlet is in the center. Note the distinction between the cold water isolation (\u0026#34;D\u0026#34; in the user\u0026#39;s manual) and service (\u0026#34;B\u0026#34;) valves and similarly between the hot water isolation (\u0026#34;C\u0026#34;) and service (\u0026#34;A\u0026#34;) valves. The service valves allow for draining and flushing the water heater while the unit is isolated from the home\u0026#39;s water supply and plumbing by closing the isolation valves.\n There is no \u0026#34;recirculation service valve\u0026#34;, but there is a pump drain port.\n Further information and diagrams can be found in the User\u0026#39;s Information Manual for Navien\u0026#39;s NPE Condensing Water Heaters. The procedure below is really just combining all the maintenance into one long procedure. See also this video, which unfortunately is done with a non-recirculating model, and this video, which is less thorough but does use a recirculating model.\n Procedure Turn off the gas valve below the water heater.\n Turn off the water heater (power button on the water heater\u0026#39;s control panel).\n Disconnect (unplug) the power supply to the water heater.\n Remove front cover. There are two screws at the bottom of the cover and two at the top. The two at the top are only accessible through the slits in the front of the top cover/lid. The hardest part of this whole job may be getting the top two screws out and then replacing them at the end.\n Remove and clean cold air intake filter located under the top cover of the water heater.\n Remove screw on/next to the \u0026#34;handle\u0026#34; of the filter.\n If necessary, loosen screw on top of water heater which may obstruct removal of air intake filter.\n Slide air intake filter out and clean with a dry toothbrush. Alternatively, clean with running water and a toothbrush, but be sure the filter is dry before you replace it.\n Replace filter and screws.\n Drain Water Heater and Clean Filters and Traps\n Close hot and cold water isolation valves.\n Close hot and cold service valves (these should already be closed).\n Close recirculation isolation valve.\n Optionally, drain hot water from taps throughout the house (I do not think that this is necessary).\n Remove caps from hot and cold water service valves and attach two washing machine hoses. Place the other ends in a 5-gallon bucket. Open both service valves to drain the water heater. (It helps to straighten the hose, keeping them running downward of course.) You may notice additional water draining into the bucket when you do the next couple of steps.\n Remove and clean the cold water inlet filter (black) next to the cold water inlet. On my water heater this filter is inserted into the bottom of the water at a 45 degree angle. Open/remove the (small black) pump drain plug and allow any residual water to drain from the water heater.\n Remove and clean the dirt trap for the condensate water clean-out. The dirt trap is white and secured with a u-shaped metal piece that you must slide out to remove the trap.\n Replace the condensate dirt trap. As mentioned in one of the videos above, you need to be sure that o-ring is properly seated. Don\u0026#39;t trust your luck on this. Use a small screw driver to reach up and retrieve the o-ring and place it properly on the trap before reinserting the trap.\n Replace/close the pump drain plug.\n Remove and clean the recirculation inlet filter (black). This is exactly the same part as the cold water inlet filter, but it screws straight into the bottom of the water heater near the recirculation inlet.\n Replace the recirculation and cold water inlet filters.\n Flush/Descale and Rinse Out Heat Exchanger\n Empty and clean a 5-gallon bucket.\n Put 2 gallons of distilled vinegar in bucket.\n Attach the free end of the hose connected to the cold water service valve to the pump and place in bucket. The pump that I purchased came with an adapter that does not change the diameter of the threads, but does change the pitch. In my experience, a washing machine hose will easily strip this adapter, so remove it first and carefully attach the washing machine hose to the pump base (it would be disastrous to strip the threads on the base itself).\n Place the free end of the hose connected to the hot water service valve in the bucket.\n Open both service valves.\n Run the pump for 45 minutes to an hour. The vinegar will be pumped into the cold water side of the water heater and return to the bucket from the hot water side.\n Disconnect the pump and allow remaining vinegar to drain from hoses into the bucket. Again, it helps to make the hoses as straight as possible.\n Close service both valves, remove hoses from service valves, and dispose of the vinegar while admiring the sediment that you have removed from your water heater.\n Replace the cap on the cold water service valve.\n Carefully attach a clean garden hose to the hot water service valve. I find that this is much easier using the adapter that came with my utility pump, so I put the adapter on first and then attach the hose to the adapter. (Whatever standards are in play here, the female side of the adapter matches the threads on the service valve and the male side matches the garden hose, both perfectly.) Put the other end of the hose somewhere that the water and any residual vinegar can drain without making a mess or doing any harm.\n Open the hot water service valve, leaving the hot water isolation valve closed. (This is important: you do not want to push the rinse solution into your house\u0026#39;s hot water lines.)\n Open the cold water isolation valve, allowing cold water to flow into the cold water side of the water heater and out through the garden hose on the hot water side. Let this run for a few minutes to flush the vinegar from the unit.\n Close the cold water isolation valve and the hot water service valve.\n Detach the garden hose and replace the cap on the hot water service valve.\n Restart Water Heater\n Make sure that all caps, parts, and filters have been replaced and replace the cover on the unit.\n Clean the outside of the unit with a damp cloth.\n Turn on the cold water isolation valve and the hot water service and isolation valves (the cold water service valve should also be open).\n Turn the gas valve back on.\n Reconnect (plug in) and restart the water heater.\n ","date":1740703822,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1740704138,"objectID":"0433038398cc7ed87a86d1ebebc1109e","permalink":"https://presnell.github.io/post/navienwaterheatermaintenance/","publishdate":"2025-02-27T19:50:22-05:00","relpermalink":"/post/navienwaterheatermaintenance/","section":"post","summary":"General Comments Our water heater is installed on the back of the house behind the laundry room. It should be descaled and flushed once a year. My target date for doing this is February 1 (the water heater was installed around the beginning of February, 2021).","tags":[],"title":"Maintenance of Navien NPE 210A Water Heater","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" These are my notes on setting up Dynamic DNS and remote SSH access to my home computer using a GigaSpire Blast u10xe, with porkbun as my domain registrar and duckdns as my DDNS provider.\nBackground We recently switched to IQ Fiber for our home internet service. They provide a GigaSpire Blast u10xe router with the service for no additional charge, and, if needed, a GigaSpire Blast u6me mesh unit. These are much newer than the two Asus RT-AC68 routers that I have been using for the past 10 years in a mesh setup, so they have more advanced Wi-Fi (802.11ax/Wi-Fi 6E vs 802.11ac/Wi-Fi 5) and naturally I am happy to use them. However, this did require me to reconfigure our home network setup, especially since I had been using Asus\u0026#39;s free, built-in DDNS service.\n Initial Router Setup Although the decal on the bottom of the router says that the internal IP address is the usual 198.162.1.1, in our case it is in fact 198.162.22.1. I discovered this by opening our IQ Fiber\u0026#39;s app on my phone and going to \u0026#39;My Network \u0026gt; Equipment \u0026gt; Brett\u0026#39;s Router \u0026gt; Additional Details\u0026#39; and noting the LAN IP adress.\n By opening 192.168.22.1 in a web browser, one gains access to the interface of the router. IQ Fiber gave me the initial password, which this should be changed when you first login to the router\u0026#39;s web interface. (Just don\u0026#39;t lose the password once you change it.) You can create a backup of your router\u0026#39;s setup by going to Utilities \u0026gt; Backup \u0026amp; Restore. You may wish to do this from time to time to avoid having to redo your work if anything goes wrong.\nWi-Fi Our Wi-Fi SSID (wifi network name) and WPA password were set during the installation. Keeping these the same as they were with your previous router avoids needing to change this information on all your Wi-Fi clients (e.g., your mobile phones, laptops, tablets, TV sticks, etc). The SSID and WPA password can be changed under the web interface if desired by choosing Wi-Fi \u0026gt; Primary Network.\n I also turned on 802.11ax under the Wi-Fi \u0026gt; Radio \u0026gt; 5GHz Radio.\n Advanced \u0026gt; IP Address \u0026gt; DHCP Settings I have a domain name registered with Porkbun to use for our home network. I don\u0026#39;t have any reason to advertise the actual domain, so let\u0026#39;s just call it mydomain.net. I like to set our internal domain name to match this name, so I entered mydomain.net in the Domain Name box. I left the Host Name as router.\n While you\u0026#39;re here, you may wish to note the beginning and ending IP addresses. These will describe the range of internal IP addresses that may be assigned to devices on your LAN (local area network).\n DHCP Reservation and DNS Host Mapping By selecting Status \u0026gt; Devices you can see the various devices connected to your network. If you are not sure what some of these devices are, you can paste their MAC Address into this MAC address lookup tool to find the manufacturer, which often helps to narrow down your search.\n Note that by default local IP addresses are assigned more-or-less randomly to your devices within the allowed range and the local IP address may change anytime that the device is disconnected and reconnected to the network (including when the router is rebooted). Local IP addresses that change are generally not an issue, but for some devices I like to have a fixed IP and a hostname that I can remember to refer to them by.\n To assign a fixed IP address to a device or devices, use Advanced \u0026gt; IP Address \u0026gt; DHCP Reservation.\n Having done this, you can assign hostnames to those devices with Advanced \u0026gt; IP Address \u0026gt; DNS Host Mapping. I would suggest assigning hostnames only to devices to which you have assigned a fixed IP address — otherwise I would be concerned that your hostname could end up pointing to an unexpected device, or to nothing at all.\n Setting Up Dynamic DNS Your home network\u0026#39;s IP address in the broader internet outside your home (this is basically what is referred to as your wide area network, or WAN) is assigned by your internet provider and it can change at any time. This is not an issue unless you wish to access your home network from the outside. I mainly do this for remote access to my desktop computer via the secure shell (SSH) protocol, but you could, for example, host a public-facing web server on a home computer (if your internet provider allowed it), or you might want access to manage your home network when you are not at home.\n In any case, what is needed to enable reliable and convenient remote access is a domain name and a way of automatically updating the IP address to which this domain name points. The updating mechanism is referred to as DDNS (Dynamic Domain Name System). There are many ways to set up DDNS using an always-on local computer, but I think that it is more convenient to take advantage of the router\u0026#39;s pre-defined functionality for interacting with a large numer of DDNS providers.\n Our current domain name registrar is Porkbun, so these notes are specific in places to Porkbun. Porkbun has an API (application programming interface) which can be accessed to set up DDNS with other software, but they do not provide their own DDNS service and the router does not have any built in functionality for porkbun, so I decided to use Duck DNS for that. It is free and seems to work well enough for my purposes.\n You could purchase a new domain name for Porkbun, or transfer an existing domain name from another registrar to porkbun if you wished. However, I\u0026#39;m fairly certain that you could do what is needed here with any domain name registrar, and some registrars may also provide DDNS services for your domain, which might save some steps. (At one time our domain name was registered with Google, who did provide DDNS as well, but they shut down their domain registration business a few years ago.)\n Here are the steps for setting up DDNS:\n Login to Duck DNS using one of the available methods (I logged in with my google account). Once you are logged in, you will see a \u0026#34;domains\u0026#34; box. Enter some domain name, probably something that matches your actual domain name fairly closely, e.g., mydomain.duckdns.org.\n Note at the top of the webpage your account name (this will reflect whatever you used to login, e.g., your google account) and the long, random token. You will need these in the next step. In the browser interface to the router, choose Advanced \u0026gt; IP Address \u0026gt; Dynamic DNS. Under the IPv4 tab, enable DDns State. Then set:\n \u0026#34;Service Provider\u0026#34; to duckdns.org\n \u0026#34;Username\u0026#34; to your duckdns account name\n \u0026#34;Password or Token\u0026#34; to the token from your duckdns account\n DDns Hostname to the hostname you setup in duckdns, e.g., mydomain.duckdns.org\n and click on the Apply button.\n This will make mydomain.duckdns.org point to your home network (you can check this by clicking on the external link icon next to the domain name; this should open the interface to your router). Now all we have to do is go to porkbun and make mydomain.net point to mydomain.duckdns.org.\n Login to your porkbun account. In the ACCOUNT menu at the top right, choose DOMAIN MANAGEMENT (you may already be on the domain management page). By hovering over mydomain.net (or by first clicking on the Details box), you will see DNS in small print just below the domain name. Click on DNS fill in the fields as follows:\n Set Type to \u0026#34;ALIAS - CNAME flattening record\u0026#34;.\n Leave Host blank.\n Set Answer to the domain name from duckdns, e.g., mydomain.duckdns.org.\n Click the Add box.\n This should finish the process. Opening mydomain.net in a web browser should now take you to your router\u0026#39;s interface.\n Port Forwarding for SSH In a previous step, I set a fixed internal IP address (say, 192.168.22.10) for my desktop computer and gave it a hostname, say, mydesktop.\n I have an SSH (secure shell) server installed and running on my desktop computer (this is easily done). Among other things, this allows me to securely login to my desktop from another computer using the ssh command and to transfer files to and from my desktop computer from another computer using the scp command.\n I do not need to use SSH to access any other device on my home network (if I did, I would just access them through my desktop computer), so I want to set things up so that an ssh request to mydomain.net is routed to my desktop.\n By default an SSH server listens on port 22 on a computer\u0026#39;s network interface. Because this is the standard, hackers are likely to try to access SSH via port 22 on your router. To thwart this sort of attempt, we simply use a different port number on the routers WAN interface for SSH, one that hackers are unlikely to guess. Port numbers 49152 to 65535 are private ports that will not generally be used by any services, so we are free to use them as we wish. By choosing a port number at random from this range, say, 59517, and using it for ssh access to our network, we can prevent hackers from pestering our computer with attempted ssh logins on port 22.\nRouter Setup To set this up on the router, select Advanced \u0026gt; Security \u0026gt; Port Forwarding in the router\u0026#39;s browser interface and click the New button. Complete the fields as follows:\n Under Local Port and IP\n Set Device to the desktop computer running the ssh server that you wish to be able to login to.\n Leave Protocol as TCP.\n Set Port Start and Port End to 22 (this refers to the port reserved for the SSH service on the desktop computer).\n Under Remote IP select All IP Addresses (this could be set up differently, but this is good enough for my purposes).\n Under WAN Ports set Port Start and Port End to a randomly chosen port number from the range 49512 to 65535, e.g., 59517.\n Click Apply.\n Client Setup Now, as long as the ssh server is installed and running on our desktop computer and listening on the default port 22, we can login to it with a command like\nssh -p 59517 mydomain.net where we have specified the port number on the router with the \u0026#34;-p\u0026#34; option. Because of our port forwarding setup, this request is redirected from port 59517 on the router to port 22 on our desktop computer.\n To eliminate the need to remember this port number, we may want to save the relevant information in an SSH config file on our client computer, e.g., on a laptop or other remote computer. On a linux machine, this will be the file config in your .ssh directory. You could edit the file to look something like this (the ForwardX11 line is pretty UNIX/linux specific, so you might want to leave that out if you\u0026#39;re a windows user):\nHost myhomecomputer Hostname mydomain.net User myusername Port 59517 ForwardX11\tyes Now we can login remote by typing\nssh myhomecomputer Windows users might want to use similar ideas to set up port forwarding for Windows Remote Desktop (RDP), which can then be securely accessed through an SSH tunnel. See this article for some background.\n ","date":1728726936,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1728833119,"objectID":"4962748e7aa32765ff9f6e3793a9d84a","permalink":"https://presnell.github.io/post/homenetwork/","publishdate":"2024-10-12T05:55:36-04:00","relpermalink":"/post/homenetwork/","section":"post","summary":"These are my notes on setting up Dynamic DNS and remote SSH access to my home computer using a GigaSpire Blast u10xe, with porkbun as my domain registrar and duckdns as my DDNS provider.","tags":[],"title":"My Home Router Setup","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" Most college basketball fans probably know that no one has ever submitted a perfect NCAA tournament bracket (the longest verified streak ever ended 49 games into the 2019 tournament). This is largely due to the astronomically large number of possible outcomes of the tournament, although things are not as bad as mere counting would lead you to believe.\nCounting Brackets A Primer: The Number of Possible Brackets for an Eight-Team Tournament I think it\u0026#39;s easiest to understand the counting part of this by first considering a tournament with only 8 teams (A, B, C, D, E, F, G, H) and hence three rounds:\n quarterfinals with 4 games (A vs B, C vs D, E vs F, and G vs H)\n semifinals with 2 games (winner of A vs B against winner of C vs D and winner of E vs F against winner of G vs H)\n final with 1 game (winner of the ABCD group against winner of the EFGH group)\n For each game in the quarterfinals, you can choose either of the two teams, giving you \\[ 2 \\times 2 \\times 2 \\times 2 = 2^4 = 16 \\] possible ways to pick the winners of the quarterfinal games (ACEG, ACEH, ACFG, ACFH, ADEG, ADEH, ADFG, ADFH, BCEG, BCEH, BCFG, BCFH, BDEG, BDEH, BDFG, and BDFH).\n No matter which 4 teams you pick to win in the quarterfinals, you can choose either of 2 teams in each of the 2 semifinal games, so you have \\(2 \\times 2 = 2^2 = 4\\) possible choices. For example, if you chose A, C, E, and G to win their quarterfinal games, then your possibilities would be AE, AG, CE, and CG. But you have 4 possible choices no matter which of the 16 sets of teams you picked in the first round, so there are \\(16 \\times 4 = 64\\) possible ways to fill out the first two rounds (quarterfinals and semifinals).\n No matter which teams you picked to win in the quarterfinals and semifinals, you can choose either of your two semifinal winners to win the final game. Thus, no matter which of the 64 possible ways you chose to fill in the quarterfinal and semifinal rounds, you have 2 possible ways to finish your bracket, leaving you with a total of \\(64 \\times 2 = 128\\) possible ways to fill in the complete bracket.\n Notice that there were 4 games in the first round, 2 games in the second round, and 1 game in the final round, for a total of 7 games, and the number of possible brackets turned out to be \\[ 2^4 \\times 2^2 \\times 2^1 = 2^{(4 + 2 + 1)} = 2^7 = 128. \\]\n So How Many Brackets are Possible for the 64 Team NCAA Tournament? Now, considering the real March Madness tournament, if we ignore the play-in games, there are 63 games in the tournament: 32 first round games, 16 second round games, 8 \u0026#34;Sweet 16\u0026#34; games, 4 \u0026#34;Elite 8\u0026#34; games, 2 \u0026#34;Final Four\u0026#34; games, and 1 championship game (32 + 16 + 8 + 4 + 2 + 1 = 63). Following the same logic as we did for the eight-team tournament:\n You could pick either of the two teams in each of the 32 first round games, so altogether there are \\(2^{32} = \\text{4,294,967,296}\\) possible sets of winners you could pick for the first round.\n Similarly, for whatever set of 32 teams you picked to win the first round games, there are \\(2^{16} = \\text{65,536}\\) different sets of teams that you could to win their 2nd round games, so by the time you fill in your teams for the first 2 rounds, you have chosen 1 of \\(2^{32} \\times 2^{16} = 2^{48} = \\text{281,474,976,710,656}\\) possibilities.\n Continuing in this way, we find that there are \\[ 2^{32} \\times 2^{16} \\times 2^8 \\times 2^4 \\times 2^2 \\times 2^1 = 2^{63} \\] possible ways to fill in your bracket. That\u0026#39;s \\[ 2^{63} = \\text{9,223,372,036,854,775,808} \\] or roughly 9 quintillion (a quintillion is a billion billion).\n So, if you flipped a coin to pick your team in each of the 63 games, meaning that you picked your bracket completely at random from among the 9 quintillion possibilities, then the probability that you would pick the perfect bracket for that year\u0026#39;s tournament would be 1 in 9 quintillion.\n For comparision, Florida currently suffers about 5 lightning deaths per year.1 The population of Florida is currently around 22 million, so if we assume an average of only 4.9 deaths due to lightning per year, then probability that a randomly chosen Floridian would be killed by lightning in the next year is roughly 1 in 22/4.9 = 4.5 million. Thus, a randomly chosen Floridian has a 2 trillion (2,000,000,000,000) times greater chance of being killed by lightning next year than a randomly chosen bracket has of being perfect.\n However, the 1 in 9 quintillion probability of choosing a perfect bracket is only correct if you randomly choose your bracket by flipping a fair coin 63 times, and of course no one picks their bracket this way.\n So What\u0026#39;s the Actual Probability of Picking a Perfect Bracket? If you didn\u0026#39;t have any personal opinion at all about the relative strengths of the teams, and if you weren\u0026#39;t concerned about competing with other bracket pickers for a prize, then it would be much better to just pick the higher seeded team to win each game, leaving you to decide only which of the 1 seeds you prefer in the semifinal and final games (there are \\(2^3 = 8\\) ways you could choose the winners of these last 3 games). The probability that the tournament will go completely \u0026#34;by the chalk\u0026#34; and give you a perfect bracket is still vanishingly small, but it\u0026#39;s bigger than 1 in 9 quintillion.\n For example, in 2023, I would have estimated the probability that this \u0026#34;chalk\u0026#34; method would yield a perfect bracket to be somewhere between 1 in 291 billion and 1 in 84 billion, depending on which teams you chose to win the final three games. Those are still extremely small probabilities, and our randomly chosen Floridian is still somewhere between 19,000 and 65,000 times more likely to die from a lightning strike in the coming year, but the chalk method is a lot better than flipping coins.\n Other Notes on Perfect Brackets Why You Probably Shouldn\u0026#39;t Choose a Completely by the Chalk Bracket for Your Pool If you are competing in a bracket pool, then your objective is to maximize your expected winnings. This is not the same as choosing your bracket to maximize your chances of being perfect (which is practically impossible anyway), and it\u0026#39;s not even the same as maximizing your expected final \u0026#34;score\u0026#34;. For example, picking the higher seeded team to win every game is generally not a good strategy, because lots of other people will do the same, or close to it, so even if you did win, you would probably split the pot with a lot of other players.\n How Did I Estimate the Probability that a \u0026#34;By the Chalk\u0026#34; Bracket is Perfect? If you have a way to estimate the probability that team A wins over team B in any potential matchup in the tournament, then you can estimate the probability that a given bracket turns out to be perfect in a given year. Many of the \u0026#34;power ratings\u0026#34; that are provided by various sites on the web can be used to estimate the needed probabilities, although the sites don\u0026#39;t usually tell you how to do it. For the calculation I did above for the 2023 tournament, I used the team ratings from FiveThirtyEight.com. Unfortunately these won\u0026#39;t be available anymore due to cutbacks at Disney/ABC, so I\u0026#39;ll have to use something else for 2024.\n What About the Play-in Games? Note: If you have to pick the 4 play-in games as well, then you have to pick the winners of \\(63 + 4 = 67\\) games, so in this case there are \\[ 2^{67} = \\text{147,573,952,589,676,412,928} \\] possible brackets, and the probability that a bracket chosen by flipping coins turns out perfect is about 1 in 148 quintillion.\n What\u0026#39;s My Interest in All of This? Since at least the early 2000\u0026#39;s I have participated in a nonstandard March Madness pool with some other statisticians and computer scientists, as well as some \u0026#34;civilians\u0026#34;. I started thinking more seriously about it in the 2010\u0026#39;s, and in 2016 I got an idea for how I might choose multiple entries in such a way as to maximize my chances of winning the pool. This led to me simulating the March Madness tournament on my home computer and using the outcomes to help me make my selections. My methods have evolved over the years and these days I run hundreds of thousands, and even millions of simulations of the tournment to generate training and test sets for choosing my picks and evaluating how well they are likely to perform. Almost every year I have ideas for improvements that I frantically implement and test out at the last minute so that I can submit my picks before the tournament begins.\n At least one other pool participant started doing similar things soon after me. He leads a large-scale optimization research team at Google. We\u0026#39;ve been successful enough that we decided to split the pool into two pools to be fair to those who choose their teams manually.\n Footnotes 1 From 1959-2010 the average number of Florida lightning deaths was nearly 9/year (and the population of the was much smaller during most of that time), so the rate was much higher. It seems to have decreased due to improved forcasting and broader awareness of lightning safety practices, although an average of 7/year is also cited by some sources. Remarkably, \u0026#34;only about 10% of people who are struck by lightning are killed, leaving 90% with various degrees of disability,\u0026#34; so presumably the chances of getting struck by lighting are much higher than the chances of getting killed by lightning. I\u0026#39;ll leave it to you to decide if that\u0026#39;s good or bad news.\n ","date":1708495921,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1709587608,"objectID":"59ca54ba12ba7ec2ce142811ed48de2a","permalink":"https://presnell.github.io/post/perfectbracket/","publishdate":"2024-02-21T01:12:01-05:00","relpermalink":"/post/perfectbracket/","section":"post","summary":"Most college basketball fans probably know that no one has ever submitted a perfect NCAA tournament bracket (the longest verified streak ever ended 49 games into the 2019 tournament).","tags":[],"title":"The Lore of the Perfect Bracket","type":"post"},{"authors":null,"categories":null,"content":"The morons betting league (MBL2) is a small informal group of friends (morons) who compete every week by picking ten football bets (NCAAF and NFL) totaling 100 \u0026ldquo;units\u0026rdquo; against the spread and/or over-under Here\u0026rsquo;s a small sample of the data. Note that\n The players (morons) are represented by one-letter codes. Some weeks may not have happened yet, so you may see a lot of missing (NA) data. There is one exceptional (bowl) week where the morons place 20 bets totalling 200 units. Note also that one moron placed 10 bets totalling 200 units that week, which is technically against the \u0026ldquo;rules\u0026rdquo; of the MBL. mia is an indicator of whether the moron failed to enter their picks. According to the MBL2 \u0026ldquo;rules\u0026rdquo; a player is allowed to have one missed week replaced by their score from the subsequent week. The \u0026ldquo;rules\u0026rdquo; do not specify what happens if the week missed or the week following the week missed is the 20-bet week. The listing of the teams/games and the line is very irregular because these are emailed and entered by hand with no standardization. For this reason, the league inforamtion (NCAAF vs NFL) is also unavailable. So the only useful data are the moron, week, number of units wagered, and number of units won. Code mbl |\u0026gt; select(-cells) |\u0026gt; slice_sample(n = 10) |\u0026gt; arrange(week, moron) # A tibble: 10 × 7 moron week mia team_s line wager units_won \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;lgl\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; 1 K 0 FALSE uscar 2.5 10 0 2 P 3 FALSE FSU @ CLEM OVER 55.0 10 5 3 P 3 FALSE NE @ NYJ NYJ +3.0 10 0 4 P 7 FALSE (17) Duke at (4) Florida State FSU -13.5 20 20 5 D 8 FALSE Horns -17.5 20 20 6 W 9 FALSE kssu/UTEX \u0026gt;50.5 10 10 7 K 11 FALSE MIA -11.5 10 0 8 S 11 FALSE Clemson -6.5 10 10 9 D 14 FALSE Army -2.5 10 10 10 S 17 FALSE LV 3 10 5 The next bit of code creates a result column (win, lose, or push) the wager and units_won columns.\n Code mbl \u0026lt;- mbl |\u0026gt; mutate( result = (units_won == wager) - (units_won == 0) + 2, result = ifelse(is.na(result), 4, result), result = c(\u0026quot;lose\u0026quot;, \u0026quot;push\u0026quot;, \u0026quot;win\u0026quot;, NA)[result]) The next bit of code creates a summary data frame of results by moron and week. It uses tidyr::fill() to backfill the units won for weeks where mia == TRUE. The variable units_won10 adjusts the number of units won to a 10-bet basis, in order to standardize the 20-bet bowl week to match the other weeks.\n Code mbl_by_moron_week \u0026lt;- mbl |\u0026gt; summarize( n_bets = n(), wins = sum(result == \u0026quot;win\u0026quot;), losses = sum(result == \u0026quot;lose\u0026quot;), pushes = sum(result == \u0026quot;push\u0026quot;), units_won = sum(units_won), .by = c(moron, week, mia) ) |\u0026gt; ## Handle MIA weeks with tidyr::fill(). arrange(moron, week) |\u0026gt; # Making sure that observations are ordered correctly. group_by(moron) |\u0026gt; # Grouping means filling done only within group (by moron). fill(units_won, .direction = \u0026quot;up\u0026quot;) |\u0026gt; ungroup() |\u0026gt; filter(!is.na(units_won)) |\u0026gt; mutate(units_won10 = (10/n_bets) * units_won) |\u0026gt; mutate(season_total = cumsum(units_won), .by = moron) Here are some quantiles of the weekly units won (10-bet basis) by the morons. This is an attempt to determine what constitutes a good or bad weekly total.\n Code mbl_by_moron_week |\u0026gt; pull(units_won10) |\u0026gt; quantile(probs = seq(0.1, 0.9, by = 0.1)) 10% 20% 30% 40% 50% 60% 70% 80% 90% 30 40 40 45 50 57 60 67 75 And here is a histogram of the same information.\n Code ## Histogram of weekly units won by the morons. mbl_by_moron_week |\u0026gt; ggplot(aes(x = units_won10)) + geom_histogram(binwidth = 10) This is a line plot of the moron\u0026rsquo;s season totals by week.\n Code mbl_by_moron_week |\u0026gt; ggplot(aes(x = week, y = season_total, color = fct_reorder2(moron, week, season_total))) + geom_line(linewidth = 1) + labs(color = \u0026quot;moron\u0026quot;, x = \u0026quot;Week\u0026quot;, y = \u0026quot;Season Total\u0026quot;) How many weeks has each moron been one of the top scorers?\n Code mbl_by_moron_week |\u0026gt; group_by(week) |\u0026gt; mutate( week_max = max(units_won), top_scorer = (units_won == week_max) ) |\u0026gt; ungroup() |\u0026gt; filter(top_scorer) |\u0026gt; summarize(n = n(), .by = moron) |\u0026gt; arrange(desc(n)) # A tibble: 6 × 2 moron n \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; 1 H 5 2 K 5 3 W 5 4 P 4 5 S 4 6 D 3 Which moron\u0026rsquo;s weekly totals (10-bet basis) are the most (and least) variable (ordered by standard deviation)?\n Code mbl_by_moron_week |\u0026gt; summarize(mean = mean(units_won10), sd = sd(units_won10), median = median(units_won10), mad = mad(units_won10), .by = moron) |\u0026gt; arrange(desc(sd)) # A tibble: 6 × 5 moron mean sd median mad \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; 1 W 51.8 20.2 50 14.8 2 K 49.6 18.3 50 22.2 3 P 56.2 16.1 55 22.2 4 H 51.4 16.1 50 14.8 5 D 55.7 15.6 55 22.2 6 S 49.9 14.6 40 7.41 Which moron\u0026rsquo;s weekly totals are the most (and least) variable (ordered by median absolute deviation)? Using knitr::kable() here for a prettier table, but I\u0026rsquo;m getting misaligned column headers. I may report this as a bug.\n Code mbl_by_moron_week |\u0026gt; summarize( mean = mean(units_won10), sd = sd(units_won10), median = median(units_won10), mad = mad(units_won10), .by = moron) |\u0026gt; arrange(desc(mad), desc(sd)) |\u0026gt; kable() moron mean sd median mad K 49.60526 18.33832 50 22.239 P 56.18421 16.12384 55 22.239 D 55.65789 15.63121 55 22.239 W 51.84211 20.22172 50 14.826 H 51.44737 16.07957 50 14.826 S 49.86842 14.63618 40 7.413 Overall number of winning, losing, and pushed wagers for each moron. The stated win percentage counts pushes as half a win.\n Code mbl |\u0026gt; filter(!is.na(result)) |\u0026gt; summarize(n = n(), .by = c(moron, result)) |\u0026gt; pivot_wider(names_from = result, values_from = n, values_fill = 0) |\u0026gt; mutate( n = win + push + lose, win_pct = 100 * (win + 0.5*push) / n) |\u0026gt; relocate(n, win, lose, push, .after = moron) |\u0026gt; arrange(desc(win_pct)) # A tibble: 6 × 6 moron n win lose push win_pct \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; 1 P 200 109 88 3 55.2 2 D 200 108 88 4 55 3 W 200 103 96 1 51.8 4 S 200 98 97 5 50.2 5 H 190 91 94 5 49.2 6 K 180 84 92 4 47.8 Do these morons know what they\u0026rsquo;re doing when they wager different amounts? The overall number of winning, losing, and pushed wagers by units wagered.\n Code mbl |\u0026gt; filter(!is.na(result)) |\u0026gt; summarize(n = n(), .by = c(wager, result)) |\u0026gt; pivot_wider(names_from = result, values_from = n, values_fill = 0) |\u0026gt; mutate( n = win + push + lose, win_pct = 100 * (win + 0.5*push) / n) |\u0026gt; relocate(n, win, lose, push, .after = wager) |\u0026gt; arrange(wager) # A tibble: 4 × 6 wager n win lose push win_pct \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; 1 5 104 51 50 3 50.5 2 10 996 507 472 17 51.8 3 15 16 4 11 1 28.1 4 20 54 31 22 1 58.3 The overall percentages of winning, losing, and pushed wagers by units wagered.\n Code mbl |\u0026gt; filter(!is.na(result)) |\u0026gt; summarize(n = n(), .by = c(wager, result)) |\u0026gt; pivot_wider(names_from = result, values_from = n, values_fill = 0) |\u0026gt; mutate( n = win + push + lose, win = 100*win/n, push = 100*push/n, lose = 100*lose/n ) |\u0026gt; relocate(n, win, lose, push, .after = wager) |\u0026gt; arrange(wager) # A tibble: 4 × 5 wager n win lose push \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; 1 5 104 49.0 48.1 2.88 2 10 996 50.9 47.4 1.71 3 15 16 25 68.8 6.25 4 20 54 57.4 40.7 1.85 The overall percentages of wining, losing, and pushed wagers by units wagered for the individual morons. Note that some morons only ever bet in 10-unit increments.\n Code mbl |\u0026gt; filter(!is.na(result)) |\u0026gt; summarize(n = n(), .by = c(moron, wager, result)) |\u0026gt; pivot_wider(names_from = result, values_from = n, values_fill = 0) |\u0026gt; mutate( n = win + push + lose, win_pct = 100 * (win + 0.5*push) / n) |\u0026gt; relocate(n, win, lose, push, .after = wager) |\u0026gt; arrange(moron, wager) |\u0026gt; print(n = Inf) # A tibble: 17 × 7 moron wager n win lose push win_pct \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; 1 D 5 17 6 10 1 38.2 2 D 10 174 99 72 3 57.8 3 D 15 1 0 1 0 0 4 D 20 8 3 5 0 37.5 5 H 5 40 17 21 2 45 6 H 10 128 63 62 3 50.4 7 H 15 4 1 3 0 25 8 H 20 18 10 8 0 55.6 9 K 5 6 3 3 0 50 10 K 10 161 74 84 3 46.9 11 K 20 13 7 5 1 57.7 12 P 5 41 25 16 0 61.0 13 P 10 133 70 61 2 53.4 14 P 15 11 3 7 1 31.8 15 P 20 15 11 4 0 73.3 16 S 10 200 98 97 5 50.2 17 W 10 200 103 96 1 51.8 ","date":1704999946,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1704999946,"objectID":"774e5de3a1b8670174a8e164450ce6c1","permalink":"https://presnell.github.io/talk/mbl/","publishdate":"0001-01-01T00:00:00Z","relpermalink":"/talk/mbl/","section":"talk","summary":"The morons betting league (MBL2) is a small informal group of friends (morons) who compete every week by picking ten football bets (NCAAF and NFL) totaling 100 \u0026ldquo;units\u0026rdquo; against the spread and/or over-under Here\u0026rsquo;s a small sample of the data.","tags":null,"title":"MBL2 2023: A Closer Look","type":"talk"},{"authors":["Brett Presnell"],"categories":[],"content":" Background I\u0026#39;ve been reading and sending email with GNU Emacs since about 1991. In that time I have used at least five different emacs email clients: MH-E, VM, Mew, gnus, and now mu4e. I have also adapted to many different email server setups, and I have helped many of my current and especially my former colleagues do the same.\n Some years ago now our departmental email server was shut down and our email moved to a Microsoft Exchange server. The Exchange IMAP server (used for reading email) in conjunction with gnus was so slow that it was unusable, so I switched to a combination of the mu4e emacs client with a local maildir store kept in sync with the server by offlineimap. I was serving as department chair at the time and the super fast search provided by mu was really nice to have with all the email that comes with that position.\n A few years ago the university decided to completely outsource its email services to Microsoft, so I configured offlineimap to retrieve my email from outlook.office365.com. This posed no problems until recently, when Microsoft deprecated the “Basic Auth” protocol for checking email in favor of “Modern Auth” (oath2) and I was once again forced lose a long weekend adapting to a new email setup.\n I admit that I am trying to do all this while minimizing the number of things that I actually have to understand about how any of these protocols work. I spent way too much of my earlier life setting up departmental email servers and clients before finally swearing off ever doing that again, and I have spent a great deal of time in the intervening years adapting to changing email environments and helping colleagues to do the same. At this point in my life I am completely uninterested in how any of this works beyond what is absolutely required for me to use it — I just want to continue to read and write work email in the same development environment (emacs) that I use for everything else.\n Slightly More Technical Background There are two parts to this problem: retrieving and syncing email with Microsoft\u0026#39;s IMAP server, which I have been doing with offlineimap; and sending email messages via Microsoft\u0026#39;s SMTP (Symmetric Mail Transport Protocol) server, which I have been doing for many years with emacs\u0026#39;s built-in sendmail code. There do exist emacs packages named oauth2, auth-source-xoauth2, and oauth2-request, but I didn\u0026#39;t get very far with any of them and they wouldn\u0026#39;t help me on the IMAP side, because I use an external program (offlineimap) for that interaction (and having become used to mu4e I\u0026#39;m not going back to gnus).\n So, I needed (1) to find another way to send email that works with oauth2, and (2) to either configure offlineimap to work with oauth2 or find another program to handle interactions with the IMAP server. For sending email messages, the most commonly used sendmail replacement seems to be msmtp, so I planned to use that, assuming that I could configure it to use oauth2. (If you don\u0026#39;t know, the actual sending of messages is traditionally handled separately from reading and managing messages and folders.)\n BTW, to retrieve/sync and send email via Microsofts servers with oauth2, one must have a registered \u0026#34;client app\u0026#34;. There is a mechanism for registering such an app with Microsoft Azure (whatever that is), but this failed for me because my institution does not allow me (or anyone?) to register a new app. This means that I must do what everyone else apparently does, which is to use the client ID and secret for Mozilla\u0026#39;s Thunderbird email client (there\u0026#39;s actually nothing secret about these and you will see them below).\n Early on in my search for a solution, I tried M365-IMAP (python) to handle the authentication. I was able to make it work with offlineimap, but the authorization token or tokens have to be updated periodically (every hour or so?). I also don\u0026#39;t want to be storing them in a clear text file, so the barebones usage outlined there won\u0026#39;t work for me. Still, at a minimum, this is a good way to retrieve some actual authentication tokens to experiment with.\n I also tried mailctl and I got it to work with msmtp but not with offlineimap. I tried another method, but the initial authentication step (which uses a browser) wouldn\u0026#39;t work for me because all the graphics (buttons) for my institutions login page didn\u0026#39;t show up, leaving me unable to complete the 2-factor authentication. (I think I was trying either email-oauth2-proxy or oauth-helper-office-365 when I ran into this problem.)\n I finally came across Larie Tratt\u0026#39;s pizauth and this actually seems to work for me and takes care of any worries about storing any authentication details on disk. However, I didn\u0026#39;t manage to get it working with offlineimap (I\u0026#39;m sure that\u0026#39;s on me), so I decided to switch over to isync/mbsync, which I was already aware of as a faster alternative to offlineimap. The rest of this describes the process of getting this working on Ubuntu 22.04 (LTS), a.k.a., \u0026#34;Ubuntu Jammy\u0026#34;.\n Setting Up pizauth First we need a Rust compiler. For this, just go to the Getting Started page for rust and follow the instructions to use the Rustup tool to install Rust. This will install a personal copy of rust in your home directory (as opposed to a system-wide installation). Then add the following lines to your ~/.profile (or wherever you keep your shell startup stuff):\nsource ~/.cargo/env You may need to reload your .profile (or your .bashrc) or just log out and log back in again to get the rust compiler on your path.\n Next download pizauth either from Laurie Tratt\u0026#39;s web pages or from the Github repository and untar/unzip it if necessary. I was able to compile the program with make but sudo make install failed because sudo doesn\u0026#39;t have the Rust compiler on it\u0026#39;s path. To fix this, I edited the Makefile and changed these lines\ninstall: cargo build --release install -d ${PREFIX}/bin ... to\ninstall: # cargo build --release install -d ${PREFIX}/bin ... This works becuase the cargo build --release step is already done when you run make (without sudo) to compile the program, so it can safely be left out of the installation step. (For reference, cargo is the Rust package manager.)\n So again, after this edit, just run the following commands to compile pizauth and install it in /usr/local.\ncd pizauth-0.1.0 make sudo make install I next created the file ~/.config/pizauth.conf, whose contents are given below. The client_id and client_secret are actually for thunderbird, but this works. For your own use you may want to change \u0026#34;UF\u0026#34; to something else (e.g., \u0026#34;work\u0026#34;) and you will have to replace my email address with your own on the login_hint line.\naccount \u0026#34;UF\u0026#34; { auth_uri = \u0026#34;https://login.microsoftonline.com/common/oauth2/v2.0/authorize\u0026#34;; token_uri = \u0026#34;https://login.microsoftonline.com/common/oauth2/v2.0/token\u0026#34;; client_id = \u0026#34;08162f7c-0fd2-4200-a84a-f25a4db0b584\u0026#34;; client_secret = \u0026#34;TxRBilcHdC6WGBee]fs?QR:SJ8nI[g82\u0026#34;; scopes = [ \u0026#34;https://outlook.office365.com/IMAP.AccessAsUser.All\u0026#34;, \u0026#34;https://outlook.office365.com/SMTP.Send\u0026#34;, \u0026#34;offline_access\u0026#34; ]; // You don\u0026#39;t have to specify login_hint, but it does make // authentication a little easier. login_hint = \u0026#34;presnell@ufl.edu\u0026#34;; } Next run\npizauth server You shouldn\u0026#39;t see any output from this. Assuming that all has gone well to here, run (again, change UF to whatever you used for the account name in your pizauth.conf file.\npizauth show UF The first time you do this a URL will be output. Copy this URL and open it in your browser and do whatever is needed to authenticate with your institution (if your browser is already authenticated, you may not have to do anything but open the URL). To see if this worked, run pizauth show UF again and you should see the access token obtained.\n Installing and Configuring msmtp This one is easy to install:\nsudo apt install msmtp Next create the file ~/.msmtprc with the following contents, which again will need to be modified to match your situation.\n## UF email via office365 (Microsoft) account UF auth xoauth2 host smtp.office365.com protocol smtp port 587 tls on tls_starttls on from presnell@ufl.edu user presnell@ufl.edu passwordeval pizauth show UF At this stage you can test that sending email is working by running something like:\nprintf \u0026#34;Subject: Test\\n\\nHello there me.\u0026#34; | msmtp -a UF your_personal_account@gmail.com and checking that the mail is received at your personal account.\n An error similar to this:\nsh: 1: pizauth: Permission denied msmtp: cannot read output of \u0026#39;pizauth show UF\u0026#39; probably indicates that your OS (Ubuntu for me) has put some overly restrictive apparmor conditions on msmtp. You can fix this by disabling apparmor for msmtp like this:\nsudo ln -s /etc/apparmor.d/usr.bin.msmtp /etc/apparmor.d/disable/ sudo apparmor_parser -R /etc/apparmor.d/usr.bin.msmtp Installing and Configuring isync/mbsync Again, installion of the isync package is routine.\nsudo apt install isync To use mbsync with oauth2, you also need to install an xoauth2 plugin for SASL (Simple Authentication and Security Layer). There are several available, and I first tried the ppa on Cononical\u0026#39;s Launchpad, but it did not work for me. The most commonly used plugin seems to be this one (I think that it is used in Arch linux and in Free BSD). To install it, I followed the instructions in the Install Cyrus SASL OAuth2 section of this page. As prerequisites, you need to install that libsasl2-dev package and if you want to do the last step (verifying that XOATH2 is known to SASL probably isn\u0026#39;t necessary), you will also need to install the sasl2-bin package to get the saslpluginviewer command:\nsudo apt install libsasl2-dev sasl2-bin After this just follow the instructions mentioned above, i.e.,\n# Clone the Cyrus SASL OAuth2 sources. git clone https://github.com/moriyoshi/cyrus-sasl-xoauth2.git # Configure and make. cd cyrus-sasl-xoauth2 ./autogen.sh ./configure # SASL2 libraries on Ubuntu are in /usr/lib/x86_64-linux-gnu/; modify the Makefile accordingly sed -i \u0026#39;s%pkglibdir = ${CYRUS_SASL_PREFIX}/lib/sasl2%pkglibdir = ${CYRUS_SASL_PREFIX}/lib/x86_64-linux-gnu/sasl2%\u0026#39; Makefile make sudo make install # Verify XOAUTH2 is known to SASL. saslpluginviewer | grep XOAUTH2 Finally, I created a ~/.mbsyncrc file with the contents below. By default Outlook creates and syncs a bunch of folders that I don\u0026#39;t use. I basically keep everything in INBOX and Archive and use mu to find things quickly, so it\u0026#39;s easiest for me to just list the folders that I want in the Patterns line. If you create a lot of folders for your email, then it might be easier to say what you don\u0026#39;t want (there are examples online of how to do this), or just use * and download everything.\n Also, for initial testing, the RECOMMENDATIONS section of the mbsync man page recommends leaving Expunge None (the default) to make sure you don\u0026#39;t lose mail if anything goes awry.\n Finally, I set Create Near so that folders (mailboxes) would be created on the local side when I initially sync things up, but I don\u0026#39;t really want to create any new folders on either end. You might prefer Create Both, which I assume is a lot more common.\n Note that a \u0026#34;Channel\u0026#34; in mbsync combines a Far with a Near store; in this case the UF channel combines UFRemote and UFLocal.\nIMAPAccount UF Host outlook.office365.com User presnell@ufl.edu Port 993 SSLType IMAPS SSLVersions TLSv1.1 TLSv1.2 AuthMechs XOAUTH2 PassCmd \u0026#34;pizauth show UF\u0026#34; IMAPStore UFRemote Account UF MailDirStore UFLocal Path ~/Maildir/UF/ Inbox ~/Maildir/UF/INBOX Subfolders Verbatim Channel UF Far :UFRemote: Near :UFLocal: SyncState * ## I only want these 5 folders: Patterns \u0026#34;INBOX\u0026#34; \u0026#34;Archive\u0026#34; \u0026#34;Drafts\u0026#34; \u0026#34;Sent Items\u0026#34; \u0026#34;Deleted Items\u0026#34; ## You can sync EVERYTHING by using this line instead: ## Patterns * Create Near Expunge Both I also had to manually create the ~Maildir/UF directory. You probably don\u0026#39;t want that to be readable by anyone but you either, so set the permissions accordingly.\nmkdir -p ~/Maildir/UF chmod -R go-rwx ~/Maildir Finally, test by running the following command. It will take a while the first time to download all your email.\nmbsync UF Socket error: unexpected eof I consistently get the following error message when I run mbsync UF, but the error doesn\u0026#39;t seem to cause any problems.\nSocket error: secure read from outlook.office365.com (52.96.29.82:993): error:0A000126:SSL routines::unexpected eof while reading Duplicate messages This post may be useful for diagnosing and fixing duplicate message errors from mbsync.\n Installing mu and mu4e I\u0026#39;m going to install the latest version of mu and mu4e from github. If you\u0026#39;re happy with an older version, you can install the Ubuntu package maildir-utils with apt.\n It might be a good idea to clear out any existing mu and mu4e installations if you have used them before, e.g., with sudo apt purge maildir-utils. I had installed them manually from source, so I did something like this:\nsudo rm /usr/local/bin/mu sudo rm -r /usr/local/share/emacs/site-lisp/mu4e sudo rm -r /usr/local/share/man/man*/mu-* sudo rm /usr/local/share/man1/mu.1 sudo rm /usr/local/share/man1/mug.1 sudo rm -r /usr/local/share/doc/mu Make sure these prerequisite libraries are installed. Add emacs to the list of packages if you don\u0026#39;t already have it (I use emacs-snapshot from a ppa so I\u0026#39;m not including that here).\nsudo apt install libgmime-3.0-dev libxapian-dev Next install the meson build system.\nsudo apt install meson ninja-build Now we can download the most recent release of mu (currently 1.8.10) and install as below. It is possible that there are prerequisite packages that need to be installed with apt, but if so, I seem to have all of them already installed from previous installations of mu.\ncd ~/Download tar -xf mu-1.8.10.tar.xz cd mu-1.8.10 meson build \u0026amp;\u0026amp; ninja -C build sudo ninja -C build install # By default this will install into /usr/local To index your mail, just run:\nmu init --maildir=~/Maildir --my-address=presnell@ufl.edu --my-address=presnell@stat.ufl.edu mu info # Checking everything is correct mu index Configuring mu4e Further Notes It looks like this person had a similar ordeal\nMy comments for Laurie Tratt\u0026#39;s blog post on pizauth: Works for me! Thanks so much for this. I lost access to my work email last week when MS turned off basic authentication. After I had struggled to arrive at an acceptable (no tokens stored in unencrypted files) and complete (IMAP and SMTP both working smoothly) solution with any of the other options I came across, pizauth saved the day. I had been using offlineimap + mu + mu4e and emacs\u0026#39;s built-in sendmail stuff. I ended up with pizauth + mbsync + msmtp + mu + mu4e, but it\u0026#39;s working, so I\u0026#39;m happy.\n A few comments:\n I have rust installed via rustup (so in my home directory) and on my linux box (Ubuntu 22.04) I couldn\u0026#39;t get sudo to use it for \u0026#34;sudo make install\u0026#34;, so I commented the \u0026#34;cargo build –release\u0026#34; step out of the install recipe in the Makefile. With that change \u0026#34;make; sudo make install\u0026#34; worked without a hitch.\n My institution does not allow me to register a new application with Azure, so I\u0026#39;m just using the client id and secret for thunderbird, which I assume is what most people are doing.\n Offlineimap will work with OAuth2 (I verified this by generating access and renew tokens and manually entering them into my .offlineimaprc file). I think that it should work with pizauth (by calling pizauth in a manner similar to this (https://wiki.archlinux.org/title/OfflineIMAP#Configuring_OAuth2_and_getting_access_tokens_via_mailctl) or this (https://www.macs.hw.ac.uk/~rs46/posts/2022-01-11-mu4e-oauth.html) but somehow I failed to get it to work. FWIW, I thought that offlineimap needed both an access token and a renewal token, and assuming that both would eventually expire if not used, I don\u0026#39;t see how to get the refresh token from pizauth.\n Today I noticed that offlineimap also has built-in functionality for renewing OAuth2 tokens (https://gist.github.com/piyueh/a2d65e095ea675a2c715ad42b7b61d10). I didn\u0026#39;t realize this, so I may have misunderstood some of the configuration advice that I encountered elsewhere. I certainly would have continued with offlineimap if I had managed to get everything working properly, but mbsync does seem to be a bit faster, so there\u0026#39;s that I guess.\n ","date":1665346618,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1714166464,"objectID":"84a3b6a3106215216f4fd602ef4eafc7","permalink":"https://presnell.github.io/post/email/","publishdate":"2022-10-09T16:16:58-04:00","relpermalink":"/post/email/","section":"post","summary":"Background I\u0026#39;ve been reading and sending email with GNU Emacs since about 1991. In that time I have used at least five different emacs email clients: MH-E, VM, Mew, gnus, and now mu4e.","tags":[],"title":"Reading Email with Emacs","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" Data Manipulation Mainly I\u0026#39;m trying to record tidyverse ways of doing things. Usually I know how to do them in base-R.\nSelecting All Columns of a Given Type This can be useful when you have lots of columns and want to just look at a certain type. Pipe it into `names()` to just get the names of the columns.\ndata(swiss) swiss \u0026lt;- as_tibble(swiss) swiss %\u0026gt;% select(where(is.double)) A base-R version would be something like:\ndata(swiss) swiss[, sapply(swiss, is.double)] Graphics Side-by-Side Histograms Before and After Log Transformation Here\u0026#39;s a quick and easy way to visually compare histograms of a variable before and after a log transformation. For easy repetition, you can string the last 4 lines together with `;` to create a one-liner, or better, turn them into a simple function. (I\u0026#39;m not sure of the relative strengths and weaknesses of the cowplot and patchwork packages, so I\u0026#39;ve included examples with both. See this stackoverflow question for other approaches.)\nUsing the cowplot package: library(cowplot) p \u0026lt;- ggplot(hcvvt, aes(x = my_variable)) p1 \u0026lt;- p + geom_histogram() p2 \u0026lt;- p1 + scale_x_log10() plot_grid(p1, p2) Using the patchwork package: library(patchwork) p \u0026lt;- ggplot(hcvvt, aes(x = my_variable)) p1 \u0026lt;- p + geom_histogram() p2 \u0026lt;- p1 + scale_x_log10() p1 + p2 ","date":1655394003,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1660392776,"objectID":"5699030a9b843436b6a45ced684d5aaf","permalink":"https://presnell.github.io/post/r/","publishdate":"2022-06-16T10:40:03-05:00","relpermalink":"/post/r/","section":"post","summary":"Useful R snippets to remember","tags":[],"title":"R Tips and Tricks","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" What Is This About? Years ago, while teaching our undergraduate categorical data analysis course, I created a small R package consisting mainly of datasets from the text An Introduction to Categorical Data Analysis (2nd edn) by my colleague Alan Agresti, along with a few convenience functions. My primary goal was to make it easy for my students to get started on the examples and exercises, so the help files for each dataset included fairly detailed R code and in my mind this is really the the main feature of the package.\n Unfortunately, I haven\u0026#39;t taught the course over a decade, so I have not been actively maintaining the package and by now there is a newer edition of the text and probably several other associated R packages. Nevertheless, I still occassionally get requests for the package and I put it on github a while back to make it more easily available. So, if you landed on my web pages while looking for the icda package, you can install it in R with the following sequence of commands:\ninstall.packages(\u0026#34;devtools\u0026#34;) library(devtools) install_github(\u0026#34;presnell/icda\u0026#34;) And here are my old class notes and the tangled R code.\n ","date":1651675396,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1663688209,"objectID":"685af4e16aa305fb438efbf33ae12cd2","permalink":"https://presnell.github.io/post/icda/","publishdate":"2022-05-04T10:43:16-04:00","relpermalink":"/post/icda/","section":"post","summary":"Functions and datasets to accompany Agresti, \"An Introduction to Categorical Data Analysis (2nd edn)\".","tags":[],"title":"R Package icda","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" Once upon a time I did a little work on ranked set sampling with my former colleague Lora Bohn, work which was eventually published in the Journal of Nonparametric Statistics. The examples and counterexamples in the paper required some fairly routine calculations that we did not include, but we promised to make them available upon request. Someone recently asked for them for the first time in at least a few years, so I decided to make them available here so that they can be found by others. Of course, if you find them useful I would be pleased to hear about it.\n My only other comment is that these details, and especially the comments therein, will not make much sense if you don\u0026#39;t read the original, extremely enlightening paper. 😄\n","date":1604961501,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1662650933,"objectID":"7a95f71eb75223e689adedb9922e9c38","permalink":"https://presnell.github.io/post/rankedsetsampling/","publishdate":"2020-11-09T17:38:21-05:00","relpermalink":"/post/rankedsetsampling/","section":"post","summary":"Some calculations not included in our 1999 paper.","tags":[],"title":"U-Statistics and Imperfect Ranking in Ranked Set Sampling","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" What Is This About? After a very long hiatus from needing to run R in the classrooms, I am back at it. The classroom (Windows 10) PCs at UF are refreshed every night and all local files created by users are wiped. By default, R packages installed by users are placed in C:/Program Files/R/R-3.5.2/library,1 and like everything else that users create, they are wiped every night. Thus, if you accept the default behavior, you have to resintall any packages you need every time you need them.2 This has been the source of some frustration for me and at least one of my colleagues, so I decided to do something about it. This post describes my current (partial) solution, which I think should also be useful for folks running R or RStudio on a desktop PC in their office (in my department at UF anyway). It\u0026#39;s nothing fancy, and if someone has a better solution I would be happy to hear about it.\n My Solution Download this file and save it under the name .Rprofile in your home directory on the departmental file server (so ~/.Rprofile in linux and H:/.Rprofile in Windows), or use a text editor to create the file yourself with with the following contents:\nif (grepl(\u0026#34;Windows\u0026#34;, Sys.info()[\u0026#34;sysname\u0026#34;])) { my.lib.path \u0026lt;- file.path(\u0026#34;H:\u0026#34;, \u0026#34;R\u0026#34;, \u0026#34;win-library\u0026#34;, paste(R.version$major, sub(\u0026#34;\\\\..*$\u0026#34;, \u0026#34;\u0026#34;, R.version$minor), sep=\u0026#34;.\u0026#34;)) if (!dir.exists(my.lib.path)) dir.create(my.lib.path, recursive = TRUE) .libPaths(my.lib.path) rm(my.lib.path) } Now, whenever you start R in the classroom, run the command\nsource(\u0026#34;H:/.Rprofile\u0026#34;) This first checks that you are running R in Windows. If so, then it checks for the existence of the directory H:/R/win-library/X.Y, where X is the major version number and Y is the minor version of the current R process, and it creates this directory if it doesn\u0026#39;t already exist. It then adds this directory to the front of R\u0026#39;s library path so that (1) R will look for packages there before trying the system packages, and (2) R will install any new packages into this directory rather than the system directory.\n If anything about that is not ok with you, then you will need to modify .Rprofile to suit your specific needs. If you already have a directory of installed R packages, you can either move/rename it to match this scheme, or you can modify the script to match, assuming that your directory is on your H: drive.\nIf You Run R in Windows in Your Office If you place a copy of this .Rprofile file in whatever directory is returned by the R command path.expand(\u0026#39;~\u0026#39;) (probably C:/Users/\u0026lt;yourusername\u0026gt;/Documents), then R will run it automatically upon startup (on your office PC) and any libraries you install in your office will be saved to your H: drive. Also, as long as your office PC and the classroom PCs are running the same version of R, they will share the same set of user-installed R packages.\n Further Background and Explanation You can skip this if you like …\n When I login to a classroom machine, my home directory from the departmental (virtual) file server is mounted as the H: drive in Windows. So, to sidestep the problem of repeatedly installing packages, I initially created the folder R/win-library/3.53 in my home directory on the file server, and in the classroom, I just ran the R command .libPaths(\u0026#34;H:/R/win-library/3.5\u0026#34;) immediately after starting R (or RStudio). With this, any libraries I install are saved on the departmental file server and they are found again the next time I teach (once I have run that command).\n Of course this is still pretty annoying and I wanted to arrange things so that it would be done automatically by an .Rprofile startup file. This works if the file is placed in C:/Users/myusername/Documents, which the R command path.expand(\u0026#39;~\u0026#39;) returns as be the default user home on our classroom Windows PCs, but of course that file would also get wiped every night, so placing the file there doesn\u0026#39;t help.\n Nevertheless, to accomodate differing/changing versions of R and to automate the process as much as possible, I decided to create a .Rprofile that checks if I am running Windows and if so, sets my R library path to .libPaths(\u0026#34;H:/R/win-library/X.Y\u0026#34;). The X.Y is replaced by whatever \u0026#34;major.minor\u0026#34; version of R is running (currently 3.5) and the directory is created if it doesn\u0026#39;t already exist. Because this is done only if I am running Windows, it has no effect on my usual, completely satisfactory R environment in Linux.\n The contents of my current .Rprofile file are given in the previous section. If you already have a non-empty .Rprofile, you could add this to it, and of course you could also create different versions for different classes and put them in the appropriate places if that tickles your fancy. In the classroom I still have to run\nsource(\u0026#34;H:/.Rprofile\u0026#34;) after starting R, but I guess I\u0026#39;m going to have to live with that.\n Footnotes 1Coming from the UNIX/Linux world this already seems a bit crazy. Why am I running R as root here? BTW, you should mentally replace \u0026#34;3.5.2\u0026#34; with whatever version of R is currently installed on the PC, and Windows/DOS users may be more comfortable replacing the \u0026#34;/\u0026#34; path separator by \u0026#34;\\\u0026#34;.\n 2The classroom IT folks suggest using a USB thumbdrive as a workaround. insert sad face here\n 3From what I saw on the classroom PCs, it appears that win-library is the R default name for the user\u0026#39;s R libraries in Windows, so I decided to stick with that. (On Linux it\u0026#39;s something like x86_64-pc-linux-gnu-library.)\n ","date":1596898140,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1596898140,"objectID":"e67b226da41d629aa34e9276488ec470","permalink":"https://presnell.github.io/post/classroomr/","publishdate":"2020-08-08T10:49:00-04:00","relpermalink":"/post/classroomr/","section":"post","summary":"How to avoid reinstalling packages everytime you teach with R.","tags":[],"title":"Setting R's Library Path on UF Classroom PCs","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" What Is This About? This started as a list of errata that either I or my students had noticed in the exercises and the solutions manual for the 7th edition of Wackerly, Mendenhall, and Scheaffer\u0026#39;s math stat text.\n This list was posted as a plain ASCII text file on my old web pages and since I took those pages down I have been surprised by the number of students and teachers who either wanted a copy of the list, or who had questions or comments about other exercises or solutions in the text. So I decided to repost them here as a public service. I hope that I have not introduced any errors in the process of converting them to org-mode. If you prefer the original text files you can grab them here (exercises) and here (solutions).\n NB: I last taught from this text in 2008, not because I have any problem with the text itself, but because in the intervening time I have not been assigned to teach my department\u0026#39;s undergrad math stat sequence. I have not checked whether any of these errata have been corrected in later printings.\n Updates [2024-04-16 Tue] Allan Vega reported an error in the calculation of the p-value in Example 10.21 (pp. 536–7). This is not in the exercises or solutions, but I decided to add it anyway. (I hope this doesn\u0026#39;t get out of hand.)\n [2024-04-16 Tue] I noticed while looking into the error reported by Allan Vega that the applets page for the text has moved here, in case that is helpful to anyone reading this.\n Some Errata Found in the Exercises This is just a list of a few errata that I happen to have noticed. It is not intended to be a comprehensive list.\nExercise 2.79 \u0026#34;\\(P(B) \u0026lt; 1\\)\u0026#34; should be \u0026#34;\\(P(B) \u0026gt; 0\\)\u0026#34;.\n Exercise 2.80 Change \u0026#34;\\(P(B) \u0026gt; 0\\)\u0026#34; to \u0026#34;\\(P(B) \u0026lt; 1\\)\u0026#34;. Since \\(A\\) is a subset of \\(B\\), the assumption that \\(P(A) \u0026gt; 0\\) already implies that \\(P(B) \u0026gt; 0\\), so it is redundant to assume that \\(P(B) \u0026gt; 0\\). If, on the other hand, \\(P(B) = 1\\), then \\(A\\) and \\(B\\) are necessarily independent, and the objective of the exercise is to show that \\(A\\) and \\(B\\) must be dependent except in the uninteresting case that one or the other of the events has probability zero or one.\n Exercise 2.106 I would change this to ask \u0026#34;what is the smallest possible value for \\(P(A)\\)\u0026#34; or something similar. \u0026#34;What is \\(P(A)\\)?\u0026#34; gives the impression that one should be able to divine the exact value of \\(P(A)\\) from the information given, which isn\u0026#39;t true.\n Exercise 3.38 This is the same as the triangular taste test example that I give in class, except that here it is not carefully worded. The statement\n Suppose that the two formulas are equally attractive.\n should be changed to\n Suppose that the two formulas are indistinguishable.\n Why?\n If the two formulations are equally attractive on average but distinguishable, say by everyone, then on the average half of all tasters would choose the glass containing formula B. (The other half would choose one of the two glasses containing formula A.) So, if the two formulas are \u0026#34;equally attractive\u0026#34; but distinguishable by everyone, then the distribution of \\(Y\\) would be binomial on \\(n = 4\\) trials with success probability \\(p = 1/2\\).\n If the two formulas are \u0026#34;equally attractive\u0026#34; and can be distinguished by some but not all tasters, then we would need more information to do the problem.\n With the change I suggest above (\u0026#34;indistinguishable\u0026#34; rather than \u0026#34;equally attractive\u0026#34; formulas), each taster is effectively picking at random among the three glasses and \\(Y\\) is binomial on \\(n = 4\\) trials with success probability \\(p = 1/3\\). This is what was actually intended and is the solution given in the solutions manual.\n Exercise 5.85 This exercise should probably be starred, since it refers to exercise 5.65, which is starred.\n Exercise 5.94 The word \u0026#34;uncorrelated\u0026#34; should be deleted from this problem. Nothing in the problem changes if \\(Y_1\\) and \\(Y_2\\) are correlated.\n Some Errata Found in the Solutions Manual 2.5 (b) This is completely wrong. It should be something like\n \\begin{align} B \\cup (A \\cap \\bar B) \u0026amp;= (B \\cup A) \\cap (B \\cup \\bar B) \\\\ \u0026amp;= (B \\cup A) \\cap S \\\\ \u0026amp;= B \\cup A \\\\ \u0026amp;= A \\end{align}\n 2.42 Should be \\(P^{10}_3 = 10!/7! = 10 \\times 9 \\times 8 = 720\\).\n 2.44 (b) Change \\(3\\) to \\(3!\\) and \\(45\\) to \\(90\\).\n Also, the solution to 2.44 (a) is correct but expressed in an odd way. It would be better as \\begin{equation} \\binom{8}{3} \\times \\binom{5}{5}. \\end{equation}\n 2.45 Change the 7 to a 5. Answer should be \\(\\binom{17}{2\\ \\ 5\\ \\ 10} = 408,408\\).\n 2.59 (b) There are actually 10 different kinds of straights (starting with any of A, 2, 3, …, 10).\n 2.65 Should be \\(5!(2/6)(1/6)^4 = 5/162\\).\n 2.114 The answers are listed as parts a,b,b,d (two b\u0026#39;s and no c), and there are a couple of misprints in the answer to b. It should read\n \\begin{align} \u0026amp; \\text{a. } P(LL) = (.95)(.10) = 0.095 \u0026amp;\u0026amp; \\text{b. } P(LT) = (.95)(.9) = 0.855 \\\\ \u0026amp; \\text{c. } P(TL) = (.05)(.10) = 0.005 \u0026amp;\u0026amp; \\text{d. } 1 (.05)(.90) = 0.955 \\end{align}\n 3.48(a) For \\(P(Y \\ge 1)\\), the solution should be\n \\begin{align} P(Y \\ge 1) \u0026amp;= 1 - P(Y = 0) \\\\ \u0026amp;= 1- \\binom{5}{0}(0.9)^0(0.1)^5 \\\\ \u0026amp;= 1 - (0.1)^5 \\\\ \u0026amp;= 0.99999 \\\\ \\end{align}\n 3.113 There is a 3 that should be changed to 1:\n \\begin{equation} \\frac{\\binom{8}{1}\\binom{12}{5}}{\\binom{20}{6}} + \\frac{\\binom{8}{0}\\binom{12}{6}}{\\binom{20}{6}} = 0.187. \\end{equation}\n 4.57 The density of \\(D\\) is wrong here. It is not equal to \\(1/4\\) on the interval \\((.01, .05)\\), but to \\(1/(.05 - .01) = 25\\). Also, the choice of \\(d\\) as the dummy variable of integration is unfortunate here, because it leads to\n \\begin{equation} \\frac{\\pi}{6} \\int_{.01}^{.05} 25\\, d^3 \\,dd \\end{equation}\n and the \\(dd\\) is confusing. Note that this is meant to be the same as\n \\begin{equation} \\frac{\\pi}{6} \\int_{.01}^{.05} 25\\, y^3 \\,dy. \\end{equation}\n Anyway, the numerical answer for the mean volume (\\(.0000065\\times\\pi\\)) is correct, but the answer for the variance of the volume is not (it should be \\(0.00000000003525\\,\\pi^2\\), i.e., \\((3.525397 \\times 10^{-11})\\,\\pi^2\\).\n 4.74 (d) This part has been left unfinished. Having found that the lower quartile of test scores is \\(73.98\\), we are supposed to find what proportion of test takers score \\(73.98 + 5 = 78.98\\) or more. Using the normal table, the final answer is \\(.4364\\) (because of rounding, this is slightly different from the answer you would get if if you did the whole exercise using a computer, \\(.4369\\)).\n 4.92 In the calculation of \\(E(Y^3)\\) and \\(E(Y^4)\\), the 100\u0026#39;s in the integrals should be 10\u0026#39;s, and the results should be \\begin{equation} E(Y^3) = \\Gamma(4)\\times 10^4 = 3! \\times 10^4 = 6000 \\end{equation} and \\begin{equation*} E(Y^4) = Γ(5)× 10^5 = 4! × 10^5 = 240,000. \\end{equation*}\n 5.9 (b) The integral is set up incorrectly, but the numerical answer \\(31/64\\) is correct.\n 6.14 Change \\(P(Y_1 \u0026gt; u/Y_2)\\) to \\(1 - P(Y_1 \u0026gt; u/Y_2)\\).\n Some Errata Found in the Text Example 10.21 (pp. 536–7) The p-value has been miscalculated somehow. The last sentence of the example should have \\(P(F \u0026gt; 2.079) = .1118\\) and \\(\\text{p-value} = 2(.1118) = .2236\\). (Reported by Allan Vega)\n ","date":1592365057,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1592365057,"objectID":"295226498aee7f1039f879302a04cfe6","permalink":"https://presnell.github.io/post/wackmendscheerrata/","publishdate":"2020-06-16T23:37:37-04:00","relpermalink":"/post/wackmendscheerrata/","section":"post","summary":"A partial list of errata and other comments.","tags":[],"title":"Mathematical Statistics With Applications (7th Edition) by Wackerly, Mendenhall, and Scheaffer","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" What Is This About? The IT folks hope to shut down our department\u0026#39;s legacy Apache web server, so I\u0026#39;m in the process of moving my web presence, such as it is, elsewhere, with elsewhere being github, at least for now. I probably won\u0026#39;t move much of the old stuff over, since it\u0026#39;s, well, old, but if there was something on my old web page that was useful to you, send me an email and I\u0026#39;ll see what I can to to make it available again.\n Course Web Pages Tonight I decided to hide the web pages for courses I\u0026#39;m currently teaching under the \u0026#34;Teaching\u0026#34; menu up above, so if you\u0026#39;re in my probability class, you know what to do.\n ","date":1566780836,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1566780836,"objectID":"3dfd9dab57a9607ac0c91d64c1bdd452","permalink":"https://presnell.github.io/post/changes/","publishdate":"2019-08-25T20:53:56-04:00","relpermalink":"/post/changes/","section":"post","summary":"In case you can't find something, maybe this will help.","tags":[],"title":"Changes","type":"post"},{"authors":["Brett Presnell"],"categories":[],"content":" Adding Git Information This response from Eric Fraga might be useful.\n Formatting Numerical Table Entries It can be rather painful to properly format numerical tables from R for export via org mode. Here is a slightly modified version of an example from the org mode manual that leaves integers untouched but prints floating point numbers with a specified format (almost). Alternatively, check out the ascii package for R.\n#+NAME: round-tbl #+BEGIN_SRC emacs-lisp :var tbl=\u0026#34;\u0026#34; :var fmt=\u0026#34;%.1f\u0026#34; (mapcar (lambda (row) (mapcar (lambda (cell) (if (floatp cell) (format fmt cell) cell)) row)) tbl) #+end_src #+begin_src R :results replace :colnames yes :post round-tbl[:colnames yes](*this*) z \u0026lt;- dplyr::tribble(~i, ~x, 6, -pi, -4, exp(1), 1, 2) z #+end_src #+RESULTS: | i | x | |----+------| | 6 | -3.1 | | -4 | 2.7 | | 1 | 2 | Note that I get a 2 in the last cell, not the 2.0 that I was hoping for. FWIW, wrapping z in print.data.frame() in the R code does not solve this problem. The problem is that something in the emacs/orgmode/elisp processing is intercepting the 2.000 and deciding that it\u0026#39;s an integer. Evidently I either need to figure that out or, alternatively, rewrite the elisp code to operate on the table in a column wise manner (ignoring the column header).\n Note that it\u0026#39;s easy to change the format used, but of course it doesn\u0026#39;t do a thing about the \u0026#34;2\u0026#34;.\n#+begin_src R :results replace :colnames yes :post round-tbl[:colnames yes](*this*, fmt=\u0026#34;%.3f\u0026#34;) z \u0026lt;- dplyr::tribble(~i, ~x, 6, -pi, -4, exp(1), 1, 2) z #+end_src #+RESULTS: | i | x | |----+--------| | 6 | -3.142 | | -4 | 2.718 | | 1 | 2 | Replacing Table Headers Sometimes I want to replace the variable names used as column header in R export with a custom, multi-row header. Here\u0026#39;s an example of how this might be done. I haven\u0026#39;t been careful about handling headers in the elisp code, so one may need to be careful about setting :colnames (and possibly :hlines) appropriately (note that :colnames nil is the default (and :hlines no). I have tried to illustrate this below.\n For me the tables would normally be something that had been computed in R, but for simplicity I\u0026#39;m just reading the data straight from the org file.\n#+name: headed_table | a | b | c | |-------+-----+-------| | red | 148 | 77.08 | | white | 140 | 72.92 | | blue | 102 | 53.13 | #+name: headless_table | red | 148 | 77.08 | | white | 140 | 72.92 | | blue | 102 | 53.13 | #+name: replacement_header | | Number | Percentage | | | of | of | | Color | Flags | Flags | Here\u0026#39;s the (simple) elisp code.\n#+name: replace-header #+BEGIN_SRC emacs-lisp :var tab=\u0026#34;\u0026#34; new_header=\u0026#34;\u0026#34; (append new_header (cons \u0026#39;hline tab)) #+END_SRC Here\u0026#39;s how to call it straight from elisp to work with an existing org table.\n#+call: replace-header(headed_table, replacement_header) #+RESULTS: | | Number | Percentage | | | of | of | | Color | Flags | Flags | |-------+--------+------------| | red | 148 | 77.08 | | white | 140 | 72.92 | | blue | 102 | 53.13 | Here\u0026#39;s calling it from R with a table having a header.\n#+begin_src R :var data=headed_table :post replace-header(*this*, replacement_header) data #+end_src #+RESULTS: | | Number | Percentage | | | of | of | | Color | Flags | Flags | |-------+--------+------------| | red | 148 | 77.08 | | white | 140 | 72.92 | | blue | 102 | 53.13 | Here\u0026#39;s calling it from R with a headless table (probably pretty rare in practice).\n#+begin_src R :var data=headless_table :colnames no :post replace-header(*this*, replacement_header) data #+end_src #+RESULTS: | | Number | Percentage | | | of | of | | Color | Flags | Flags | |-------+--------+------------| | red | 148 | 77.08 | | white | 140 | 72.92 | | blue | 102 | 53.13 | And here is how to combine this with the formatting provided by the round-tbl function from elsewhere in this document: just compose the functions in the :post header argument.\n#+begin_src R :var data=headed_table :post replace-header(round-tbl(*this*, \u0026#34;%.1f\u0026#34;), replacement_header) data #+end_src #+RESULTS: | | Number | Percentage | | | of | of | | Color | Flags | Flags | |-------+--------+------------| | red | 148 | 77.1 | | white | 140 | 72.9 | | blue | 102 | 53.1 | Naming Source Code Blocks and Their Results for Referencing This response by Nicolas Goaziou is as clear an explanation as you\u0026#39;ll ever see. :results drawer and maybe :wrap export org These might be useful for code blocks that need to be evaluated as org text. Check the org list from around 2020-11-11 for more.\n Stacking Tables The org-mode equivalent of rbind() in R is revealed here by Emmanuel Charpentier.\n Org Mode Interface to Canvas This project might be worth keeping an eye on if my use of Canvas expands.\n Easy-Hugo The easy-hugo package might be useful for maintaining my web site.\n ","date":1566780799,"expirydate":-62135596800,"kind":"page","lang":"en","lastmod":1651895066,"objectID":"ebf5b402c566ceb3fbbe2e1af96e3f94","permalink":"https://presnell.github.io/post/orgmode/","publishdate":"2019-08-25T20:53:19-04:00","relpermalink":"/post/orgmode/","section":"post","summary":"Useful org mode snippets to remember","tags":[],"title":"Org Mode Tips and Tricks","type":"post"}]