<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://labwiki.maceys.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lynn</id>
	<title>My Homelab - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://labwiki.maceys.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lynn"/>
	<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Special:Contributions/Lynn"/>
	<updated>2026-08-21T03:59:10Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=The_assessments_are_here&amp;diff=1562</id>
		<title>The assessments are here</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=The_assessments_are_here&amp;diff=1562"/>
		<updated>2026-08-21T02:00:27Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;The software landscape is vast. It is a little like being in a candy store the size of a Walmart. With hypervisors like Proxmox and TrueNAS it is rediculously easy to sping up virtual machines or launch software with docker. What used to take hours installing an OS and configuring a physical resource only takes minutes. Installing software used to be its own hurdle. Getting it to work on you specific combination of hardware and OS could literally take days.   =The tools...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The software landscape is vast. It is a little like being in a candy store the size of a Walmart. With hypervisors like Proxmox and TrueNAS it is rediculously easy to sping up virtual machines or launch software with docker. What used to take hours installing an OS and configuring a physical resource only takes minutes. Installing software used to be its own hurdle. Getting it to work on you specific combination of hardware and OS could literally take days. &lt;br /&gt;
&lt;br /&gt;
=The tools That I use, or have used=&lt;br /&gt;
==Hypervisors==&lt;br /&gt;
For the most part these tools are bare metal installs. Let&#039;s not get into the crazy case where a hypervisor is installed on a hypervisor. Yes it can be done but I personally think that it is crazy.&lt;br /&gt;
===Proxmox===&lt;br /&gt;
===TrueNAS===&lt;br /&gt;
===Hyper-V===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=YAMS=&lt;br /&gt;
[https://gitlab.com/rogs/yams YAMS on Github]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1561</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1561"/>
		<updated>2026-08-21T01:43:11Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
=Introduction=&lt;br /&gt;
This wiki covers my journey toward the perfect Homelab/Home server for me. This likely is not the perfect one for you. &lt;br /&gt;
&lt;br /&gt;
I am a retired IP professional who spent 45 years in the trenches doing much this same work and got paid for it. Now I do it for fun and, face it, it keeps off of the streets and out of jail. &lt;br /&gt;
&lt;br /&gt;
[[How did I get here?]]&lt;br /&gt;
&lt;br /&gt;
I have been through a lot of hardware, software and solutions over the years. As of now, I am regretting scrapping some of the hardware that arrived over time. I don&#039;t feel bad about getting rid of the large 1U and 2U servers that I had at one time. They were not terribly fast, but very noisy and power hungry. After my wife and I downsized from a medium sized house to a 2 BR apartment, it made no sense to keep them. Yes, they were fun to tinker with, but they were also a sledgehammer to the fine task that I was attempting to accomplish.&lt;br /&gt;
&lt;br /&gt;
[[The Network and Home Servers]]&lt;br /&gt;
&lt;br /&gt;
I have been through a number of solution packages getting to where I am, and I am largely still looking. Hopefully I will be able to declare success in the relatively near future...&lt;br /&gt;
&lt;br /&gt;
Like many of you I started out with discrete tools as I was learning how to use Docker. I am not sure how I would get along without this tool. Below I will list what I feel are the strengths and weaknesses of the configurations that I have tried. To a large degree, if you starting out building a home lab, you need to have the ability to manage the configuration that you pt together because generally none of them are a perfect solution. One of the common problems since the developers are likely to be home hobbyists like ourselves, The projects tend to stall out after a while. The developer moves on or experiences people being demanding, ungrateful and sometimes just plain nasty. &lt;br /&gt;
&lt;br /&gt;
I have been willing, and happy, to pay them subscription fees to fund their efforts. These are usually modest, typically equivalent to two or three lattes a month. Getting traction on their part is often difficult and reaching critical mass generally doesn&#039;t happen. I recognize that most of these people have real jobs and developing the code is just a side gig that helps to pay the electric bill and buy some hardware. So, with that, let me tell you how I got to here.&lt;br /&gt;
&lt;br /&gt;
[[The Homelab Stack History]]&lt;br /&gt;
&lt;br /&gt;
The stack implementation progression has been SimpleHomeLab, Funky Penguin, YAMS and then Deployrr. I am now working with The TrueNAS-Compose suite. I have tried to give a reasoned top-level assessment of the good and bad aspects of the tool on the assessment page.&lt;br /&gt;
&lt;br /&gt;
[[The assessments are here]]&lt;br /&gt;
&lt;br /&gt;
For more of a deep dive deep dive into them just head over here:&lt;br /&gt;
&lt;br /&gt;
[[Technical details are here]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User&#039;s Guide] for information on using the wiki software.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]&lt;br /&gt;
* [https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/ MediaWiki release mailing list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1560</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1560"/>
		<updated>2026-08-21T01:37:03Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
=Introduction=&lt;br /&gt;
This wiki covers my journey toward the perfect Homelab/Home server for me. This likely is not the perfect one for you. &lt;br /&gt;
&lt;br /&gt;
I am a retired IP professional who spent 45 years in the trenches doing much this same work and got paid for it. Now I do it for fun and, face it, it keeps off of the streets and out of jail. &lt;br /&gt;
&lt;br /&gt;
[[How did I get here?]]&lt;br /&gt;
&lt;br /&gt;
I have been through a lot of hardware, software and solutions over the years. As of now, I am regretting scrapping some of the hardware that arrived over time. I don&#039;t feel bad about getting rid of the large 1U and 2U servers that I had at one time. They were not terribly fast, but very noisy and power hungry. After my wife and I downsized from a medium sized house to a 2 BR apartment, it made no sense to keep them. Yes, they were fun to tinker with, but they were also a sledgehammer to the fine task that I was attempting to accomplish.&lt;br /&gt;
&lt;br /&gt;
[[The Network and Home Servers]]&lt;br /&gt;
&lt;br /&gt;
I have been through a number of solution packages getting to where I am, and I am largely still looking. Hopefully I will be able to declare success in the relatively near future...&lt;br /&gt;
&lt;br /&gt;
Like many of you I started out with discrete tools as I was learning how to use Docker. I am not sure how I would get along without this tool. Below I will list what I feel are the strengths and weaknesses of the configurations that I have tried. To a large degree, if you starting out building a home lab, you need to have the ability to manage the configuration that you pt together because generally none of them are a perfect solution. One of the common problems since the developers are likely to be home hobbyists like ourselves, The projects tend to stall out after a while. The developer moves on or experiences people being demanding, ungrateful and sometimes just plain nasty. &lt;br /&gt;
&lt;br /&gt;
I have been willing, and happy, to pay them subscription fees to fund their efforts. These are usually modest, typically equivalent to two or three lattes a month. Getting traction on their part is often difficult and reaching critical mass generally doesn&#039;t happen. I recognize that most of these people have real jobs and developing the code is just a side gig that helps to pay the electric bill and buy some hardware. So, with that, let me tell you how I got to here.&lt;br /&gt;
&lt;br /&gt;
[[The Homelab Stack History]]&lt;br /&gt;
&lt;br /&gt;
The stack implementation progression has been YAMS, Funky Penguin and Deployrr. I am now working with The TrueNAS-Compose suite. I have tried to give a reasoned top level assessment of the good and bad aspects of the tool on the assessment page.&lt;br /&gt;
&lt;br /&gt;
[[The assessments are here]]&lt;br /&gt;
&lt;br /&gt;
For more of a deep dive deep dive into them just head over here:&lt;br /&gt;
&lt;br /&gt;
[[Technical details are here]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User&#039;s Guide] for information on using the wiki software.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]&lt;br /&gt;
* [https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/ MediaWiki release mailing list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=The_Homelab_Stack_History&amp;diff=1559</id>
		<title>The Homelab Stack History</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=The_Homelab_Stack_History&amp;diff=1559"/>
		<updated>2026-08-21T01:33:55Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=The early days=&lt;br /&gt;
Like most systems administrators, I was loath to throw anything away that wasn&#039;t broken. Time and time again, having that odd cable, odd peripheral or obscure tool saved me a lot of time and the companies money. &lt;br /&gt;
&lt;br /&gt;
Even before I retired, I couldn&#039;t keep it all. this eventually led to major runs to the e-waste facility. It is interesting that those places tend to come and go pretty frequently. From observation, it appears that the have an imbalance between intake and disposal.&lt;br /&gt;
&lt;br /&gt;
So, I confess that I am a data hoarder. I was a very early adopter of software on CDs. I actually had a subscription that brought me 10 to 20 disks/month. Many of them were not terrible useful at the time but the good ones in the bundle made up for it. I think that some of them are still in the back of a closet waiting for hardware and OS environments that only exist in the computer history museum.&lt;br /&gt;
&lt;br /&gt;
At that point in time I had a large collection of ripped music CDs, that are still at the house that we left to our daughter, books, a lot of files from various jobs and a ton of email. Video file came along later. I gathered stuff, and still do, for the sake of the collecting. Now sharing with friends and family is a side benefit but at the time it required burning CDs or DVDs. Streaming was not even feasible.&lt;br /&gt;
=Along Came High-Speed links=&lt;br /&gt;
It was suddenly possible to have just about anything accessible with a little looking and a small investment of time. The price of disk storage was coming down; I still remember being impressed when it crossed the $.25 per megabyte threshold. Clearly the resource had to be used. What took days to download with even a 56Kb modem could be fetched in minutes.&lt;br /&gt;
=Then Plex entered and the *arr stack to manage it=&lt;br /&gt;
I could now watch movies on my computer. At first, all it took was to put the files in the root folder and call it good. You all know the drill. Suddenly you have hundreds and the thousands of hours of content. I spun up a NAS and ran Plex from there&lt;br /&gt;
&lt;br /&gt;
The *arr collection added a means to organize the chaos. Initially, Radarr and Sonarr ran natively on a Linux system that had been a desktop at one time. Then I moved to a significant server and installed Proxmox. Then I added a large TrueNAS system that I am presently consolidating most everything on.&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=The_Homelab_Stack_History&amp;diff=1558</id>
		<title>The Homelab Stack History</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=The_Homelab_Stack_History&amp;diff=1558"/>
		<updated>2026-08-21T01:33:18Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;=The early days= Like most systems administrators, I was loath to throw anything away that wasn&amp;#039;t broken. Time and time again, having that odd cable, odd peripheral or obscure tool saved me a lot of time and the companies money.   Even before I retired, I couldn&amp;#039;t keep it all. this eventually led to major runs to the e-waste facility. It is interesting that those places tend to come and go pretty frequently. From observation, it appears that the have an imbalance between...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=The early days=&lt;br /&gt;
Like most systems administrators, I was loath to throw anything away that wasn&#039;t broken. Time and time again, having that odd cable, odd peripheral or obscure tool saved me a lot of time and the companies money. &lt;br /&gt;
&lt;br /&gt;
Even before I retired, I couldn&#039;t keep it all. this eventually led to major runs to the e-waste facility. It is interesting that those places tend to come and go pretty frequently. From observation, it appears that the have an imbalance between intake and disposal.&lt;br /&gt;
&lt;br /&gt;
So, I confess that I am a data hoarder. I was a very early adopter of software on CDs. I actually had a subscription that brought me 10 to 20 disks/month. Many of them were not terrible useful at the time but the good ones in the bundle made up for it. I think that some of them are still in the back of a closet waiting for hardware and OS environments that only exist in the computer history museum.&lt;br /&gt;
&lt;br /&gt;
At that point in time I had a large collection of ripped music CDs, that are still at the house that we left to our daughter, books, a lot of files from various jobs and a ton of email. Video file came along later. I gathered stuff, and still do, for the sake of the collecting. Now sharing with friends and family is a side benefit but at the time it required burning CDs or DVDs. Streaming was not even feasible.&lt;br /&gt;
=Along Came High-Speed links=&lt;br /&gt;
It was suddenly possible to have just about anything accessible with a little looking and a small investment of time. The price of disk storage was coming down; I still remember being impressed when it crossed the $.25 per megabyte threshold. Clearly the resource had to be used. What took days to download with even a 56Kb modem could be fetched in minutes.&lt;br /&gt;
=Then Plex entered and the *arr stack to manage it=&lt;br /&gt;
I could now watch movies on my computer. At first, all it took was to put the files in the root folder and call it good. You all know the drill. Suddenly you have hundreds and the thousands of hours of content. I spun up a NAS and ran Plex from there&lt;br /&gt;
&lt;br /&gt;
The *arr collection added a means to organize the chaos. Initially, Radarr and Sonarr ran natively on a Linux system that had been a desktop at one time. Then I moved to a significant server and installed Proxmox. Then I added a large TrueNAS system that I am presently consolidating most everything on.&lt;br /&gt;
&lt;br /&gt;
The progression has been YAMS, Funky Penguin and Deployrr. I am now working with The TrueNAS-Compose suite.&lt;br /&gt;
&lt;br /&gt;
[[The assessments are here]]&lt;br /&gt;
&lt;br /&gt;
[[Technical details are here]]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1557</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1557"/>
		<updated>2026-08-21T00:54:14Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
=Introduction=&lt;br /&gt;
This wiki covers my journey toward the perfect Homelab/Home server for me. This likely is not the perfect one for you. &lt;br /&gt;
&lt;br /&gt;
I am a retired IP professional who spent 45 years in the trenches doing much this same work and got paid for it. Now I do it for fun and, face it, it keeps off of the streets and out of jail. &lt;br /&gt;
&lt;br /&gt;
[[How did I get here?]]&lt;br /&gt;
&lt;br /&gt;
I have been through a lot of hardware, software and solutions over the years. As of now, I am regretting scrapping some of the hardware that arrived over time. I don&#039;t feel bad about getting rid of the large 1U and 2U servers that I had at one time. They were not terribly fast, but very noisy and power hungry. After my wife and I downsized from a medium sized house to a 2 BR apartment, it made no sense to keep them. Yes, they were fun to tinker with, but they were also a sledgehammer to the fine task that I was attempting to accomplish.&lt;br /&gt;
&lt;br /&gt;
[[The Network and Home Servers]]&lt;br /&gt;
&lt;br /&gt;
I have been through a number of solution packages getting to where I am, and I am largely still looking. Hopefully I will be able to declare success in the relatively near future...&lt;br /&gt;
&lt;br /&gt;
Like many of you I started out with discrete tools as I was learning how to use Docker. I am not sure how I would get along without this tool. Below I will list what I feel are the strengths and weaknesses of the configurations that I have tried. To a large degree, if you starting out building a home lab, you need to have the ability to manage the configuration that you pt together because generally none of them are a perfect solution. One of the common problems since the developers are likely to be home hobbyists like ourselves, The projects tend to stall out after a while. The developer moves on or experiences people being demanding, ungrateful and sometimes just plain nasty. &lt;br /&gt;
&lt;br /&gt;
I have been willing, and happy, to pay them subscription fees to fund their efforts. These are usually modest, typically equivalent to two or three lattes a month. Getting traction on their part is often difficult and reaching critical mass generally doesn&#039;t happen. I recognize that most of these people have real jobs and developing the code is just a side gig that helps to pay the electric bill and buy some hardware. So, with that, let me tell you how I got to here.&lt;br /&gt;
&lt;br /&gt;
[[The Homelab Stack History]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User&#039;s Guide] for information on using the wiki software.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]&lt;br /&gt;
* [https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/ MediaWiki release mailing list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1556</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1556"/>
		<updated>2026-08-21T00:28:52Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
=Introduction=&lt;br /&gt;
This wiki covers my journey toward the perfect Homelab/Home server for me. This likely is not the perfect one for you. &lt;br /&gt;
&lt;br /&gt;
I am a retired IP professional who spent 45 years in the trenches doing much this same work and got paid for it. Now I do it for fun and, face it, it keeps off of the streets and out of jail. &lt;br /&gt;
&lt;br /&gt;
[[How did I get here?]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User&#039;s Guide] for information on using the wiki software.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]&lt;br /&gt;
* [https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/ MediaWiki release mailing list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1555</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1555"/>
		<updated>2026-08-21T00:23:51Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User&#039;s Guide] for information on using the wiki software.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]&lt;br /&gt;
* [https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/ MediaWiki release mailing list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=User:Lynn&amp;diff=1554</id>
		<title>User:Lynn</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=User:Lynn&amp;diff=1554"/>
		<updated>2026-08-19T01:55:59Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{User&lt;br /&gt;
| full name = Lynn Macey&lt;br /&gt;
| image name =&lt;br /&gt;
| hover text = lynn&lt;br /&gt;
| job title = Happily Retired&lt;br /&gt;
| organization = Working for The Family&lt;br /&gt;
| short quote = General All Around Good Guy&lt;br /&gt;
| about me = Have you got all day?&lt;br /&gt;
| about my work = I spent 45 years in high tech. Now I do it for fun.&lt;br /&gt;
| contact me = lynnmacey@gmail.com&lt;br /&gt;
| disclaimer = Only I am responsible&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
What I need to pull resolution and codec:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ffprobe -v error -select_streams v:0 -show_entries stream=width,height,codec_name -of csv=p=0 input.mp4  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fetch Termius Passkey: curl -fs https://sshid.io/lynnmacey &amp;gt;&amp;gt; ~/.ssh/authorized_keys&lt;br /&gt;
&lt;br /&gt;
Get iMatch from these guys: [https://www.photools.com/ Photools.com]&lt;br /&gt;
&lt;br /&gt;
[http://openflights.org/user/lynnmacey Lynn&#039;s Flight History]&lt;br /&gt;
&lt;br /&gt;
[[The Weekly Task List]]&lt;br /&gt;
&lt;br /&gt;
[[Home Server Applications to Try]]&lt;br /&gt;
&lt;br /&gt;
[[The Notes Collection]]&lt;br /&gt;
&lt;br /&gt;
[[Projects]]&lt;br /&gt;
&lt;br /&gt;
[[Wish List and Vendors]]&lt;br /&gt;
&lt;br /&gt;
Some places that may be useful:&lt;br /&gt;
*[https://www.virtualizationhowto.com/2026/07/how-i-organize-my-entire-home-lab-so-i-can-actually-find-anything/ How I Organize My Entire Home Lab]&lt;br /&gt;
[[Videos to Categorize]]&lt;br /&gt;
==Personal Accounts==&lt;br /&gt;
===BofA Checking===&lt;br /&gt;
Routing: 121000358&lt;br /&gt;
Account: 00126220---- add last 4 digits&lt;br /&gt;
===Venmo===&lt;br /&gt;
https://venmo.com/account/sign-in/&lt;br /&gt;
&lt;br /&gt;
 Username: @lynnmacey&lt;br /&gt;
 Password: M...&lt;br /&gt;
 Email Address: lynnmacey@gmail.com&lt;br /&gt;
&lt;br /&gt;
== Time Sensitive Information ==&lt;br /&gt;
&lt;br /&gt;
Interesting .zshrc rc file for the zsh shell. https://github.com/natelandau/dotfiles&lt;br /&gt;
&lt;br /&gt;
Some backup scripts are here https://github.com/natelandau/db_scripts&lt;br /&gt;
&lt;br /&gt;
==Movie reviews ==&lt;br /&gt;
Medieval &amp;quot;porn&amp;quot; : [https://www.youtube.com/watch?v=nTY2_NieZtw]&lt;br /&gt;
&lt;br /&gt;
Banned 1960s movies : [https://www.youtube.com/watch?v=J2CHNxk-jD0]&lt;br /&gt;
&lt;br /&gt;
13 Brutal 1970s Exploitation Films: [https://www.youtube.com/watch?v=3uBYsRYEhO0 13 Brutal 1970s Exploitation Films]&lt;br /&gt;
&lt;br /&gt;
15 Unfiltered Grindhouse Movies Hollywood Refused to Touch: [[https://www.youtube.com/watch?v=kfGhksb6Cho 15 Unfiltered Grindhouse Movies Hollywood Refused to Touch]&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=CY_e_9UoQpU 10 Movies So Wild Studios Would Never Greenlight Them Today]&lt;br /&gt;
&lt;br /&gt;
==Lynn&#039;s Flight History==&lt;br /&gt;
&lt;br /&gt;
[http://openflights.org/user/lynnmacey Lynn&#039;s Flight History]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;a href=&#039;https://openflights.org/user/lynnmacey&#039; target=&#039;_blank&#039;&amp;gt;&amp;lt;img src=&#039;https://openflights.org/banner/lynnmacey.png&#039; width=400 height=70&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I want this product for my wall: https://theflightwall.com/products/flightwall-mini-flight-tracking-led-display&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=User:Lynn&amp;diff=1553</id>
		<title>User:Lynn</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=User:Lynn&amp;diff=1553"/>
		<updated>2026-08-18T16:40:02Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* Personal Accounts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{User&lt;br /&gt;
| full name = Lynn Macey&lt;br /&gt;
| image name =&lt;br /&gt;
| hover text = lynn&lt;br /&gt;
| job title = Happily Retired&lt;br /&gt;
| organization = Working for The Family&lt;br /&gt;
| short quote = General All Around Good Guy&lt;br /&gt;
| about me = Have you got all day?&lt;br /&gt;
| about my work = I spent 45 years in high tech. Now I do it for fun.&lt;br /&gt;
| contact me = lynnmacey@gmail.com&lt;br /&gt;
| disclaimer = Only I am responsible&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Fetch Termius Passkey: curl -fs https://sshid.io/lynnmacey &amp;gt;&amp;gt; ~/.ssh/authorized_keys&lt;br /&gt;
&lt;br /&gt;
Get iMatch from these guys: [https://www.photools.com/ Photools.com]&lt;br /&gt;
&lt;br /&gt;
[http://openflights.org/user/lynnmacey Lynn&#039;s Flight History]&lt;br /&gt;
&lt;br /&gt;
[[The Weekly Task List]]&lt;br /&gt;
&lt;br /&gt;
[[Home Server Applications to Try]]&lt;br /&gt;
&lt;br /&gt;
[[The Notes Collection]]&lt;br /&gt;
&lt;br /&gt;
[[Projects]]&lt;br /&gt;
&lt;br /&gt;
[[Wish List and Vendors]]&lt;br /&gt;
&lt;br /&gt;
Some places that may be useful:&lt;br /&gt;
*[https://www.virtualizationhowto.com/2026/07/how-i-organize-my-entire-home-lab-so-i-can-actually-find-anything/ How I Organize My Entire Home Lab]&lt;br /&gt;
[[Videos to Categorize]]&lt;br /&gt;
==Personal Accounts==&lt;br /&gt;
===BofA Checking===&lt;br /&gt;
Routing: 121000358&lt;br /&gt;
Account: 00126220---- add last 4 digits&lt;br /&gt;
===Venmo===&lt;br /&gt;
https://venmo.com/account/sign-in/&lt;br /&gt;
&lt;br /&gt;
 Username: @lynnmacey&lt;br /&gt;
 Password: M...&lt;br /&gt;
 Email Address: lynnmacey@gmail.com&lt;br /&gt;
&lt;br /&gt;
== Time Sensitive Information ==&lt;br /&gt;
&lt;br /&gt;
Interesting .zshrc rc file for the zsh shell. https://github.com/natelandau/dotfiles&lt;br /&gt;
&lt;br /&gt;
Some backup scripts are here https://github.com/natelandau/db_scripts&lt;br /&gt;
&lt;br /&gt;
==Movie reviews ==&lt;br /&gt;
Medieval &amp;quot;porn&amp;quot; : [https://www.youtube.com/watch?v=nTY2_NieZtw]&lt;br /&gt;
&lt;br /&gt;
Banned 1960s movies : [https://www.youtube.com/watch?v=J2CHNxk-jD0]&lt;br /&gt;
&lt;br /&gt;
13 Brutal 1970s Exploitation Films: [https://www.youtube.com/watch?v=3uBYsRYEhO0 13 Brutal 1970s Exploitation Films]&lt;br /&gt;
&lt;br /&gt;
15 Unfiltered Grindhouse Movies Hollywood Refused to Touch: [[https://www.youtube.com/watch?v=kfGhksb6Cho 15 Unfiltered Grindhouse Movies Hollywood Refused to Touch]&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=CY_e_9UoQpU 10 Movies So Wild Studios Would Never Greenlight Them Today]&lt;br /&gt;
&lt;br /&gt;
==Lynn&#039;s Flight History==&lt;br /&gt;
&lt;br /&gt;
[http://openflights.org/user/lynnmacey Lynn&#039;s Flight History]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;a href=&#039;https://openflights.org/user/lynnmacey&#039; target=&#039;_blank&#039;&amp;gt;&amp;lt;img src=&#039;https://openflights.org/banner/lynnmacey.png&#039; width=400 height=70&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I want this product for my wall: https://theflightwall.com/products/flightwall-mini-flight-tracking-led-display&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1552</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1552"/>
		<updated>2026-08-18T01:48:11Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
					l, m = string.find(pargs[&#039;image&#039; .. i], &amp;quot;[[file:&amp;quot;)&lt;br /&gt;
					if (l ~= 0) then&lt;br /&gt;
						pargs[&#039;image&#039; .. i] = string.sub(pargs[&#039;image&#039; .. i], m + 1, len(pargs[&#039;image&#039; .. i]) - 2)&lt;br /&gt;
					end&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1551</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1551"/>
		<updated>2026-08-18T01:45:45Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* The Apartment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 450&lt;br /&gt;
| image1    = {{#display_map:39.75224,-121.79213|zoom=100|layers=OpenStreetMap}} &lt;br /&gt;
&lt;br /&gt;
| alt1      = Chico Map&lt;br /&gt;
&lt;br /&gt;
| image2    = Condo beach.jpg&lt;br /&gt;
| width     =450&lt;br /&gt;
| alt2      = Beach at the condo&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1550</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1550"/>
		<updated>2026-08-18T01:45:11Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function die(s)&lt;br /&gt;
  warn(s)&lt;br /&gt;
  error()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
					l, m = string.find(pargs[&#039;image&#039; .. i], &amp;quot;[[file:&amp;quot;)&lt;br /&gt;
					if (l == 1) then&lt;br /&gt;
						pargs[&#039;image&#039; .. i] = string.sub(pargs[&#039;image&#039; .. i], m + 1, len(pargs[&#039;image&#039; .. i]) - 2)&lt;br /&gt;
						die(pargs[&#039;image&#039; .. i])&lt;br /&gt;
					end&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1549</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1549"/>
		<updated>2026-08-18T01:27:51Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* The Apartment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 450&lt;br /&gt;
| image1    = {{#display_map:39.75224,-121.79213|zoom=100|layers=OpenStreetMap}} &lt;br /&gt;
&lt;br /&gt;
| alt1      = Chico Map&lt;br /&gt;
&lt;br /&gt;
| image2    = [[file:Condo beach.jpg]]&lt;br /&gt;
| width     =450&lt;br /&gt;
| alt2      = Beach at the condo&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1548</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1548"/>
		<updated>2026-08-18T01:26:37Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
					l, m = string.find(pargs[&#039;image&#039; .. i], &amp;quot;[[file:&amp;quot;)&lt;br /&gt;
					if (l == 1) then&lt;br /&gt;
						pargs[&#039;image&#039; .. i] = string.sub(pargs[&#039;image&#039; .. i], m + 1, len(pargs[&#039;image&#039; .. i]) - 2)&lt;br /&gt;
					end&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1547</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1547"/>
		<updated>2026-08-18T01:21:31Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
					l, m = string.find(pargs[&#039;image&#039; .. i], &amp;quot;[[file:&amp;quot;)&lt;br /&gt;
					if (l == 1) then&lt;br /&gt;
						pargs[&#039;image&#039; .. i] = string.sub(pargs[&#039;image&#039; .. i], m, len(pargs[&#039;image&#039; .. i]) - 2)&lt;br /&gt;
					end&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1546</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1546"/>
		<updated>2026-08-18T01:09:40Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
					l, m = string.find(pargs[&#039;image&#039; .. i], &amp;quot;[[file:&amp;quot;)&lt;br /&gt;
					if (l == 1) then&lt;br /&gt;
						pargs[&#039;image&#039; .. i] = string.sub(pargs[&#039;image&#039; .. i], l, len(pargs[&#039;image&#039; .. i]) - 2)&lt;br /&gt;
					end&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1545</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1545"/>
		<updated>2026-08-18T01:08:51Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
					l, m = string.find(pargs[&#039;image&#039; .. i], &amp;quot;[[File:&amp;quot;)&lt;br /&gt;
					if (l == 1) then&lt;br /&gt;
						pargs[&#039;image&#039; .. i] = string.sub(pargs[&#039;image&#039; .. i], l, len(pargs[&#039;image&#039; .. i]) - 2)&lt;br /&gt;
					end&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1544</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1544"/>
		<updated>2026-08-18T00:46:12Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1543</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1543"/>
		<updated>2026-08-18T00:12:18Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
					print(&amp;quot;Image&amp;quot;, pargs[&#039;image&#039; .. i])&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1542</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1542"/>
		<updated>2026-08-17T22:56:13Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
[[File:Chico_banner.webp]]&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
This is a collection of information related to, and being, &amp;quot;The Maceys&amp;quot;. It is intended to be a collection point for things that do not have a security value. We have other places to store passwords, for example.&lt;br /&gt;
&lt;br /&gt;
The primary focus is the Maceys in California who are Lynn and Bonita, their kids and kid&#039;s spouses. You will find them here:&lt;br /&gt;
{{col-float}}&lt;br /&gt;
==[[The Family Guide]]==&lt;br /&gt;
==[[What&#039;s new on Plex?]]==&lt;br /&gt;
==Quick Links==&lt;br /&gt;
==[[Chico Technical|Chico General Information]]==&lt;br /&gt;
&lt;br /&gt;
==[[San Jose General Information|San Jose General Information]]==&lt;br /&gt;
&lt;br /&gt;
==[[Technical Guides|Technical Guides]]==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{col-float-break}}&lt;br /&gt;
{{#display_map: Chico~Chico [[Living in Chico]]; San Jose~San Jose [[San Jose]]; Lake Almanor~Lake Almanor [[Lake Almanor]];Lihue~Nalu [[Hawaii Condo]]&lt;br /&gt;
|width=350|height=400|layers=OpenStreetMap}}&lt;br /&gt;
&lt;br /&gt;
{{col-float-end}}&lt;br /&gt;
==Family Locations==&lt;br /&gt;
&#039;&#039;&#039;{{Highlight|[[Living in Chico]]}}&#039;&#039;&#039; - [https://www.flightradar24.com/39.81,-122.13/9 Display Flight Radar]&lt;br /&gt;
&lt;br /&gt;
[https://adsb-chico.maceys.net/ Aircraft Localto Both Sites]&lt;br /&gt;
&lt;br /&gt;
[[San Jose Information]] - [https://www.flightradar24.com/37.37,-121.85/11 Display Flight Radar]&lt;br /&gt;
&lt;br /&gt;
[[Lake Almanor Information]] - [https://www.flightradar24.com/40.23,-120.98/10 DisplayFlight Radar]&lt;br /&gt;
[https://adsb-chico.maceys.net/1 Local Aircraft]&lt;br /&gt;
&lt;br /&gt;
[[Kauai Condotel]]&lt;br /&gt;
&lt;br /&gt;
[[Mace Companies]]&lt;br /&gt;
&lt;br /&gt;
==Special Interest==&lt;br /&gt;
[[Live Flight Radar]]&lt;br /&gt;
&lt;br /&gt;
[[ Interactive Fiction]]&lt;br /&gt;
&lt;br /&gt;
[[Cruises| Cruises Taken]]&lt;br /&gt;
&lt;br /&gt;
[[Software#Ring]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User&#039;s Guide] for information on using the wiki software.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]&lt;br /&gt;
* [https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/ MediaWiki release mailing list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1541</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1541"/>
		<updated>2026-08-17T22:55:44Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
[[File:Chico_banner.webp]]&lt;br /&gt;
Hook extensions @ [[Main Page|MediaWiki.org]] &amp;gt; [[:Category:Extensions|Extensions]] &amp;gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
This is a collection of information related to, and being, &amp;quot;The Maceys&amp;quot;. It is intended to be a collection point for things that do not have a security value. We have other places to store passwords, for example.&lt;br /&gt;
&lt;br /&gt;
The primary focus is the Maceys in California who are Lynn and Bonita, their kids and kid&#039;s spouses. You will find them here:&lt;br /&gt;
{{col-float}}&lt;br /&gt;
==[[The Family Guide]]==&lt;br /&gt;
==[[What&#039;s new on Plex?]]==&lt;br /&gt;
==Quick Links==&lt;br /&gt;
==[[Chico Technical|Chico General Information]]==&lt;br /&gt;
&lt;br /&gt;
==[[San Jose General Information|San Jose General Information]]==&lt;br /&gt;
&lt;br /&gt;
==[[Technical Guides|Technical Guides]]==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{col-float-break}}&lt;br /&gt;
{{#display_map: Chico~Chico [[Living in Chico]]; San Jose~San Jose [[San Jose]]; Lake Almanor~Lake Almanor [[Lake Almanor]];Lihue~Nalu [[Hawaii Condo]]&lt;br /&gt;
|width=350|height=400|layers=OpenStreetMap}}&lt;br /&gt;
&lt;br /&gt;
{{col-float-end}}&lt;br /&gt;
==Family Locations==&lt;br /&gt;
&#039;&#039;&#039;{{Highlight|[[Living in Chico]]}}&#039;&#039;&#039; - [https://www.flightradar24.com/39.81,-122.13/9 Display Flight Radar]&lt;br /&gt;
&lt;br /&gt;
[https://adsb-chico.maceys.net/ Aircraft Localto Both Sites]&lt;br /&gt;
&lt;br /&gt;
[[San Jose Information]] - [https://www.flightradar24.com/37.37,-121.85/11 Display Flight Radar]&lt;br /&gt;
&lt;br /&gt;
[[Lake Almanor Information]] - [https://www.flightradar24.com/40.23,-120.98/10 DisplayFlight Radar]&lt;br /&gt;
[https://adsb-chico.maceys.net/1 Local Aircraft]&lt;br /&gt;
&lt;br /&gt;
[[Kauai Condotel]]&lt;br /&gt;
&lt;br /&gt;
[[Mace Companies]]&lt;br /&gt;
&lt;br /&gt;
==Special Interest==&lt;br /&gt;
[[Live Flight Radar]]&lt;br /&gt;
&lt;br /&gt;
[[ Interactive Fiction]]&lt;br /&gt;
&lt;br /&gt;
[[Cruises| Cruises Taken]]&lt;br /&gt;
&lt;br /&gt;
[[Software#Ring]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User&#039;s Guide] for information on using the wiki software.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]&lt;br /&gt;
* [https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/ MediaWiki release mailing list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1540</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Main_Page&amp;diff=1540"/>
		<updated>2026-08-17T22:55:21Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
[[File:Chico_banner.webp]]&lt;br /&gt;
#* Hook extensions @ [[Main Page|MediaWiki.org]] &amp;gt; [[:Category:Extensions|Extensions]] &amp;gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
This is a collection of information related to, and being, &amp;quot;The Maceys&amp;quot;. It is intended to be a collection point for things that do not have a security value. We have other places to store passwords, for example.&lt;br /&gt;
&lt;br /&gt;
The primary focus is the Maceys in California who are Lynn and Bonita, their kids and kid&#039;s spouses. You will find them here:&lt;br /&gt;
{{col-float}}&lt;br /&gt;
==[[The Family Guide]]==&lt;br /&gt;
==[[What&#039;s new on Plex?]]==&lt;br /&gt;
==Quick Links==&lt;br /&gt;
==[[Chico Technical|Chico General Information]]==&lt;br /&gt;
&lt;br /&gt;
==[[San Jose General Information|San Jose General Information]]==&lt;br /&gt;
&lt;br /&gt;
==[[Technical Guides|Technical Guides]]==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{col-float-break}}&lt;br /&gt;
{{#display_map: Chico~Chico [[Living in Chico]]; San Jose~San Jose [[San Jose]]; Lake Almanor~Lake Almanor [[Lake Almanor]];Lihue~Nalu [[Hawaii Condo]]&lt;br /&gt;
|width=350|height=400|layers=OpenStreetMap}}&lt;br /&gt;
&lt;br /&gt;
{{col-float-end}}&lt;br /&gt;
==Family Locations==&lt;br /&gt;
&#039;&#039;&#039;{{Highlight|[[Living in Chico]]}}&#039;&#039;&#039; - [https://www.flightradar24.com/39.81,-122.13/9 Display Flight Radar]&lt;br /&gt;
&lt;br /&gt;
[https://adsb-chico.maceys.net/ Aircraft Localto Both Sites]&lt;br /&gt;
&lt;br /&gt;
[[San Jose Information]] - [https://www.flightradar24.com/37.37,-121.85/11 Display Flight Radar]&lt;br /&gt;
&lt;br /&gt;
[[Lake Almanor Information]] - [https://www.flightradar24.com/40.23,-120.98/10 DisplayFlight Radar]&lt;br /&gt;
[https://adsb-chico.maceys.net/1 Local Aircraft]&lt;br /&gt;
&lt;br /&gt;
[[Kauai Condotel]]&lt;br /&gt;
&lt;br /&gt;
[[Mace Companies]]&lt;br /&gt;
&lt;br /&gt;
==Special Interest==&lt;br /&gt;
[[Live Flight Radar]]&lt;br /&gt;
&lt;br /&gt;
[[ Interactive Fiction]]&lt;br /&gt;
&lt;br /&gt;
[[Cruises| Cruises Taken]]&lt;br /&gt;
&lt;br /&gt;
[[Software#Ring]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents User&#039;s Guide] for information on using the wiki software.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]&lt;br /&gt;
* [https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/ MediaWiki release mailing list]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]&lt;br /&gt;
* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Template_link_general/config&amp;diff=1539</id>
		<title>Module:Template link general/config</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Template_link_general/config&amp;diff=1539"/>
		<updated>2026-08-17T22:19:12Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;local cfg = {}; -- Don’t touch this line.  -- The link for the “subst:” prefix when the “link subst” parameter is truthy. -- Set to “nil” to disable  the “link subst” parameter. cfg[&amp;quot;subst-link&amp;quot;] = &amp;quot;Special:MyLanguage/Help:Substitution&amp;quot;;  return cfg; -- Don’t touch this line.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local cfg = {}; -- Don’t touch this line.&lt;br /&gt;
&lt;br /&gt;
-- The link for the “subst:” prefix when the “link subst” parameter is truthy.&lt;br /&gt;
-- Set to “nil” to disable  the “link subst” parameter.&lt;br /&gt;
cfg[&amp;quot;subst-link&amp;quot;] = &amp;quot;Special:MyLanguage/Help:Substitution&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
return cfg; -- Don’t touch this line.&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Template_link_general&amp;diff=1538</id>
		<title>Module:Template link general</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Template_link_general&amp;diff=1538"/>
		<updated>2026-08-17T22:16:14Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;-- This implements Template:Template link general and various other templates in its family local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs local yesno = require(&amp;#039;Module:Yesno&amp;#039;)  local cfg = mw.loadData(&amp;#039;Module:Template link general/config&amp;#039;)  local p = {}  -- Is a string non-empty? local function _ne(s) 	return s ~= nil and s ~= &amp;quot;&amp;quot; end  local nw = mw.text.nowiki  local function addTemplate(s) 	local i, _ = s:find(&amp;#039;:&amp;#039;, 1, true) 	if i == nil then 		return &amp;#039;Template...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- This implements [[Template:Template link general]] and various other templates in its family&lt;br /&gt;
local getArgs = require(&#039;Module:Arguments&#039;).getArgs&lt;br /&gt;
local yesno = require(&#039;Module:Yesno&#039;)&lt;br /&gt;
&lt;br /&gt;
local cfg = mw.loadData(&#039;Module:Template link general/config&#039;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
-- Is a string non-empty?&lt;br /&gt;
local function _ne(s)&lt;br /&gt;
	return s ~= nil and s ~= &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local nw = mw.text.nowiki&lt;br /&gt;
&lt;br /&gt;
local function addTemplate(s)&lt;br /&gt;
	local i, _ = s:find(&#039;:&#039;, 1, true)&lt;br /&gt;
	if i == nil then&lt;br /&gt;
		return &#039;Template:&#039; .. s&lt;br /&gt;
	end&lt;br /&gt;
	local ns = s:sub(1, i - 1)&lt;br /&gt;
	if ns == &#039;&#039; or mw.site.namespaces[ns] then&lt;br /&gt;
		return s&lt;br /&gt;
	else&lt;br /&gt;
		return &#039;Template:&#039; .. s&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function trimTemplate(s)&lt;br /&gt;
	local needle = &#039;template:&#039;&lt;br /&gt;
	if s:sub(1, needle:len()):lower() == needle then&lt;br /&gt;
		return s:sub(needle:len() + 1)&lt;br /&gt;
	else&lt;br /&gt;
		return s&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function linkTitle(args)&lt;br /&gt;
	if yesno(args.nolink) then&lt;br /&gt;
		return args[1]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local titleObj&lt;br /&gt;
	local titlePart = &#039;[[&#039;&lt;br /&gt;
	if args[1] then&lt;br /&gt;
		-- This handles :Page and other NS&lt;br /&gt;
		titleObj = mw.title.new(args[1], &#039;Template&#039;)&lt;br /&gt;
	else&lt;br /&gt;
		titleObj = mw.title.getCurrentTitle()&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	titlePart = titlePart .. (titleObj ~= nil and titleObj.fullText or&lt;br /&gt;
				addTemplate(args[1]))&lt;br /&gt;
&lt;br /&gt;
	local textPart = args.alttext&lt;br /&gt;
	if not _ne(textPart) then&lt;br /&gt;
		if titleObj ~= nil then&lt;br /&gt;
			textPart = titleObj:inNamespace(&amp;quot;Template&amp;quot;) and args[1] or titleObj.fullText&lt;br /&gt;
		else&lt;br /&gt;
			-- redlink&lt;br /&gt;
			textPart = args[1]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if yesno(args.brace) then&lt;br /&gt;
		textPart = nw(&#039;{{&#039;) .. textPart .. nw(&#039;}}&#039;)&lt;br /&gt;
	elseif yesno(args.braceinside) then&lt;br /&gt;
		textPart = nw(&#039;{&#039;) .. textPart .. nw(&#039;}&#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	titlePart = titlePart .. &#039;|&#039; .. textPart .. &#039;]]&#039;&lt;br /&gt;
	if yesno(args.braceinside) then&lt;br /&gt;
		titlePart = nw(&#039;{&#039;) .. titlePart .. nw(&#039;}&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return titlePart&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
	local args = getArgs(frame, {&lt;br /&gt;
		trim = true,&lt;br /&gt;
		removeBlanks = false,&lt;br /&gt;
		frameOnly = false,&lt;br /&gt;
		wrappers = {&lt;br /&gt;
			&amp;quot;Template:Tlg&amp;quot;,&lt;br /&gt;
			&amp;quot;Template:Template link general&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
	return p._main(args)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._main(args)&lt;br /&gt;
	-- TemplateStyles&lt;br /&gt;
	local templateStyles = {&lt;br /&gt;
		mono   = false,&lt;br /&gt;
		nowrap = false,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local bold = yesno(args.bold) or yesno(args.boldlink) or yesno(args.boldname)&lt;br /&gt;
	local italic = yesno(args.italic) or yesno(args.italics)&lt;br /&gt;
	local dontBrace = yesno(args.brace) or yesno(args.braceinside)&lt;br /&gt;
	local code = yesno(args.code) or yesno(args.tt)&lt;br /&gt;
	local show_result = yesno(args._show_result)&lt;br /&gt;
	local expand = yesno(args._expand)&lt;br /&gt;
	local classes = {}&lt;br /&gt;
&lt;br /&gt;
	-- Build the link part&lt;br /&gt;
	local titlePart = linkTitle(args)&lt;br /&gt;
	if bold then titlePart = &amp;quot;&#039;&#039;&#039;&amp;quot; .. titlePart .. &amp;quot;&#039;&#039;&#039;&amp;quot; end&lt;br /&gt;
&lt;br /&gt;
	if yesno(args.subst) then&lt;br /&gt;
		local substLink = cfg[&#039;subst-link&#039;]&lt;br /&gt;
		if _ne(substLink) and yesno(args[&#039;link subst&#039;]) then&lt;br /&gt;
			titlePart = &#039;[[&#039; .. substLink .. &#039;|subst]]:&#039; .. titlePart&lt;br /&gt;
		else&lt;br /&gt;
			titlePart = &#039;subst:&#039; .. titlePart&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if yesno(args.nowrapname) then&lt;br /&gt;
		templateStyles.nowrap = true&lt;br /&gt;
		titlePart = &#039;&amp;lt;span class=&amp;quot;nowrap&amp;quot;&amp;gt;&#039; .. titlePart .. &#039;&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Build the arguments&lt;br /&gt;
	local textPart = &amp;quot;&amp;quot;&lt;br /&gt;
	local textPartBuffer = &amp;quot;&amp;amp;#124;&amp;quot;&lt;br /&gt;
	local codeArguments = {}&lt;br /&gt;
	local codeArgumentsString = &amp;quot;&amp;quot;&lt;br /&gt;
	local i = 2&lt;br /&gt;
	local j = 1&lt;br /&gt;
	while args[i] do&lt;br /&gt;
		local val = args[i]&lt;br /&gt;
		if val ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			if yesno(args.nowiki) then&lt;br /&gt;
				-- Unstrip nowiki tags first because calling nw on something that already contains nowiki tags will&lt;br /&gt;
				-- mangle the nowiki strip marker and result in literal UNIQ...QINU showing up&lt;br /&gt;
				val = nw(mw.text.unstripNoWiki(val))&lt;br /&gt;
			end&lt;br /&gt;
			local k, v = string.match(val, &amp;quot;(.*)=(.*)&amp;quot;)&lt;br /&gt;
			if not k then&lt;br /&gt;
				codeArguments[j] = val&lt;br /&gt;
				j = j + 1&lt;br /&gt;
			else&lt;br /&gt;
				codeArguments[k] = v&lt;br /&gt;
			end&lt;br /&gt;
			codeArgumentsString = codeArgumentsString .. textPartBuffer .. val&lt;br /&gt;
			if italic then&lt;br /&gt;
				val = &#039;&amp;lt;span style=&amp;quot;font-style:italic;&amp;quot;&amp;gt;&#039; .. val .. &#039;&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
			end&lt;br /&gt;
			textPart = textPart .. textPartBuffer .. val&lt;br /&gt;
		end&lt;br /&gt;
		i = i + 1&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local tagName = nil&lt;br /&gt;
	local css = nil&lt;br /&gt;
&lt;br /&gt;
	-- final wrap&lt;br /&gt;
	local ret = titlePart .. textPart&lt;br /&gt;
	if not dontBrace then ret = nw(&#039;{{&#039;) .. ret .. nw(&#039;}}&#039;) end&lt;br /&gt;
	if yesno(args.a) then ret = nw(&#039;*&#039;) .. &#039;&amp;amp;nbsp;&#039; .. ret end&lt;br /&gt;
	if yesno(args.kbd) then&lt;br /&gt;
		tagName = &#039;kbd&#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if yesno(args.mono) then&lt;br /&gt;
		templateStyles.mono = true&lt;br /&gt;
		table.insert(classes, &#039;monospaced&#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local plaincode = yesno(args.plaincode) and not code&lt;br /&gt;
	if code or plaincode then&lt;br /&gt;
		if tagName then&lt;br /&gt;
			-- kbd == true &amp;amp;&amp;amp; code == true&lt;br /&gt;
			ret = (&#039;&amp;lt;%s&amp;gt;%s&amp;lt;/%s&amp;gt;&#039;):format(tagName, ret, tagName)&lt;br /&gt;
		end&lt;br /&gt;
		tagName = &#039;code&#039;&lt;br /&gt;
		if plaincode then&lt;br /&gt;
			css = {&lt;br /&gt;
				background = &#039;transparent&#039;,&lt;br /&gt;
				border     = &#039;none&#039;,&lt;br /&gt;
				color      = &#039;var(--color-emphasized, #101418)&#039;,&lt;br /&gt;
			}&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if show_result then&lt;br /&gt;
		local result = mw.getCurrentFrame():expandTemplate{title = addTemplate(args[1]), args = codeArguments}&lt;br /&gt;
		ret = ret .. &amp;quot; → &amp;quot; .. result&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if expand then&lt;br /&gt;
		local query = mw.text.encode(&#039;{{&#039; .. addTemplate(args[1]) .. string.gsub(codeArgumentsString, textPartBuffer, &amp;quot;|&amp;quot;) .. &#039;}}&#039;)&lt;br /&gt;
		local url = mw.uri.fullUrl(&#039;special:ExpandTemplates&#039;, &#039;wpInput=&#039; .. query)&lt;br /&gt;
		mw.log()&lt;br /&gt;
		ret = ret .. &amp;quot; [&amp;quot; .. tostring(url) .. &amp;quot;]&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if yesno(args.nowrap) then&lt;br /&gt;
		templateStyles.nowrap = true&lt;br /&gt;
		table.insert(classes, &#039;nowrap&#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if tagName or #classes &amp;gt; 0 or css then&lt;br /&gt;
		local span = mw.html.create(tagName or &#039;span&#039;)&lt;br /&gt;
			:addClass(table.concat(classes, &#039; &#039;))&lt;br /&gt;
			:wikitext(ret)&lt;br /&gt;
&lt;br /&gt;
		if css then&lt;br /&gt;
			span:css(css)&lt;br /&gt;
		end&lt;br /&gt;
		ret = tostring(span:allDone())&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local ts = {}&lt;br /&gt;
	if templateStyles.mono then&lt;br /&gt;
		table.insert(ts, mw.getCurrentFrame():extensionTag{&lt;br /&gt;
			name = &#039;templatestyles&#039;,&lt;br /&gt;
			args = { src = &#039;Template:Mono/styles.css&#039; }&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if templateStyles.nowrap then&lt;br /&gt;
		table.insert(ts, mw.getCurrentFrame():extensionTag{&lt;br /&gt;
			name = &#039;templatestyles&#039;,&lt;br /&gt;
			args = { src = &#039;Template:Nowrap/styles.css&#039; }&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if yesno(args.debug) then&lt;br /&gt;
		ret = ret .. &#039;\n&amp;lt;pre&amp;gt;&#039; .. mw.text.encode(mw.dumpObject(args)) .. &#039;&amp;lt;/pre&amp;gt;&#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(ts) .. ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Li&amp;diff=1537</id>
		<title>Li</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Li&amp;diff=1537"/>
		<updated>2026-08-17T22:07:18Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT {{Localized link}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Li&amp;diff=1536</id>
		<title>Li</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Li&amp;diff=1536"/>
		<updated>2026-08-17T22:07:00Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT {{Template:Localized link}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Li&amp;diff=1535</id>
		<title>Li</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Li&amp;diff=1535"/>
		<updated>2026-08-17T22:06:47Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT {{Template:Locaized link}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Li&amp;diff=1534</id>
		<title>Li</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Li&amp;diff=1534"/>
		<updated>2026-08-17T22:06:24Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;#REDIRECT {{Locaized link}}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT {{Locaized link}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Template:Doc&amp;diff=1533</id>
		<title>Template:Doc</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Template:Doc&amp;diff=1533"/>
		<updated>2026-08-17T22:02:57Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;#REDIRECT{{Documentation}}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT{{Documentation}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Template:Documentation&amp;diff=1532</id>
		<title>Template:Documentation</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Template:Documentation&amp;diff=1532"/>
		<updated>2026-08-17T22:01:01Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;&amp;lt;noinclude&amp;gt; &amp;lt;languages/&amp;gt; &amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;{{#invoke:documentation|main|_content={{ {{#invoke:documentation|contentTitle}}}}}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt; {{documentation|content=  {{Lua|Module:Documentation}} &amp;lt;translate&amp;gt;&amp;lt;!--T:12--&amp;gt; This template automatically displays a documentation box like the one you are seeing now, of which the content is sometimes transcluded from another page.&amp;lt;/translate&amp;gt; &amp;lt;translate&amp;gt;&amp;lt;!--T:13--&amp;gt; It is intended for pages which are &amp;lt;tvar name=...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;languages/&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;{{#invoke:documentation|main|_content={{ {{#invoke:documentation|contentTitle}}}}}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{documentation|content=&lt;br /&gt;
&lt;br /&gt;
{{Lua|Module:Documentation}}&lt;br /&gt;
&amp;lt;translate&amp;gt;&amp;lt;!--T:12--&amp;gt; This template automatically displays a documentation box like the one you are seeing now, of which the content is sometimes transcluded from another page.&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&amp;lt;!--T:13--&amp;gt; It is intended for pages which are [[&amp;lt;tvar name=1&amp;gt;Special:MyLanguage/Help:Transclusion&amp;lt;/tvar&amp;gt;|transcluded]] in other pages, i.e. templates, whether in the template namespace or not.&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Usage == &amp;lt;!--T:2--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Customising display === &amp;lt;!--T:3--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--T:4--&amp;gt;&lt;br /&gt;
Overrides exist to customise the output in special cases:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;{{&amp;lt;/nowiki&amp;gt;documentation{{!}}&#039;&#039;&#039;heading&#039;&#039;&#039;=&amp;lt;nowiki&amp;gt;}}&amp;lt;/nowiki&amp;gt; - &amp;lt;translate&amp;gt;&amp;lt;!--T:5--&amp;gt; change the text of the &amp;quot;documentation&amp;quot; heading.&amp;lt;/translate&amp;gt; &amp;lt;translate&amp;gt;&amp;lt;!--T:10--&amp;gt; If this is set to blank, the entire heading line (including the first [edit] link) will also disappear.&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Rationale == &amp;lt;!--T:6--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&amp;lt;!--T:7--&amp;gt; This template allows any page to use any documentation page, and makes it possible to protect templates while allowing anyone to edit the template&#039;s documentation and categories.&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&amp;lt;!--T:8--&amp;gt; It also reduces server resources by circumventing a [[w:Wikipedia:Template limits|technical limitation of templates]] (see a [[&amp;lt;tvar name=1&amp;gt;:en:Special:Diff/69888944&amp;lt;/tvar&amp;gt;|developer&#039;s explanation]]).&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== See also == &amp;lt;!--T:9--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
* &amp;lt;translate&amp;gt;&amp;lt;!--T:14--&amp;gt; [[w:Template:Documentation subpage]]&amp;lt;/translate&amp;gt;&lt;br /&gt;
* {{tim|Documentation}}&lt;br /&gt;
* &amp;lt;translate&amp;gt;&amp;lt;!--T:11--&amp;gt; [[w:Wikipedia:Template documentation]]&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
[[Category:Formatting templates{{#translation:}}|Template documentation]]&lt;br /&gt;
[[Category:Template documentation{{#translation:}}| ]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;{{#if:{{{content|}}}|&lt;br /&gt;
[[Category:Template documentation pages{{#translation:}}]]&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Template_translation&amp;diff=1527</id>
		<title>Module:Template translation</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Template_translation&amp;diff=1527"/>
		<updated>2026-08-17T21:49:22Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;local this = {}  function this.checkLanguage(subpage, default)     --[[Check first if there&amp;#039;s an any invalid character that would cause the         mw.language.isKnownLanguageTag function() to throw an exception:         - all ASCII controls in [\000-\031\127],         - double quote (&amp;quot;), sharp sign (#), ampersand (&amp;amp;), apostrophe (&amp;#039;),         - slash (/), colon (:), semicolon (;), lower than (&amp;lt;), greater than (&amp;gt;),         - brackets and braces ([, ], {, }), pipe (|), bac...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local this = {}&lt;br /&gt;
&lt;br /&gt;
function this.checkLanguage(subpage, default)&lt;br /&gt;
    --[[Check first if there&#039;s an any invalid character that would cause the&lt;br /&gt;
        mw.language.isKnownLanguageTag function() to throw an exception:&lt;br /&gt;
        - all ASCII controls in [\000-\031\127],&lt;br /&gt;
        - double quote (&amp;quot;), sharp sign (#), ampersand (&amp;amp;), apostrophe (&#039;),&lt;br /&gt;
        - slash (/), colon (:), semicolon (;), lower than (&amp;lt;), greater than (&amp;gt;),&lt;br /&gt;
        - brackets and braces ([, ], {, }), pipe (|), backslash (\\)&lt;br /&gt;
        All other characters are accepted, including space and all non-ASCII&lt;br /&gt;
        characters (including \192, which is invalid in UTF-8).&lt;br /&gt;
    --]]&lt;br /&gt;
    if mw.language.isValidCode(subpage) and mw.language.isKnownLanguageTag(subpage)&lt;br /&gt;
    --[[However &amp;quot;SupportedLanguages&amp;quot; are too restrictive, as they discard many&lt;br /&gt;
        valid BCP47 script variants (only because MediaWiki still does not&lt;br /&gt;
        define automatic transliterators for them, e.g. &amp;quot;en-dsrt&amp;quot; or&lt;br /&gt;
        &amp;quot;fr-brai&amp;quot; for French transliteration in Braille), and country variants,&lt;br /&gt;
        (useful in localized data, even if they are no longer used for&lt;br /&gt;
        translations, such as zh-cn, also useful for legacy codes).&lt;br /&gt;
        We want to avoid matching subpagenames containing any uppercase letter,&lt;br /&gt;
        (even if they are considered valid in BCP 47, in which they are&lt;br /&gt;
        case-insensitive; they are not &amp;quot;SupportedLanguages&amp;quot; for MediaWiki, so&lt;br /&gt;
        they are not &amp;quot;KnownLanguageTags&amp;quot; for MediaWiki).&lt;br /&gt;
        To be more restrictive, we exclude tags&lt;br /&gt;
        * for specific uses in template subpages and unusable as language tags;&lt;br /&gt;
        * that is not ASCII and not a lowercase letter, minus-hyphen, or digit,&lt;br /&gt;
          or does not start by a letter or does not finish by a letter or digit;&lt;br /&gt;
        * or that has subtags with more than 8 characters between hyphens;&lt;br /&gt;
        * or that has two hyphens.&lt;br /&gt;
    --]]&lt;br /&gt;
    or  subpage ~= &amp;quot;doc&amp;quot;&lt;br /&gt;
    and subpage ~= &amp;quot;layout&amp;quot;&lt;br /&gt;
    and subpage ~= &amp;quot;button&amp;quot;&lt;br /&gt;
    and subpage ~= &amp;quot;buttons&amp;quot;&lt;br /&gt;
    and subpage ~= &amp;quot;sandbox&amp;quot;&lt;br /&gt;
    and subpage ~= &amp;quot;testcase&amp;quot;&lt;br /&gt;
    and subpage ~= &amp;quot;testcases&amp;quot;&lt;br /&gt;
    and string.find(subpage, &amp;quot;^[%l][%-%d%l]*[%d%l]$&amp;quot;) ~= nil&lt;br /&gt;
    and string.find(subpage, &amp;quot;[%d%l][%d%l][%d%l][%d%l][%d%l][%d%l][%d%l][%d%l][%d%l]&amp;quot;) == nil&lt;br /&gt;
    and string.find(subpage, &amp;quot;%-%-&amp;quot;) == nil then&lt;br /&gt;
        return subpage&lt;br /&gt;
    end&lt;br /&gt;
    -- Otherwise there&#039;s currently no known language subpage&lt;br /&gt;
    return default&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[Get the last subpage of an arbitrary page if it is a translation.&lt;br /&gt;
    To be used from templates.&lt;br /&gt;
    ]]&lt;br /&gt;
function this.getLanguageSubpage(frame)&lt;br /&gt;
	local title = frame and frame.args[1]&lt;br /&gt;
	if not title or title == &#039;&#039; then&lt;br /&gt;
		title = mw.title.getCurrentTitle()&lt;br /&gt;
	end&lt;br /&gt;
	return this._getLanguageSubpage(title)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[Get the last subpage of an arbitrary page if it is a translation.&lt;br /&gt;
    To be used from Lua.&lt;br /&gt;
    ]]&lt;br /&gt;
function this._getLanguageSubpage(title)&lt;br /&gt;
	if type(title) == &#039;string&#039; then&lt;br /&gt;
		title = mw.title.new(title)&lt;br /&gt;
	end&lt;br /&gt;
	if not title then&lt;br /&gt;
		-- invalid title&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	--[[This code does not work in all namespaces where the Translate tool works.&lt;br /&gt;
	--  It works in the main namespace on Meta because it allows subpages there&lt;br /&gt;
	--  It would not work in the main namespace of English Wikipedia (but the&lt;br /&gt;
	--  articles are monolignual on that wiki).&lt;br /&gt;
	--  On Meta-Wiki the main space uses subpages and its pages are translated.&lt;br /&gt;
	--  The Translate tool allows translatng pages in all namespaces, even if&lt;br /&gt;
	--  the namespace officially does not have subpages.&lt;br /&gt;
	--  On Meta-Wiki the Category namespace still does not have subpages enabled,&lt;br /&gt;
	--  even if they would be very useful for categorizing templates, that DO have&lt;br /&gt;
	--  subpages (for documentatio and tstboxes pages). This is a misconfiguration&lt;br /&gt;
	--  bug of Meta-Wiki. The work-around is to split the full title and then&lt;br /&gt;
	--  get the last titlepart.&lt;br /&gt;
	local subpage = title.subpageText&lt;br /&gt;
	--]]&lt;br /&gt;
	local titleparts = mw.text.split(title.fullText, &#039;/&#039;)&lt;br /&gt;
	local subpage = titleparts[#titleparts]&lt;br /&gt;
	return this.checkLanguage(subpage, &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[Get the last subpage of the current page if it is a translation.&lt;br /&gt;
    ]]&lt;br /&gt;
function this.getCurrentLanguageSubpage()&lt;br /&gt;
	return this._getLanguageSubpage(mw.title.getCurrentTitle())&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[Get the first part of the language code of the subpage, before the &#039;-&#039;.&lt;br /&gt;
--]]&lt;br /&gt;
function this.getMainLanguageSubpage()&lt;br /&gt;
	parts = mw.text.split(this.getCurrentLanguageSubpage(), &#039;-&#039;)&lt;br /&gt;
	return parts[1]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[Get the last subpage of the current frame if it is a translation.&lt;br /&gt;
    Not used locally.&lt;br /&gt;
--]]&lt;br /&gt;
function this.getFrameLanguageSubpage(frame)&lt;br /&gt;
	return this._getLanguageSubpage(frame:getParent():getTitle())&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[Get the language of the current page. Not used locally.&lt;br /&gt;
--]]&lt;br /&gt;
function this.getLanguage()&lt;br /&gt;
    local subpage = mw.title.getCurrentTitle().subpageText&lt;br /&gt;
    return this.checkLanguage(subpage, mw.language.getContentLanguage():getCode())&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[Get the language of the current frame. Not used locally.&lt;br /&gt;
--]]&lt;br /&gt;
function this.getFrameLanguage(frame)&lt;br /&gt;
    local titleparts = mw.text.split(frame:getParent():getTitle(), &#039;/&#039;)&lt;br /&gt;
    local subpage = titleparts[#titleparts]&lt;br /&gt;
    return this.checkLanguage(subpage, mw.language.getContentLanguage():getCode())&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function this.title(namespace, basepagename, subpage)&lt;br /&gt;
    local message, title&lt;br /&gt;
    local pagename = basepagename&lt;br /&gt;
    if (subpage or &#039;&#039;) ~= &#039;&#039; then&lt;br /&gt;
        pagename = pagename .. &#039;/&#039; .. subpage&lt;br /&gt;
    end&lt;br /&gt;
    local valid, title = xpcall(function()&lt;br /&gt;
            return mw.title.new(pagename, namespace) -- costly&lt;br /&gt;
        end, function(msg) -- catch undocumented exception (!?)&lt;br /&gt;
            -- thrown when namespace does not exist. The doc still&lt;br /&gt;
            -- says it should return a title, even in that case...&lt;br /&gt;
            message = msg&lt;br /&gt;
        end)&lt;br /&gt;
    if valid and title ~= nil and (title.id or 0) ~= 0 then&lt;br /&gt;
        return title&lt;br /&gt;
    end&lt;br /&gt;
    return { -- &amp;quot;pseudo&amp;quot; mw.title object with id = nil in case of error&lt;br /&gt;
        prefixedText = pagename, -- the only property we need below&lt;br /&gt;
        message = message -- only for debugging&lt;br /&gt;
    }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[If on a translation subpage (like Foobar/de), this function returns&lt;br /&gt;
    a given template in the same language, if the translation is available.&lt;br /&gt;
    Otherwise, the template is returned in its default language, without&lt;br /&gt;
    modification.&lt;br /&gt;
    This is aimed at replacing the current implementation of Template:TNTN.&lt;br /&gt;
&lt;br /&gt;
    This version does not expand the returned template name: this solves the&lt;br /&gt;
    problem of self-recursion in TNT when translatable templates need themselves&lt;br /&gt;
    to transclude other translable templates (such as Tnavbar).&lt;br /&gt;
--]]&lt;br /&gt;
function this.getTranslatedTemplate(frame, withStatus)&lt;br /&gt;
    local args = frame.args&lt;br /&gt;
    local pagename = args[&#039;template&#039;]&lt;br /&gt;
    --[[Check whether the pagename is actually in the Template namespace, or&lt;br /&gt;
        if we&#039;re transcluding a main-namespace page.&lt;br /&gt;
        (added for backward compatibility of Template:TNT)&lt;br /&gt;
        ]]&lt;br /&gt;
    local namespace, title = args[&#039;tntns&#039;] or &#039;&#039;&lt;br /&gt;
    if namespace ~= &#039;&#039; then -- Checks for tntns parameter for custom ns.&lt;br /&gt;
        title = this.title(namespace, pagename) -- Costly&lt;br /&gt;
    else -- Supposes that set page is in ns10.&lt;br /&gt;
    	namespace = &#039;Template&#039;&lt;br /&gt;
        title = this.title(namespace, pagename) -- Costly&lt;br /&gt;
        if title.id == nil then -- not found in the Template namespace, assume the main namespace (for backward compatibility)&lt;br /&gt;
    	    namespace = &#039;&#039;&lt;br /&gt;
            title = this.title(namespace, pagename) -- Costly&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    -- Get the last subpage and check if it matches a known language code.&lt;br /&gt;
    local subpage = args[&#039;uselang&#039;] or &#039;&#039;&lt;br /&gt;
    if subpage == &#039;&#039; then&lt;br /&gt;
        subpage = this.getCurrentLanguageSubpage()&lt;br /&gt;
    end&lt;br /&gt;
    if subpage == &#039;&#039; then&lt;br /&gt;
        -- Check if a translation of the pagename exists in English&lt;br /&gt;
        local newtitle = this.title(namespace, pagename, &#039;en&#039;) -- Costly&lt;br /&gt;
        -- Use the translation when it exists&lt;br /&gt;
        if newtitle.id ~= nil then&lt;br /&gt;
            title = newtitle&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        -- Check if a translation of the pagename exists in that language&lt;br /&gt;
        local newtitle = this.title(namespace, pagename, subpage) -- Costly&lt;br /&gt;
        if newtitle.id == nil then&lt;br /&gt;
            -- Check if a translation of the pagename exists in English&lt;br /&gt;
            newtitle = this.title(namespace, pagename, &#039;en&#039;) -- Costly&lt;br /&gt;
        end&lt;br /&gt;
        -- Use the translation when it exists&lt;br /&gt;
        if newtitle.id ~= nil then&lt;br /&gt;
            title = newtitle&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    -- At this point the title should exist&lt;br /&gt;
    if withStatus then&lt;br /&gt;
    	-- status returned to Lua function below&lt;br /&gt;
        return title.prefixedText, title.id ~= nil&lt;br /&gt;
    else&lt;br /&gt;
    	-- returned directly to MediaWiki&lt;br /&gt;
        return title.prefixedText&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[If on a translation subpage (like Foobar/de), this function renders&lt;br /&gt;
    a given template in the same language, if the translation is available.&lt;br /&gt;
    Otherwise, the template is rendered in its default language, without&lt;br /&gt;
    modification.&lt;br /&gt;
    This is aimed at replacing the current implementation of Template:TNT.&lt;br /&gt;
    &lt;br /&gt;
    Note that translatable templates cannot transclude themselves other&lt;br /&gt;
    translatable templates, as it will recurse on TNT. Use TNTN instead&lt;br /&gt;
    to return only the effective template name to expand externally, with&lt;br /&gt;
    template parameters also provided externally.&lt;br /&gt;
--]]&lt;br /&gt;
function this.renderTranslatedTemplate(frame)&lt;br /&gt;
	local title, found = this.getTranslatedTemplate(frame, true)&lt;br /&gt;
    -- At this point the title should exist prior to performing the expansion&lt;br /&gt;
    -- of the template, otherwise render a red link to the missing page&lt;br /&gt;
    -- (resolved in its assumed namespace). If we don&#039;t tet this here, a&lt;br /&gt;
    -- script error would be thrown. Returning a red link is consistant with&lt;br /&gt;
    -- MediaWiki behavior when attempting to transclude inexistant templates.&lt;br /&gt;
	if not found then&lt;br /&gt;
		return &#039;[[&#039; .. title .. &#039;]]&#039;&lt;br /&gt;
	end&lt;br /&gt;
    -- Copy args pseudo-table to a proper table so we can feed it to expandTemplate.&lt;br /&gt;
    -- Then render the pagename.&lt;br /&gt;
    local args = frame.args&lt;br /&gt;
    local pargs = (frame:getParent() or {}).args&lt;br /&gt;
    local arguments = {}&lt;br /&gt;
    if (args[&#039;noshift&#039;] or &#039;&#039;) == &#039;&#039; then&lt;br /&gt;
        for k, v in pairs(pargs) do&lt;br /&gt;
            local n = tonumber(k) or 0&lt;br /&gt;
            if n &amp;lt;= 0 then -- unnumbered args&lt;br /&gt;
                arguments[k] = v&lt;br /&gt;
            elseif n &amp;gt;= 2 then -- numbered args &amp;gt;= 2 need to be shifted&lt;br /&gt;
                arguments[n - 1] = v&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    else -- special case where TNT is used as autotranslate&lt;br /&gt;
    	-- (don&#039;t shift again what is shifted in the invokation)&lt;br /&gt;
        for k, v in pairs(pargs) do&lt;br /&gt;
            arguments[k] = v&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    arguments[&#039;template&#039;] = title -- override the existing parameter of the base template name supplied with the full name of the actual template expanded&lt;br /&gt;
    arguments[&#039;tntns&#039;] = nil -- discard the specified namespace override&lt;br /&gt;
    arguments[&#039;uselang&#039;] = args[&#039;uselang&#039;] -- argument forwarded into parent frame&lt;br /&gt;
    arguments[&#039;noshift&#039;] = args[&#039;noshift&#039;] -- argument forwarded into parent frame&lt;br /&gt;
    return frame:expandTemplate{title = &#039;:&#039; .. title, args = arguments}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[A helper for mocking TNT in Special:TemplateSandbox. TNT breaks&lt;br /&gt;
    TemplateSandbox; mocking it with this method means templates won&#039;t be&lt;br /&gt;
    localized but at least TemplateSandbox substitutions will work properly.&lt;br /&gt;
    Won&#039;t work with complex uses.&lt;br /&gt;
--]]&lt;br /&gt;
function this.mockTNT(frame)&lt;br /&gt;
    local pargs = (frame:getParent() or {}).args&lt;br /&gt;
    local arguments = {}&lt;br /&gt;
    for k, v in pairs(pargs) do&lt;br /&gt;
        local n = tonumber(k) or 0&lt;br /&gt;
        if n &amp;lt;= 0 then -- unnumbered args&lt;br /&gt;
            arguments[k] = v&lt;br /&gt;
        elseif n &amp;gt;= 2 then -- numbered args &amp;gt;= 2 need to be shifted&lt;br /&gt;
            arguments[n - 1] = v&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    if not pargs[1] then&lt;br /&gt;
    	return &#039;&#039;&lt;br /&gt;
	end&lt;br /&gt;
    return frame:expandTemplate{title = &#039;Template:&#039; .. pargs[1], args = arguments}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return this&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Transclusion_count&amp;diff=1526</id>
		<title>Module:Transclusion count</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Transclusion_count&amp;diff=1526"/>
		<updated>2026-08-17T21:45:14Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;local p = {}  function p._fetch(args) 	local template = nil 	local return_value = nil  	-- Use demo parameter if it exists, otherwise use current template name 	local namespace = mw.title.getCurrentTitle().namespace 	if args[&amp;quot;demo&amp;quot;] and args[&amp;quot;demo&amp;quot;] ~= &amp;quot;&amp;quot; then 		template = mw.ustring.gsub(args[&amp;quot;demo&amp;quot;],&amp;quot;^[Tt]emplate:&amp;quot;,&amp;quot;&amp;quot;) 	elseif namespace == 10 then -- Template namespace 		template = mw.title.getCurrentTitle().text 	elseif namespace == 828 then -- Module namespace 		temp...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local p = {}&lt;br /&gt;
&lt;br /&gt;
function p._fetch(args)&lt;br /&gt;
	local template = nil&lt;br /&gt;
	local return_value = nil&lt;br /&gt;
&lt;br /&gt;
	-- Use demo parameter if it exists, otherwise use current template name&lt;br /&gt;
	local namespace = mw.title.getCurrentTitle().namespace&lt;br /&gt;
	if args[&amp;quot;demo&amp;quot;] and args[&amp;quot;demo&amp;quot;] ~= &amp;quot;&amp;quot; then&lt;br /&gt;
		template = mw.ustring.gsub(args[&amp;quot;demo&amp;quot;],&amp;quot;^[Tt]emplate:&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
	elseif namespace == 10 then -- Template namespace&lt;br /&gt;
		template = mw.title.getCurrentTitle().text&lt;br /&gt;
	elseif namespace == 828 then -- Module namespace&lt;br /&gt;
		template = (mw.site.namespaces[828].name .. &amp;quot;:&amp;quot; .. mw.title.getCurrentTitle().text)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- If in template or module namespace, look up count in /data&lt;br /&gt;
	if template ~= nil then&lt;br /&gt;
		namespace = mw.title.new(template, &amp;quot;Template&amp;quot;).namespace&lt;br /&gt;
		if namespace == 10 or namespace == 828 then&lt;br /&gt;
			template =  mw.ustring.gsub(template, &amp;quot;/doc$&amp;quot;, &amp;quot;&amp;quot;) -- strip /doc from end&lt;br /&gt;
			template =  mw.ustring.gsub(template, &amp;quot;/sandbox$&amp;quot;, &amp;quot;&amp;quot;) -- strip /sandbox from end&lt;br /&gt;
			local index = mw.ustring.sub(mw.title.new(template).text,1,1)&lt;br /&gt;
			local status, data = pcall(function ()&lt;br /&gt;
				return(mw.loadData(&#039;Module:Transclusion_count/data/&#039; .. (mw.ustring.find(index, &amp;quot;%a&amp;quot;) and index or &amp;quot;other&amp;quot;)))&lt;br /&gt;
			end)&lt;br /&gt;
			if status then&lt;br /&gt;
				return_value = tonumber(data[mw.ustring.gsub(template, &amp;quot; &amp;quot;, &amp;quot;_&amp;quot;)])&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- If database value doesn&#039;t exist, use value passed to template&lt;br /&gt;
	if return_value == nil and args[1] ~= nil then&lt;br /&gt;
		local arg1=mw.ustring.match(args[1], &#039;[%d,]+&#039;)&lt;br /&gt;
		if arg1 and arg1 ~= &#039;&#039; then&lt;br /&gt;
			return_value = tonumber(mw.getCurrentFrame():callParserFunction(&#039;formatnum&#039;, arg1, &#039;R&#039;))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return return_value	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.fetch(frame)&lt;br /&gt;
	return p._fetch(frame.args)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Tabulate this data for [[Wikipedia:Database reports/Templates transcluded on the most pages]]&lt;br /&gt;
function p.tabulate()&lt;br /&gt;
	local list = {}&lt;br /&gt;
	for i = 65, 91 do&lt;br /&gt;
		local data = mw.loadData(&#039;Module:Transclusion count/data/&#039; .. ((i == 91) and &#039;other&#039; or string.char(i)))&lt;br /&gt;
		for name, count in pairs(data) do&lt;br /&gt;
			local title = mw.title.new(name, &amp;quot;Template&amp;quot;)&lt;br /&gt;
			table.insert(list, {title, count})&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(list, function(a, b)&lt;br /&gt;
		return (a[2] == b[2]) and (a[1] &amp;lt; b[1]) or (a[2] &amp;gt; b[2])&lt;br /&gt;
	end)&lt;br /&gt;
	local lang = mw.getContentLanguage();&lt;br /&gt;
	for i = 1, #list do&lt;br /&gt;
		local protLevel = &amp;quot;&amp;quot;&lt;br /&gt;
		local title = list[i][1]&lt;br /&gt;
		if i &amp;lt; 400 then&lt;br /&gt;
			-- Stop at 400 to avoid breaching the expensive parser function call limit&lt;br /&gt;
			protLevel = title.protectionLevels.edit[1] or &amp;quot;(unprotected)&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
		list[i] = (&#039;|-\n| %d || [[%s]] || %s || %s \n&#039;):format(i, title.fullText:gsub(&#039;_&#039;, &#039; &#039;), lang:formatNum(list[i][2]), protLevel)&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(list)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Template:Localized_link&amp;diff=1525</id>
		<title>Template:Localized link</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Template:Localized_link&amp;diff=1525"/>
		<updated>2026-08-17T21:41:29Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;languages/&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;!--&lt;br /&gt;
--&amp;gt;{{#ifeq:{{FULLPAGENAME:{{{1}}}}}|{{FULLPAGENAME:{{translatable}}}}&amp;lt;!--self link (including translation pages)--&amp;gt;&lt;br /&gt;
  |&amp;lt;b&amp;gt;&lt;br /&gt;
}}&amp;lt;!----&amp;gt;[[Special:MyLanguage/{{{1}}}|{{#if:{{{2|}}}&lt;br /&gt;
|{{{2}}}&lt;br /&gt;
|{{{2|{{#ifexist:Translations:{{#if:{{NAMESPACE:{{{1}}}}}|{{NAMESPACE:{{{1}}}}}:}}{{PAGENAME:{{{1}}}}}/Page display title/{{PAGELANGUAGE}}&amp;lt;!--if the source page, PAGELANGUAGE returns en--&amp;gt;&lt;br /&gt;
  |{{#ifexpr:{{#if:{{{nsp|}}}|1|0}} and {{NAMESPACENUMBER:{{{1}}}}}!=0&lt;br /&gt;
    |{{#ifeq:{{PAGELANGUAGE}}|en&lt;br /&gt;
      |{{PAGENAME:{{{1}}}}}&lt;br /&gt;
      |&amp;lt;!-- check whether the string is not empty --&amp;gt;&amp;lt;!--&lt;br /&gt;
    --&amp;gt;{{#if:{{PAGENAME:{{ {{TNTN|Translations:{{#if:{{NAMESPACE:{{{1}}}}}|{{NAMESPACE:{{{1}}}}}:}}{{PAGENAME:{{{1}}}}}/Page_display_title}} }} }}&lt;br /&gt;
         |{{#ifeq:{{#invoke:string|find|{{PAGENAME:{{ {{TNTN|Translations:{{#if:{{NAMESPACE:{{{1}}}}}|{{NAMESPACE:{{{1}}}}}:}}{{PAGENAME:{{{1}}}}}/Page_display_title}} }} }}|:}}|0&lt;br /&gt;
           |{{PAGENAME:{{ {{TNTN|Translations:{{#if:{{NAMESPACE:{{{1}}}}}|{{NAMESPACE:{{{1}}}}}:}}{{PAGENAME:{{{1}}}}}/Page_display_title}} }} }}&lt;br /&gt;
           | {{#invoke:string|match|{{PAGENAME:{{ {{TNTN|Translations:{{#if:{{NAMESPACE:{{{1}}}}}|{{NAMESPACE:{{{1}}}}}:}}{{PAGENAME:{{{1}}}}}/Page_display_title}} }} }}|:(.*)}}&lt;br /&gt;
         }}&lt;br /&gt;
         |&amp;lt;!-- pass parameter to, e.g., &amp;quot;Template:LC zh&amp;quot;; check whether the string is not empty --&amp;gt;&amp;lt;!--&lt;br /&gt;
       --&amp;gt;{{#if:{{ {{TNTN|Translations:{{#if:{{NAMESPACE:{{{1}}}}}|{{NAMESPACE:{{{1}}}}}:}}{{PAGENAME:{{{1}}}}}/Page_display_title}} | nsp = 0 }}&lt;br /&gt;
           |{{ {{TNTN|Translations:{{#if:{{NAMESPACE:{{{1}}}}}|{{NAMESPACE:{{{1}}}}}:}}{{PAGENAME:{{{1}}}}}/Page_display_title}} | nsp = 0 }}&lt;br /&gt;
           |{{{1}}}&lt;br /&gt;
        }}&lt;br /&gt;
      }}&lt;br /&gt;
    }}&lt;br /&gt;
    |{{ {{TNTN|Translations:{{#if:{{NAMESPACE:{{{1}}}}}|{{NAMESPACE:{{{1}}}}}:}}{{PAGENAME:{{{1}}}}}/Page_display_title}} }}&lt;br /&gt;
  }}&lt;br /&gt;
  &amp;lt;!--if the translation page does not exist (or called from the source page), output as is--&amp;gt;&lt;br /&gt;
  |{{#if:{{{nsp|}}}&lt;br /&gt;
    |{{#if:{{PAGENAME:{{{1}}}}}&lt;br /&gt;
      |{{PAGENAME:{{{1}}}}}&lt;br /&gt;
      |{{{1}}}&lt;br /&gt;
    }}&lt;br /&gt;
    |{{{1}}}&lt;br /&gt;
  }}&lt;br /&gt;
}}&amp;lt;!--#ifexist--&amp;gt;&amp;lt;!--&lt;br /&gt;
--&amp;gt;}}}&amp;lt;!--{{{2|--&amp;gt;&amp;lt;!--&lt;br /&gt;
--&amp;gt;}}&amp;lt;!--#if:{{{2|}}}--&amp;gt;&amp;lt;!--&lt;br /&gt;
--&amp;gt;]]&amp;lt;!--&lt;br /&gt;
--&amp;gt;{{#ifeq:{{FULLPAGENAME:{{{1}}}}}|{{FULLPAGENAME:{{translatable}}}}&amp;lt;!--self link (including translation pages)--&amp;gt;&lt;br /&gt;
  |&amp;lt;/b&amp;gt;&lt;br /&gt;
}}&amp;lt;span style=&amp;quot;display:none&amp;quot;&amp;gt;[[:{{{1}}}| ]]&amp;lt;/span&amp;gt;&amp;lt;!-- T63547 --&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{documentation|content=&lt;br /&gt;
&lt;br /&gt;
{{tsh|ll|LL}}&lt;br /&gt;
{{High-use|35000}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Purpose == &amp;lt;!--T:1--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&amp;lt;!--T:8--&amp;gt; This helper template can be used to link to [[&amp;lt;tvar name=1&amp;gt;Special:LanguageStats&amp;lt;/tvar&amp;gt;|translatable pages]] in the user&#039;s language.&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&amp;lt;!--T:9--&amp;gt; It uses the special page prefix &amp;lt;tvar name=1&amp;gt;&amp;lt;code&amp;gt;Special:MyLanguage/&amp;lt;/code&amp;gt;&amp;lt;/tvar&amp;gt;, which checks if there is a translated version of a page in the user&#039;s language, and links to it if there is one, and links to a fallback language where available, or the default wiki language version (English in MediaWiki) if there isn&#039;t.&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Usage == &amp;lt;!--T:2--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
{{Localized link/doc}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:11--&amp;gt;&lt;br /&gt;
If the &amp;quot;&amp;lt;tvar name=1&amp;gt;&amp;lt;code&amp;gt;nsp&amp;lt;/code&amp;gt;&amp;lt;/tvar&amp;gt;&amp;quot; parameter is not defined, as link text this displays the full pagename (including the namespace); otherwise — if the &amp;quot;&amp;lt;tvar name=1&amp;gt;&amp;lt;code&amp;gt;nsp&amp;lt;/code&amp;gt;&amp;lt;/tvar&amp;gt;&amp;quot; parameter is defined to any value the link text displays the short pagename (without the namespace).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--T:25--&amp;gt;&lt;br /&gt;
When linking to a section within a page, the section is not displayed in the link text.&lt;br /&gt;
&lt;br /&gt;
=== Examples of simple usage === &amp;lt;!--T:3--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
{{(}}{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
{{!}}-&lt;br /&gt;
! &amp;lt;translate&amp;gt;&amp;lt;!--T:4--&amp;gt; Use&amp;lt;/translate&amp;gt;&lt;br /&gt;
! &amp;lt;translate&amp;gt;&amp;lt;!--T:5--&amp;gt; Becomes&amp;lt;/translate&amp;gt;&lt;br /&gt;
{{!}}-&lt;br /&gt;
{{!}} {{Tlx|ll|Communication}}&lt;br /&gt;
{{!}} {{ll|Communication}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
{{!}} {{Tlx|ll|Communication|コミュニケーション}}&lt;br /&gt;
{{!}} {{ll|Communication|コミュニケーション}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
{{!}} {{Tlx|ll|Project:About}}&lt;br /&gt;
{{!}} {{ll|Project:About}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
{{!}} {{Tlx|ll|Project:About#See_also}}&lt;br /&gt;
{{!}} {{ll|Project:About#See_also}}&lt;br /&gt;
{{!}}-&lt;br /&gt;
{{!}} {{Tlx|ll|Project:About|nsp{{=}}0}}&lt;br /&gt;
{{!}} {{ll|Project:About|nsp=0}}&lt;br /&gt;
{{!}}{{)}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Usage in translatable pages == &amp;lt;!--T:6--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--T:12--&amp;gt;&lt;br /&gt;
On pages prepared for translation with the &amp;lt;tvar name=1&amp;gt;{{ll|Extension:Translate|nsp=0}}&amp;lt;/tvar&amp;gt; extension, this template may be used in three ways.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;translate&amp;gt;&amp;lt;!--T:13--&amp;gt; Substitute this template, then embed the wikilink target in a &amp;lt;tvar name=1&amp;gt;{{#tag:syntaxhighlight|{{^(}}tvar name=id{{)^}}...{{^(}}/tvar{{)^}}|lang=html|inline=1}}&amp;lt;/tvar&amp;gt;, separate from the translatable text of the link.&amp;lt;/translate&amp;gt;&lt;br /&gt;
#: &amp;lt;translate&amp;gt;&amp;lt;!--T:26--&amp;gt; For example:&amp;lt;/translate&amp;gt; {{#tag:syntaxhighlight|Learn more {{{{^(}}tvar name=1{{)^}}ll|Communication{{^(}}/tvar{{)^}}|about communication}}.|lang=html|inline=1}}&lt;br /&gt;
# &amp;lt;translate&amp;gt;&amp;lt;!--T:16--&amp;gt; If link text is the same as the name of the target page, all of the code could also be embedded into &amp;lt;tvar name=1&amp;gt;{{tag|tvar|open}}&amp;lt;/tvar&amp;gt;.&amp;lt;/translate&amp;gt;&lt;br /&gt;
#: &amp;lt;translate&amp;gt;&amp;lt;!--T:27--&amp;gt; For example:&amp;lt;/translate&amp;gt; {{#tag:syntaxhighlight|Learn more about {{^(}}tvar name=1{{)^}}&amp;lt;nowiki&amp;gt;{{ll|Communication}}&amp;lt;/nowiki&amp;gt;{{^(}}/tvar{{)^}}.|lang=html|inline=1}}&lt;br /&gt;
# &amp;lt;translate&amp;gt;&amp;lt;!--T:28--&amp;gt; For standalone links, such as in a list or table, translate only the link text if it differs from the name of the target page.&amp;lt;/translate&amp;gt; &amp;lt;translate&amp;gt;&amp;lt;!--T:15--&amp;gt; This is useful for bulleted lists of links, e.g. in the &amp;quot;See also:&amp;quot; sections.&amp;lt;/translate&amp;gt; &amp;lt;translate&amp;gt;&amp;lt;!--T:29--&amp;gt; Make sure to include the parameter name when adding translate tags inside template syntax.&amp;lt;/translate&amp;gt;&lt;br /&gt;
#: &amp;lt;translate&amp;gt;&amp;lt;!--T:30--&amp;gt; For example:&amp;lt;/translate&amp;gt;&lt;br /&gt;
::: {{#tag:syntaxhighlight|* {{((}}ll{{!}}Project:About{{))}}|lang=html|inline=1}}&lt;br /&gt;
::: {{#tag:syntaxhighlight|* {{((}}ll{{!}}Communication{{!}}2={{^(}}translate{{)^}}About communication{{^(}}/translate{{)^}}{{))}}|lang=html|inline=1}}&lt;br /&gt;
&lt;br /&gt;
== Test cases ==&lt;br /&gt;
{{Localized link/testcases}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== See also == &amp;lt;!--T:7--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
* [[Template:Localized link/messagedoc]] — &amp;lt;translate&amp;gt;&amp;lt;!--T:17--&amp;gt; should be used for message documentation in translatable pages that use this template.&amp;lt;/translate&amp;gt;&lt;br /&gt;
* {{tl|Translatable template}} - &amp;lt;translate&amp;gt;&amp;lt;!--T:18--&amp;gt; alias &amp;lt;tvar name=1&amp;gt;{{tl|TNT}}&amp;lt;/tvar&amp;gt; or &amp;lt;tvar name=2&amp;gt;{{tl|tnt}}&amp;lt;/tvar&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
* {{tl|Translatable template name}} - &amp;lt;translate&amp;gt;&amp;lt;!--T:19--&amp;gt; alias &amp;lt;tvar name=1&amp;gt;{{tl|TNTN}}&amp;lt;/tvar&amp;gt; or &amp;lt;tvar name=2&amp;gt;{{tl|tntn}}&amp;lt;/tvar&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
* {{tl|Page language link}} - &amp;lt;translate&amp;gt;&amp;lt;!--T:20--&amp;gt; alias &amp;lt;tvar name=1&amp;gt;{{tl|pll}}&amp;lt;/tvar&amp;gt;&amp;lt;/translate&amp;gt; - &amp;lt;translate&amp;gt;&amp;lt;!--T:21--&amp;gt; add a link from a translatable page to another translatable page in the same language&amp;lt;/translate&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
[[Category:Internationalization templates{{#translation:}}]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Template:Div_col&amp;diff=1524</id>
		<title>Template:Div col</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Template:Div_col&amp;diff=1524"/>
		<updated>2026-08-17T21:34:55Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;templatestyles src=&amp;quot;Div col/styles.css&amp;quot;/&amp;gt;&amp;lt;!--&lt;br /&gt;
--&amp;gt;&amp;lt;div class=&amp;quot;div-col {{#ifeq:{{{small|}}}|yes|div-col-small}} {{#ifeq:{{{rules|}}}|yes|div-col-rules}} {{{class|}}}&amp;quot; &amp;lt;!--&lt;br /&gt;
--&amp;gt;{{#if:{{{colwidth|}}}{{{gap|}}}{{{style|}}}|&amp;lt;!--&lt;br /&gt;
--&amp;gt;style=&amp;quot;{{#if:{{{colwidth|}}}|column-width: {{{colwidth}}};}}{{#if:{{{gap|}}}|column-gap: {{{gap}}};}}{{#if:{{{style|}}}|{{{style}}}}}&amp;quot;&amp;lt;!--&lt;br /&gt;
--&amp;gt;}}&amp;gt;&amp;lt;!--&lt;br /&gt;
--&amp;gt;{{#if:{{{content|}}}|{{{content}}}&amp;lt;/div&amp;gt;}}&amp;lt;!-- Inventory how many pages use small=yes &lt;br /&gt;
--&amp;gt;{{#ifeq:{{{small|}}}|yes|[[Category:Pages using div col with small parameter]]}}&amp;lt;!--&lt;br /&gt;
--&amp;gt;&amp;lt;/includeonly&amp;gt;{{#invoke:Check for unknown parameters|check|unknown={{main other|[[Category:Pages using div col with unknown parameters|_VALUE_{{PAGENAME}}]]}}|preview=Page using [[Template:Div col]] with unknown parameter &amp;quot;_VALUE_&amp;quot;; use colwidth= to specify column size |ignoreblank=y | class | colwidth | content | gap | rules | small | style }}&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Documentation/i18n&amp;diff=1523</id>
		<title>Module:Documentation/i18n</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Documentation/i18n&amp;diff=1523"/>
		<updated>2026-08-17T21:25:21Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;local format = require(&amp;#039;Module:TNT&amp;#039;).format local i18n = {}  i18n[&amp;#039;cfg-error-msg-type&amp;#039;] = format(&amp;#039;I18n/Documentation&amp;#039;, &amp;#039;cfg-error-msg-type&amp;#039;) i18n[&amp;#039;cfg-error-msg-empty&amp;#039;] = format(&amp;#039;I18n/Documentation&amp;#039;, &amp;#039;cfg-error-msg-empty&amp;#039;)  -- cfg[&amp;#039;template-namespace-heading&amp;#039;] -- The heading shown in the template namespace. i18n[&amp;#039;template-namespace-heading&amp;#039;] = format(&amp;#039;I18n/Documentation&amp;#039;, &amp;#039;template-namespace-heading&amp;#039;)  -- cfg[&amp;#039;module-namespace-heading&amp;#039;] -- The heading shown in the module...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local format = require(&#039;Module:TNT&#039;).format&lt;br /&gt;
local i18n = {}&lt;br /&gt;
&lt;br /&gt;
i18n[&#039;cfg-error-msg-type&#039;] = format(&#039;I18n/Documentation&#039;, &#039;cfg-error-msg-type&#039;)&lt;br /&gt;
i18n[&#039;cfg-error-msg-empty&#039;] = format(&#039;I18n/Documentation&#039;, &#039;cfg-error-msg-empty&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;template-namespace-heading&#039;]&lt;br /&gt;
-- The heading shown in the template namespace.&lt;br /&gt;
i18n[&#039;template-namespace-heading&#039;] = format(&#039;I18n/Documentation&#039;, &#039;template-namespace-heading&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;module-namespace-heading&#039;]&lt;br /&gt;
-- The heading shown in the module namespace.&lt;br /&gt;
i18n[&#039;module-namespace-heading&#039;] = format(&#039;I18n/Documentation&#039;, &#039;module-namespace-heading&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;file-namespace-heading&#039;]&lt;br /&gt;
-- The heading shown in the file namespace.&lt;br /&gt;
i18n[&#039;file-namespace-heading&#039;] = format(&#039;I18n/Documentation&#039;, &#039;file-namespace-heading&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;other-namespaces-heading&#039;]&lt;br /&gt;
-- The heading shown in other namespaces.&lt;br /&gt;
i18n[&#039;other-namespaces-heading&#039;] = format(&#039;I18n/Documentation&#039;, &#039;other-namespaces-heading&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;view-link-display&#039;]&lt;br /&gt;
-- The text to display for &amp;quot;view&amp;quot; links.&lt;br /&gt;
i18n[&#039;view-link-display&#039;] = format(&#039;I18n/Documentation&#039;, &#039;view-link-display&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;edit-link-display&#039;]&lt;br /&gt;
-- The text to display for &amp;quot;edit&amp;quot; links.&lt;br /&gt;
i18n[&#039;edit-link-display&#039;] = format(&#039;I18n/Documentation&#039;, &#039;edit-link-display&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;history-link-display&#039;]&lt;br /&gt;
-- The text to display for &amp;quot;history&amp;quot; links.&lt;br /&gt;
i18n[&#039;history-link-display&#039;] = format(&#039;I18n/Documentation&#039;, &#039;history-link-display&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;purge-link-display&#039;]&lt;br /&gt;
-- The text to display for &amp;quot;purge&amp;quot; links.&lt;br /&gt;
i18n[&#039;purge-link-display&#039;] = format(&#039;I18n/Documentation&#039;, &#039;purge-link-display&#039;)&lt;br /&gt;
&lt;br /&gt;
-- cfg[&#039;create-link-display&#039;]&lt;br /&gt;
-- The text to display for &amp;quot;create&amp;quot; links.&lt;br /&gt;
i18n[&#039;create-link-display&#039;] = format(&#039;I18n/Documentation&#039;, &#039;create-link-display&#039;)&lt;br /&gt;
&lt;br /&gt;
return i18n&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Projects&amp;diff=1522</id>
		<title>Projects</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Projects&amp;diff=1522"/>
		<updated>2026-08-17T18:20:31Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* Software Changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
In spite of the small size of the apartment, the newness of it and that it is an apartment the opportunity to improve upon it are limited. We assume that the complex manager would not look kindly on moving walls.&lt;br /&gt;
&lt;br /&gt;
Most of the effort that I plan to make is in my room.&lt;br /&gt;
&lt;br /&gt;
To get serious, install the docker version of Openproject. For now, this will be the outline.&lt;br /&gt;
&lt;br /&gt;
==Software Changes==&lt;br /&gt;
===Upgrade Mediawiki to 1.42.x - latest===&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|checked}} Make all necessary backups&lt;br /&gt;
{{checkbox|checked}} Review extensions and install/update to current&lt;br /&gt;
{{checkbox|checked}} Make a snapshot&lt;br /&gt;
{{checkbox|checked}} Run the upgrade script&lt;br /&gt;
{{checkbox|checked}} Test new implementation&lt;br /&gt;
{{checkbox|checked}} Configure Traefik to point to the new wiki&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
Best laid plans and all. It was good until running the upgrade script. I decided to start from a fresh install since the wiki isn&#039;t all that large. I was careful about picking extensions and then transferred the template library. There is probably a better way than moving them one by one.&lt;br /&gt;
&lt;br /&gt;
Sticking points:&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|on|color=red|tick=no}} Flightradar24 doesn&#039;t work in an iframe anymore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Implement Mediawiki page security===&lt;br /&gt;
Basically, chose one that fits.&lt;br /&gt;
&lt;br /&gt;
[https://www.mediawiki.org/wiki/Extension:Restrict_access_by_category_and_group Access by category and group]&lt;br /&gt;
&lt;br /&gt;
[https://www.mediawiki.org/wiki/Extension:PageOwnership PageOwnership is a permissions manager]&lt;br /&gt;
&lt;br /&gt;
Decided on PageOwnership.&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|checked}} Install and configure&lt;br /&gt;
{{checkbox|unchecked}} Figure out how to use&lt;br /&gt;
{{checkbox|unchecked}} Split wiki to public and private&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Chico Apartment==&lt;br /&gt;
Generally pretty good, but there are some areas to improve.&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|unchecked}} Update doorbell to current Google version from old nest&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Lynn&#039;s Room==&lt;br /&gt;
===Infrastructure===&lt;br /&gt;
There are several places that need to be cleaned up and improved. It has been a few years since this stuff went in and there have been changes. The overall goals are:&lt;br /&gt;
&lt;br /&gt;
====Repair ZimaCube====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox}} Depends on parts arrival&lt;br /&gt;
{{checkbox}} Disassemble Cube and replace parts&lt;br /&gt;
{{checkbox|color=red}} Test with ZimaOS.&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
I really hoped that the supplied parts would have fixed the problem. After installing them, the system displayed the same problems as before. Fortunately, Icewhale replaced the unit and it worked. Continuing on.&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox}} Test with ZimaOS. Run for a day or so and reboot occasionally&lt;br /&gt;
{{checkbox}} Review fan noise and order quieter fans&lt;br /&gt;
{{checkbox}} Install latest TrueNAS on Cube &amp;amp; Test&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
====Upgrade ZimaCube====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox}} Order updated fan kit from Zima&lt;br /&gt;
{{checkbox|unchecked}} Decide which fan kit to use&lt;br /&gt;
{{checkbox|unchecked}} Install fan kit&lt;br /&gt;
{{checkbox|unchecked}} Test cooling&lt;br /&gt;
{{checkbox|unchecked}} Install case fans&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Migrate Data to Other Resources====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox}} Migrate data from TR004 on PC to data_0 volume on qnap&lt;br /&gt;
{{checkbox|color=red|tick=no}} Move TR004 to Intel with 4x HDD&lt;br /&gt;
&lt;br /&gt;
{{checkbox}} Move data from standalone USB drives to truenas&lt;br /&gt;
{{checkbox}} Review disks in the inventory and copy to Cube&lt;br /&gt;
{{checkbox|unchecked}} Build inventory list and recycle drives as appropriate&lt;br /&gt;
{{checkbox|unchecked}} Begin migration from Qnap to Cube. Setup rsync on cron to keep them in sync&lt;br /&gt;
{{checkbox|unchecked}} Install the Media Management utilities and Plex on the Cube&lt;br /&gt;
{{checkbox|unchecked}} Install each app and then migrate the databases from the docker versions&lt;br /&gt;
{{checkbox|unchecked}} Update Caddy and change port forwarding when it is working&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
The TR004 would not provide individual drives to pve. I picked up an inexpensive disk array that would let me put those drives up and make them available to the Truenas VM.&lt;br /&gt;
&lt;br /&gt;
====Upgrade Proxmox====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
* Preliminary&lt;br /&gt;
{{checkbox}} Review the Proxmox upgrade document&lt;br /&gt;
{{checkbox}} Do a full set of backups according to the upgrade document&lt;br /&gt;
{{checkbox}} Do an alternate set of just the data areas &lt;br /&gt;
* Upgrade hardware and Software&lt;br /&gt;
{{checkbox}} Pull the machine and clean. Add a 2TB stick in the empty slot&lt;br /&gt;
{{checkbox}} Upgrade the 1TB stick to a 2TB one&lt;br /&gt;
{{checkbox}} Download and install the latest version of Proxmox&lt;br /&gt;
{{checkbox}} Install the 14TB drives into the newly freed Qnap TR004 and attach the expansion to the Proxmox machine&lt;br /&gt;
:: {{checkbox|checked|tick=no|color=red}} The TR004 didn&#039;t work. TR004 from Qnap not free yet&lt;br /&gt;
{{checkbox}} Recreate the VMs and reload from backup&lt;br /&gt;
* Pust Upgrade&lt;br /&gt;
{{checkbox}} Create a new VM and install TrueNAS.. Create a disk pool from the Qnap moounted drives&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Update Qnap====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|unchecked}} Review all storage locations looking for duplicates. &lt;br /&gt;
{{checkbox|unchecked}} Move data as appropriate to the Cube and TrueNAS instance on Proxmox.&lt;br /&gt;
{{checkbox|unchecked}} Retire Expansion for now&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Finish Migration Back to Lenovo Deskside====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|unchecked}} Identify applications to move&lt;br /&gt;
{{checkbox|unchecked}} Move/reinstall applications&lt;br /&gt;
{{checkbox|unchecked}} Move data&lt;br /&gt;
{{checkbox|unchecked}} Reconfigure Dell box and reinsatll OS&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Under Desk Cleanup====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox}} Create and review wiring plan&lt;br /&gt;
{{checkbox}} Pull out all hardware &lt;br /&gt;
{{checkbox}} Move desk and clean and vacuum under it&lt;br /&gt;
{{checkbox}} Clean window and sill&lt;br /&gt;
{{checkbox}} Replace current switch with compact one from Bidwell (east switch)&lt;br /&gt;
{{checkbox}} Rewire removing portable USB drives. Data has moved. Setup filesharing so that mounts are consistent&lt;br /&gt;
{{checkbox}} Put the desk back and layout accordingly. Should desks be swapped?&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====West Stack Cleanup====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|unchecked}} Finish armoire clean up&lt;br /&gt;
{{checkbox|unchecked}} Move desk back to have room to work&lt;br /&gt;
{{checkbox|unchecked}} Pull out all hardware &lt;br /&gt;
{{checkbox|unchecked}} Pull out armoire and shelving&lt;br /&gt;
{{checkbox}} Replace the power strip&lt;br /&gt;
{{checkbox|unchecked}} Return armoire&lt;br /&gt;
{{checkbox|unchecked}} Have wood spacer made for white stack to physically support TiVo better &lt;br /&gt;
{{checkbox|unchecked}} Put the TV and Raspberry Pi back&lt;br /&gt;
{{checkbox|unchecked}} Review placement &lt;br /&gt;
{{checkbox|unchecked}} Retire iMac mini&lt;br /&gt;
{{checkbox|unchecked}} Prewire electrical and network&lt;br /&gt;
{{checkbox|unchecked}} Install the under desk switch (west switch)&lt;br /&gt;
{{checkbox|unchecked}} Put the shelves back&lt;br /&gt;
{{checkbox|unchecked}} Reinstall remaining hardware&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Armoire Cleanup====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|unchecked}} Pull drawers, one at a time, and decide what to do with stuff&lt;br /&gt;
{{checkbox|unchecked}} If it isn&#039;t being used it needs to go somewhere hint, hint&lt;br /&gt;
{{checkbox|checked|tick=no|color=green}} The collection of old phones stays&lt;br /&gt;
{{checkbox|unchecked}} Review what is under the bed to see if consolidation is possible.&lt;br /&gt;
{{checkbox|unchecked}} The top shelving has been recently visited but needs more work&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Nightstand and Electrical====&lt;br /&gt;
As with many things, deciding to do something leads inevitably to doing other things. This is a perfect example. The cords under the bed are a mess and need to be reworked to just the large power strip. I need that for the Medtronic monitor and likely for a CPAP :-( The current inadequate cord plugs in behind the nightstand. The nightstand cannot be moved when full.&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|unchecked}} Review boxes under the bed&lt;br /&gt;
{{checkbox|unchecked}} Empty file drawers and things on top&lt;br /&gt;
{{checkbox|unchecked}} Raise head of bed&lt;br /&gt;
{{checkbox|unchecked}} Make the necessary wiring changes&lt;br /&gt;
{{checkbox|unchecked}} Return stuff to top&lt;br /&gt;
{{checkbox|unchecked}} Reload drawers while culling extra papers&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Closet====&lt;br /&gt;
The goal would be to reduce, recycle and toss. Do I need 8 power bricks or 20 USB cables?&lt;br /&gt;
====Photos====&lt;br /&gt;
&amp;lt;poem&amp;gt;&lt;br /&gt;
{{checkbox|unchecked}} Finish scanning slides&lt;br /&gt;
{{checkbox|unchecked}} Decide which ones can be tossed or rescanned at a higher resolution&lt;br /&gt;
{{checkbox|unchecked}} Review photo negatives and scan&lt;br /&gt;
{{checkbox|unchecked}} Categorize and organize&lt;br /&gt;
&amp;lt;/poem&amp;gt;&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=User:Lynn&amp;diff=1521</id>
		<title>User:Lynn</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=User:Lynn&amp;diff=1521"/>
		<updated>2026-08-17T18:18:35Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{User&lt;br /&gt;
| full name = Lynn Macey&lt;br /&gt;
| image name =&lt;br /&gt;
| hover text = lynn&lt;br /&gt;
| job title = Happily Retired&lt;br /&gt;
| organization = Working for The Family&lt;br /&gt;
| short quote = General All Around Good Guy&lt;br /&gt;
| about me = Have you got all day?&lt;br /&gt;
| about my work = I spent 45 years in high tech. Now I do it for fun.&lt;br /&gt;
| contact me = lynnmacey@gmail.com&lt;br /&gt;
| disclaimer = Only I am responsible&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Fetch Termius Passkey: curl -fs https://sshid.io/lynnmacey &amp;gt;&amp;gt; ~/.ssh/authorized_keys&lt;br /&gt;
&lt;br /&gt;
Get iMatch from these guys: [https://www.photools.com/ Photools.com]&lt;br /&gt;
&lt;br /&gt;
[http://openflights.org/user/lynnmacey Lynn&#039;s Flight History]&lt;br /&gt;
&lt;br /&gt;
[[The Weekly Task List]]&lt;br /&gt;
&lt;br /&gt;
[[Home Server Applications to Try]]&lt;br /&gt;
&lt;br /&gt;
[[The Notes Collection]]&lt;br /&gt;
&lt;br /&gt;
[[Projects]]&lt;br /&gt;
&lt;br /&gt;
[[Wish List and Vendors]]&lt;br /&gt;
&lt;br /&gt;
Some places that may be useful:&lt;br /&gt;
*[https://www.virtualizationhowto.com/2026/07/how-i-organize-my-entire-home-lab-so-i-can-actually-find-anything/ How I Organize My Entire Home Lab]&lt;br /&gt;
[[Videos to Categorize]]&lt;br /&gt;
==Personal Accounts==&lt;br /&gt;
===Venmo===&lt;br /&gt;
https://venmo.com/account/sign-in/&lt;br /&gt;
&lt;br /&gt;
 Username: @lynnmacey&lt;br /&gt;
 Password: M...&lt;br /&gt;
 Email Address: lynnmacey@gmail.com&lt;br /&gt;
&lt;br /&gt;
== Time Sensitive Information ==&lt;br /&gt;
&lt;br /&gt;
Interesting .zshrc rc file for the zsh shell. https://github.com/natelandau/dotfiles&lt;br /&gt;
&lt;br /&gt;
Some backup scripts are here https://github.com/natelandau/db_scripts&lt;br /&gt;
&lt;br /&gt;
==Movie reviews ==&lt;br /&gt;
Medieval &amp;quot;porn&amp;quot; : [https://www.youtube.com/watch?v=nTY2_NieZtw]&lt;br /&gt;
&lt;br /&gt;
Banned 1960s movies : [https://www.youtube.com/watch?v=J2CHNxk-jD0]&lt;br /&gt;
&lt;br /&gt;
13 Brutal 1970s Exploitation Films: [https://www.youtube.com/watch?v=3uBYsRYEhO0 13 Brutal 1970s Exploitation Films]&lt;br /&gt;
&lt;br /&gt;
15 Unfiltered Grindhouse Movies Hollywood Refused to Touch: [[https://www.youtube.com/watch?v=kfGhksb6Cho 15 Unfiltered Grindhouse Movies Hollywood Refused to Touch]&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=CY_e_9UoQpU 10 Movies So Wild Studios Would Never Greenlight Them Today]&lt;br /&gt;
&lt;br /&gt;
==Lynn&#039;s Flight History==&lt;br /&gt;
&lt;br /&gt;
[http://openflights.org/user/lynnmacey Lynn&#039;s Flight History]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;a href=&#039;https://openflights.org/user/lynnmacey&#039; target=&#039;_blank&#039;&amp;gt;&amp;lt;img src=&#039;https://openflights.org/banner/lynnmacey.png&#039; width=400 height=70&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I want this product for my wall: https://theflightwall.com/products/flightwall-mini-flight-tracking-led-display&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=User:Lynn&amp;diff=1520</id>
		<title>User:Lynn</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=User:Lynn&amp;diff=1520"/>
		<updated>2026-08-17T17:18:58Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{User&lt;br /&gt;
| full name = Lynn Macey&lt;br /&gt;
| image name =&lt;br /&gt;
| hover text = lynn&lt;br /&gt;
| job title = Happily Retired&lt;br /&gt;
| organization = Working for The Family&lt;br /&gt;
| short quote = General All Around Good Guy&lt;br /&gt;
| about me = Have you got all day?&lt;br /&gt;
| about my work = I spent 45 years in high tech. Now I do it for fun.&lt;br /&gt;
| contact me = lynnmacey@gmail.com&lt;br /&gt;
| disclaimer = Only I am responsible&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Fetch Termius Passkey: curl -fs https://sshid.io/lynnmacey &amp;gt;&amp;gt; ~/.ssh/authorized_keys&lt;br /&gt;
&lt;br /&gt;
[http://openflights.org/user/lynnmacey Lynn&#039;s Flight History]&lt;br /&gt;
&lt;br /&gt;
[[The Weekly Task List]]&lt;br /&gt;
&lt;br /&gt;
[[Home Server Applications to Try]]&lt;br /&gt;
&lt;br /&gt;
[[The Notes Collection]]&lt;br /&gt;
&lt;br /&gt;
[[Projects]]&lt;br /&gt;
&lt;br /&gt;
[[Wish List and Vendors]]&lt;br /&gt;
&lt;br /&gt;
Some places that may be useful:&lt;br /&gt;
*[https://www.virtualizationhowto.com/2026/07/how-i-organize-my-entire-home-lab-so-i-can-actually-find-anything/ How I Organize My Entire Home Lab]&lt;br /&gt;
[[Videos to Categorize]]&lt;br /&gt;
==Personal Accounts==&lt;br /&gt;
===Venmo===&lt;br /&gt;
https://venmo.com/account/sign-in/&lt;br /&gt;
&lt;br /&gt;
 Username: @lynnmacey&lt;br /&gt;
 Password: M...&lt;br /&gt;
 Email Address: lynnmacey@gmail.com&lt;br /&gt;
&lt;br /&gt;
== Time Sensitive Information ==&lt;br /&gt;
&lt;br /&gt;
Interesting .zshrc rc file for the zsh shell. https://github.com/natelandau/dotfiles&lt;br /&gt;
&lt;br /&gt;
Some backup scripts are here https://github.com/natelandau/db_scripts&lt;br /&gt;
&lt;br /&gt;
==Movie reviews ==&lt;br /&gt;
Medieval &amp;quot;porn&amp;quot; : [https://www.youtube.com/watch?v=nTY2_NieZtw]&lt;br /&gt;
&lt;br /&gt;
Banned 1960s movies : [https://www.youtube.com/watch?v=J2CHNxk-jD0]&lt;br /&gt;
&lt;br /&gt;
13 Brutal 1970s Exploitation Films: [https://www.youtube.com/watch?v=3uBYsRYEhO0 13 Brutal 1970s Exploitation Films]&lt;br /&gt;
&lt;br /&gt;
15 Unfiltered Grindhouse Movies Hollywood Refused to Touch: [[https://www.youtube.com/watch?v=kfGhksb6Cho 15 Unfiltered Grindhouse Movies Hollywood Refused to Touch]&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=CY_e_9UoQpU 10 Movies So Wild Studios Would Never Greenlight Them Today]&lt;br /&gt;
&lt;br /&gt;
==Lynn&#039;s Flight History==&lt;br /&gt;
&lt;br /&gt;
[http://openflights.org/user/lynnmacey Lynn&#039;s Flight History]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;a href=&#039;https://openflights.org/user/lynnmacey&#039; target=&#039;_blank&#039;&amp;gt;&amp;lt;img src=&#039;https://openflights.org/banner/lynnmacey.png&#039; width=400 height=70&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I want this product for my wall: https://theflightwall.com/products/flightwall-mini-flight-tracking-led-display&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Applications&amp;diff=1519</id>
		<title>Applications</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Applications&amp;diff=1519"/>
		<updated>2026-08-17T14:47:01Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* Local Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PAGEBANNER:Software_background.jpg}}&lt;br /&gt;
&lt;br /&gt;
==Local Applications==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Applications Installed Per Machine&lt;br /&gt;
|-&lt;br /&gt;
! Name !! Windows !! Linux !! Mac ||Application Type !! Official !! Notes&lt;br /&gt;
|-&lt;br /&gt;
|| [[angry ip scanner]] || Y || Y || || Scan local Network || [https://angryip.org/ Angry IP Scanner] ||&lt;br /&gt;
|-&lt;br /&gt;
|| [[brave]] || Y || Y || || Secure Browser || [https://brave.com Brave] ||&lt;br /&gt;
|-&lt;br /&gt;
|| [[Calbre]] || Y || Y || || e-Book library manager || || [[calibre-web Calibre-web]] is a companion app&lt;br /&gt;
|-&lt;br /&gt;
|| [[filebot]] || Y || Y || || Video FIle Swiss Army Knife || [https://www.filebot.net/] || CLI Scripting&lt;br /&gt;
|-&lt;br /&gt;
|| [[remmina]] || N || Y || || SSH Client || [https://remmina.org/ Remmina] ||&lt;br /&gt;
|-&lt;br /&gt;
|| [[reolink]] || Y || N || ||Access Security Cameras || [https://reolink.com/software-and-manual/] ||&lt;br /&gt;
|-&lt;br /&gt;
|| [[Termius]] || N || Y || ||SSH Client || [https://termius.com/index.html Termius]||&lt;br /&gt;
|-&lt;br /&gt;
|| [[Thunderbird]] || - || Y || || E-mail and Calendar || &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Application Servers==&lt;br /&gt;
There are several and even a reason why it is that way. They are listed here. These are all virtual machines, VMs, that are hosted on the main Proxmox server [[pve]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Chico Application Servers&lt;br /&gt;
|-&lt;br /&gt;
! Name !! IP !! Management !! Access !! Content Type&lt;br /&gt;
|-&lt;br /&gt;
|| [[Chico1]] || 192.168.86.31 || [https://yams.media/ Yams] || [https://portainer1.maceys.net Portainer1] || Audio and Video management with some other apps &lt;br /&gt;
|-&lt;br /&gt;
|| [[Chico3]] || 192.168.86.33 || Dockge || [https://portainer3.maceys.net Portainer3] || &lt;br /&gt;
Applications that are not available on TrueNAS or Deployrr&lt;br /&gt;
|-&lt;br /&gt;
|| [[Chico5]] || 192.168.86.35 || Apache || none || Non-Docker Apps&lt;br /&gt;
|-&lt;br /&gt;
|| [[Chico7]] || 192.168.86.37 || [https://github.com/SimpleHomelab/Deployrr Deployrr] || [https://portainer7.maceys.net Portainer7] || Most Docker Apps and Proxy Server&lt;br /&gt;
|-&lt;br /&gt;
|| [[Cube]] || 192.168.86.12 || [[http://cube.lan:81 TrueNAS]] || [https://portainer.maceys.net Portainer] || Media Management&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
See also: [[Virtual Machines]]&lt;br /&gt;
&lt;br /&gt;
==Web Applications==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Available and Supported Web Applications&lt;br /&gt;
|-&lt;br /&gt;
! Name !! Server !! Group || Official Web Site || Description&lt;br /&gt;
|-&lt;br /&gt;
|| [https://calibre.maceys.net Calibre] || [[Chico7]] || Media || [https://calibre-ebook.com/ Calibre] ||  Comprehensive book library and management&lt;br /&gt;
|-&lt;br /&gt;
|| [https://calibre-web-auto.maceys.net Calibre-web] || [[Chico7]] || Media ||[https://github.com/janeczku/calibre-web Calibre-web] || A smaller set of books that are easily accessed on the web&lt;br /&gt;
|-&lt;br /&gt;
|| [https://radarr.maceys.net Radarr] || [[Chico1]] || Media || [https://radarr.video/ Radarr] || Movie database&lt;br /&gt;
|-&lt;br /&gt;
|| [https://sonarr.maceys.net Sonarr] || [[Chico1]] || Media || [https://sonarr.video/ Sonarr] || TV Series database&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Application Management ==&lt;br /&gt;
Having the applications is great, but quickly becomes more than a person can keep in their head. Where is the app located? What port is it served from all needs to be abstracted in order to be easily adopted. Basically, people come to the application in order to use then and not spent much time trying to find them. My adoption and use of the tools has changed over time. Docker and Docker Compose are great, but can be a challenge to work with because of their complexity. The management systems work by insulating the administrator from a lot of the details. The tradeoff is, of course, that flexibility may be limited.&lt;br /&gt;
&lt;br /&gt;
===Dockge===&lt;br /&gt;
Dockge is installed on the Cube server and is intended to consolidate Chico1 and the Plex server on Qnap.&lt;br /&gt;
&lt;br /&gt;
===Yams===&lt;br /&gt;
I started with Yams and am not really unhappy with it. It is a pretty straight from the box docker management application. Docker compose scripts can be added to a local yaml file and started from docker. Generally, after it is running, the deployrr app is used to set up a proxy so that it can be run from https://name.maceys.net where name is the application. Most of the applications here are available through deployrr. The main media applications are still here for the time being.&lt;br /&gt;
&lt;br /&gt;
The usage information for Yams is here: [https://yams.media/install/using-the-cli/ Using the Yams CLI]&lt;br /&gt;
===Deployrr===&lt;br /&gt;
Deployrr is the next generation application management tools. It combines Docker and the Traefik proxy server and wraps them into a command line application to manage the whole stack. The author has put a great deal of effort making this work. I support him with an annual subscription. At this point, unless there is a really good reason to apply some other approach, I use Deployrr&lt;br /&gt;
&lt;br /&gt;
Detailed information on Deployrr is here [https://github.com/SimpleHomelab/Deployrr Deployrr].&lt;br /&gt;
&lt;br /&gt;
Return to [[Technical Guides]]&amp;lt;br&amp;gt;&lt;br /&gt;
Return to [[Main Page]]&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1518</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1518"/>
		<updated>2026-08-17T01:26:59Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* The Apartment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 450&lt;br /&gt;
| image1    = {{#display_map:39.75224,-121.79213|zoom=100|layers=OpenStreetMap}} &lt;br /&gt;
&lt;br /&gt;
| alt1      = Chico Map&lt;br /&gt;
&lt;br /&gt;
| image2    = Condo beach.jpg&lt;br /&gt;
| width     =450&lt;br /&gt;
| alt2      = Beach at the condo&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1517</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1517"/>
		<updated>2026-08-17T01:25:50Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* The Apartment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 450&lt;br /&gt;
| image1    = {{#display_map:39.75224,-121.79213|zoom=100|layers=OpenStreetMap}} &lt;br /&gt;
&lt;br /&gt;
| alt1      = Chico Map&lt;br /&gt;
&lt;br /&gt;
| image2    = Condo beach.jpg&lt;br /&gt;
| alt2      = Beach at the condo&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1516</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1516"/>
		<updated>2026-08-17T01:25:06Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* The Apartment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 450&lt;br /&gt;
| image1    = {{#display_map:39.75224,-121.79213||width=450|height=500|zoom=100|layers=OpenStreetMap}} &lt;br /&gt;
&lt;br /&gt;
| alt1      = Chico Map&lt;br /&gt;
&lt;br /&gt;
| image2    = Condo beach.jpg&lt;br /&gt;
| alt2      = Beach at the condo&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1515</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1515"/>
		<updated>2026-08-17T01:24:28Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* The Apartment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 450&lt;br /&gt;
| image1    = {{#display_map:39.75224,-121.79213&lt;br /&gt;
||width=450|height=500|zoom=100|layers=OpenStreetMap&lt;br /&gt;
}} &lt;br /&gt;
&lt;br /&gt;
| alt1      = Chico Map&lt;br /&gt;
&lt;br /&gt;
| image2    = Condo beach.jpg&lt;br /&gt;
| alt2      = Beach at the condo&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1514</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1514"/>
		<updated>2026-08-17T01:22:31Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* The Apartment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
{{#display_map:39.75224,-121.79213&lt;br /&gt;
||width=450|height=500|zoom=100|layers=OpenStreetMap&lt;br /&gt;
}} &lt;br /&gt;
|| [[File:Condo beach.jpg | 500px]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 450&lt;br /&gt;
&lt;br /&gt;
| image1    = {{#display_map:39.75224,-121.79213&lt;br /&gt;
||width=450|height=500|zoom=100|layers=OpenStreetMap&lt;br /&gt;
}} &lt;br /&gt;
|| [[File:Condo beach.jpg | 450px]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
| alt1      = Yellow cartouche&lt;br /&gt;
&lt;br /&gt;
| image2    = Condo beach.jpg&lt;br /&gt;
| alt2      = Red cartouche&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1513</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1513"/>
		<updated>2026-08-17T01:21:05Z</updated>

		<summary type="html">&lt;p&gt;Lynn: /* The Apartment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
{{#display_map:39.75224,-121.79213&lt;br /&gt;
||width=450|height=500|zoom=100|layers=OpenStreetMap&lt;br /&gt;
}} &lt;br /&gt;
|| [[File:Condo beach.jpg | 500px]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 60&lt;br /&gt;
&lt;br /&gt;
| image1    = {{#display_map:39.75224,-121.79213&lt;br /&gt;
||width=450|height=500|zoom=100|layers=OpenStreetMap&lt;br /&gt;
}} &lt;br /&gt;
|| [[File:Condo beach.jpg | 500px]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
| alt1      = Yellow cartouche&lt;br /&gt;
&lt;br /&gt;
| image2    = Red card.svg&lt;br /&gt;
| alt2      = Red cartouche&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1512</id>
		<title>Living in Chico</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Living_in_Chico&amp;diff=1512"/>
		<updated>2026-08-17T01:17:20Z</updated>

		<summary type="html">&lt;p&gt;Lynn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{PAGEBANNER:City-of-chico-banner.jpg}}&lt;br /&gt;
=Chico Writeup Related to Retirees=&lt;br /&gt;
[https://familydestinationsguide.com/town-california-affordable-retirees/ Chico Writeup Related to Retirees]&lt;br /&gt;
&lt;br /&gt;
= The Apartment =&lt;br /&gt;
{|&lt;br /&gt;
The apartment is located on the east side of town, approximately here:&lt;br /&gt;
{{#display_map:39.75224,-121.79213&lt;br /&gt;
||width=450|height=500|zoom=100|layers=OpenStreetMap&lt;br /&gt;
}} &lt;br /&gt;
|| [[File:Condo beach.jpg | 500px]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
{{multiple image&lt;br /&gt;
| footer    = Players are cautioned with a yellow card and sent off with a red card.&lt;br /&gt;
| width     = 60&lt;br /&gt;
&lt;br /&gt;
| image1    = Yellow card.svg&lt;br /&gt;
| alt1      = Yellow cartouche&lt;br /&gt;
&lt;br /&gt;
| image2    = Red card.svg&lt;br /&gt;
| alt2      = Red cartouche&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is: &lt;br /&gt;
&lt;br /&gt;
 The Maceys&lt;br /&gt;
 2580 California Park Dr #223&lt;br /&gt;
 Chico, CA 95928-4213&lt;br /&gt;
&lt;br /&gt;
WiFi quick connect:&lt;br /&gt;
&lt;br /&gt;
[[File:Macey WiFi-1024.jpeg | 150px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gym code: 25-80-17 (enter)&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
==[[Chico Apartment|Chico Apartment Details]]==&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
==[[The Weekly Task List|What Lynn should be working on by day]]==&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;br /&gt;
&lt;br /&gt;
= The House =&lt;br /&gt;
Josh and Anna&#039;s house is on the north end of town, here:&lt;br /&gt;
&lt;br /&gt;
{{#display_map:3163 Burnt Ranch Way, chico, CA&lt;br /&gt;
||width=450|height=500|zoom=100| layers=OpenStreetMap&lt;br /&gt;
}}&lt;br /&gt;
Note that the marker is just &amp;quot;close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The mailing address is:&lt;br /&gt;
&lt;br /&gt;
 Josh &amp;amp; Anna Macey&lt;br /&gt;
 3163 Sawyers Bar Ln&lt;br /&gt;
 Chico, CA 95973&lt;br /&gt;
&lt;br /&gt;
[[Chico House|Chico House Details]]&lt;br /&gt;
&lt;br /&gt;
Return to: {{Highlight|[[Main Page]]}}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Template:Multiple_image/styles.css&amp;diff=1511</id>
		<title>Template:Multiple image/styles.css</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Template:Multiple_image/styles.css&amp;diff=1511"/>
		<updated>2026-08-17T01:14:10Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;/* this is a block */ .thumbinner { 	display: flex; 	flex-direction: column; }  .trow { 	display: flex; 	flex-direction: row; 	clear: left; 	flex-wrap: wrap; 	width: 100%; 	box-sizing: border-box; }  /* this is a cell */ .tsingle { 	margin: 1px; 	float: left; }  .theader { 	clear: both; 	font-weight: bold; 	text-align: center; 	align-self: center; 	background-color: transparent; 	width: 100%; }  .thumbcaption { 	background-color: transparent; }  .text-align-left { 	text-...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* this is a block */&lt;br /&gt;
.thumbinner {&lt;br /&gt;
	display: flex;&lt;br /&gt;
	flex-direction: column;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.trow {&lt;br /&gt;
	display: flex;&lt;br /&gt;
	flex-direction: row;&lt;br /&gt;
	clear: left;&lt;br /&gt;
	flex-wrap: wrap;&lt;br /&gt;
	width: 100%;&lt;br /&gt;
	box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* this is a cell */&lt;br /&gt;
.tsingle {&lt;br /&gt;
	margin: 1px;&lt;br /&gt;
	float: left;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.theader {&lt;br /&gt;
	clear: both;&lt;br /&gt;
	font-weight: bold;&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	align-self: center;&lt;br /&gt;
	background-color: transparent;&lt;br /&gt;
	width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.thumbcaption {&lt;br /&gt;
	background-color: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.text-align-left {&lt;br /&gt;
	text-align: left;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.text-align-right {&lt;br /&gt;
	text-align: right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.text-align-center {&lt;br /&gt;
	text-align: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media all and ( max-width: 720px ) {&lt;br /&gt;
	.thumbinner {&lt;br /&gt;
		/* not !important usage can be removed when these are no longer inline styles&lt;br /&gt;
		inside Template:Multiple image and media query using min-width is introduced */&lt;br /&gt;
		width: 100% !important;&lt;br /&gt;
		box-sizing: border-box;&lt;br /&gt;
		max-width: none !important;&lt;br /&gt;
		align-items: center;&lt;br /&gt;
	}&lt;br /&gt;
	.trow {&lt;br /&gt;
		justify-content: center;&lt;br /&gt;
	}&lt;br /&gt;
	.tsingle {&lt;br /&gt;
		/* not !important usage can be removed when these are no longer inline styles&lt;br /&gt;
		inside Template:Multiple image and media query using min-width is introduced */&lt;br /&gt;
		float: none !important;&lt;br /&gt;
		max-width: 100% !important;&lt;br /&gt;
		box-sizing: border-box;&lt;br /&gt;
	}&lt;br /&gt;
	.trow &amp;gt; .thumbcaption {&lt;br /&gt;
		text-align: center;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1510</id>
		<title>Module:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Module:Multiple_image&amp;diff=1510"/>
		<updated>2026-08-17T01:12:02Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Lynn moved page Module:Multiple Image to Module:Multiple image without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- implements [[template:multiple image]]&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local autoscaledimages&lt;br /&gt;
local nonautoscaledimages&lt;br /&gt;
&lt;br /&gt;
local function isnotempty(s)&lt;br /&gt;
	return s and s:match( &#039;^%s*(.-)%s*$&#039; ) ~= &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removepx(s)&lt;br /&gt;
	return tostring(s or &#039;&#039;):match(&#039;^(.*)[Pp][Xx]%s*$&#039;) or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getdimensions(s, w, h)&lt;br /&gt;
	if tonumber(w) and tonumber(h) then&lt;br /&gt;
		nonautoscaledimages = true&lt;br /&gt;
		return tonumber(w), tonumber(h)&lt;br /&gt;
	end&lt;br /&gt;
	local file = s and mw.title.new(&#039;File:&#039; .. mw.uri.decode(mw.ustring.gsub(s,&#039;%|.*$&#039;,&#039;&#039;), &#039;WIKI&#039;))&lt;br /&gt;
	file = file and file.file or {width = 0, height = 0}&lt;br /&gt;
	w = tonumber(file.width) or 0&lt;br /&gt;
	h = tonumber(file.height) or 0&lt;br /&gt;
	autoscaledimages = true&lt;br /&gt;
	return w, h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle)&lt;br /&gt;
	local root = mw.html.create(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local altstr = &#039;|alt=&#039; .. (alt or &#039;&#039;)&lt;br /&gt;
	local linkstr = link and (&#039;|link=&#039; .. link) or &#039;&#039;&lt;br /&gt;
	local widthstr = &#039;|&#039; .. tostring(width) .. &#039;px&#039;&lt;br /&gt;
	local thumbtimestr = &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if isnotempty( thumbtime ) then&lt;br /&gt;
		thumbtimestr = &#039;|thumbtime=&#039; .. thumbtime&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local imagediv = root:tag(&#039;div&#039;)&lt;br /&gt;
	imagediv:addClass(&#039;thumbimage&#039;)&lt;br /&gt;
	imagediv:cssText(istyle)&lt;br /&gt;
	if( height ) then&lt;br /&gt;
		imagediv:css(&#039;height&#039;, tostring(height) .. &#039;px&#039;)&lt;br /&gt;
		imagediv:css(&#039;overflow&#039;, &#039;hidden&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	imagediv:wikitext(&#039;[[file:&#039; .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. &#039;]]&#039;)&lt;br /&gt;
	if isnotempty(caption) then&lt;br /&gt;
		local captiondiv = root:tag(&#039;div&#039;)&lt;br /&gt;
		captiondiv:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
		if isnotempty(textalign) then&lt;br /&gt;
			captiondiv:addClass(&#039;text-align-&#039; .. textalign)&lt;br /&gt;
		end&lt;br /&gt;
		captiondiv:wikitext(caption)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getWidth(w1, w2)&lt;br /&gt;
	local w&lt;br /&gt;
	if isnotempty(w1) then&lt;br /&gt;
		w = tonumber(w1)&lt;br /&gt;
	elseif isnotempty(w2) then&lt;br /&gt;
		w = tonumber(w2)&lt;br /&gt;
	end&lt;br /&gt;
	return w or 200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPerRow(pstr, ic)&lt;br /&gt;
	-- split string into array using any non-digit as a dilimiter&lt;br /&gt;
	local pr = mw.text.split(pstr or &#039;&#039;, &#039;[^%d][^%d]*&#039;)&lt;br /&gt;
	-- if split failed, assume a single row&lt;br /&gt;
	if (#pr &amp;lt; 1) then&lt;br /&gt;
		pr = {tostring(ic)}&lt;br /&gt;
	end&lt;br /&gt;
	-- convert the array of strings to an array of numbers,&lt;br /&gt;
	-- adding any implied/missing numbers at the end of the array&lt;br /&gt;
	local r = 1&lt;br /&gt;
	local thisrow = tonumber(pr[1] or ic) or ic&lt;br /&gt;
	local prownum = {}&lt;br /&gt;
	while( ic &amp;gt; 0 ) do&lt;br /&gt;
		prownum[r] = thisrow&lt;br /&gt;
		ic = ic - thisrow&lt;br /&gt;
		r = r + 1&lt;br /&gt;
		-- use the previous if the next is missing and&lt;br /&gt;
		-- make sure we don&#039;t overstep the number of images&lt;br /&gt;
		thisrow = math.min(tonumber(pr[r] or thisrow) or ic, ic)&lt;br /&gt;
	end&lt;br /&gt;
	return prownum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderMultipleImages(frame)&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local width = removepx(pargs[&#039;width&#039;] or &#039;&#039;)&lt;br /&gt;
	local dir = pargs[&#039;direction&#039;] or &#039;&#039;&lt;br /&gt;
	local border = pargs[&#039;border&#039;] or args[&#039;border&#039;] or &#039;&#039;&lt;br /&gt;
	local align = pargs[&#039;align&#039;] or args[&#039;align&#039;] or (border == &#039;infobox&#039; and &#039;center&#039; or &#039;&#039;)&lt;br /&gt;
	local capalign = pargs[&#039;caption_align&#039;] or args[&#039;caption_align&#039;] or &#039;&#039;&lt;br /&gt;
	local totalwidth = removepx(pargs[&#039;total_width&#039;] or args[&#039;total_width&#039;] or &#039;&#039;)&lt;br /&gt;
	local imgstyle = pargs[&#039;image_style&#039;] or args[&#039;image_style&#039;]&lt;br /&gt;
	local header = pargs[&#039;header&#039;] or pargs[&#039;title&#039;] or &#039;&#039;&lt;br /&gt;
	local footer = pargs[&#039;footer&#039;] or &#039;&#039;&lt;br /&gt;
	local imagegap = tonumber(pargs[&#039;image_gap&#039;] or &#039;1&#039;) or 1&lt;br /&gt;
	local perrow = nil&lt;br /&gt;
	local thumbclass = {&lt;br /&gt;
		[&amp;quot;left&amp;quot;] = &#039;tleft&#039;,&lt;br /&gt;
		[&amp;quot;none&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;center&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;centre&amp;quot;] = &#039;tnone&#039;,&lt;br /&gt;
		[&amp;quot;right&amp;quot;] = &#039;tright&#039;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	-- find all the nonempty images&lt;br /&gt;
	local imagenumbers = {}&lt;br /&gt;
	local imagecount = 0&lt;br /&gt;
	for k, v in pairs( pargs ) do&lt;br /&gt;
		local i = tonumber(tostring(k):match( &#039;^%s*image([%d]+)%s*$&#039; ) or &#039;0&#039;)&lt;br /&gt;
		if( i &amp;gt; 0 and isnotempty(v) ) then&lt;br /&gt;
			table.insert( imagenumbers, i)&lt;br /&gt;
			imagecount = imagecount + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- sort the imagenumbers&lt;br /&gt;
	table.sort(imagenumbers)&lt;br /&gt;
&lt;br /&gt;
	-- create an array with the number of images per row&lt;br /&gt;
	perrow = getPerRow(dir == &#039;vertical&#039; and &#039;1&#039; or pargs[&#039;perrow&#039;], imagecount)&lt;br /&gt;
&lt;br /&gt;
	-- compute the number of rows&lt;br /&gt;
	local rowcount = #perrow&lt;br /&gt;
&lt;br /&gt;
	-- store the image widths and compute row widths and maximum row width&lt;br /&gt;
	local heights = {}&lt;br /&gt;
	local widths = {}&lt;br /&gt;
	local widthmax = 0&lt;br /&gt;
	local widthsum = {}&lt;br /&gt;
	local k = 0&lt;br /&gt;
	for r=1,rowcount do&lt;br /&gt;
		widthsum[r] = 0&lt;br /&gt;
		for c=1,perrow[r] do&lt;br /&gt;
			k = k + 1&lt;br /&gt;
			if( k &amp;lt;= imagecount ) then&lt;br /&gt;
				local i = imagenumbers[k]&lt;br /&gt;
				if( isnotempty(totalwidth) ) then&lt;br /&gt;
					widths[k], heights[k] = getdimensions(pargs[&#039;image&#039; .. i], pargs[&#039;width&#039; .. i], pargs[&#039;height&#039; .. i])&lt;br /&gt;
				else&lt;br /&gt;
					widths[k] = getWidth(width, pargs[&#039;width&#039; .. i])&lt;br /&gt;
				end&lt;br /&gt;
				widthsum[r] = widthsum[r] + widths[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- make sure the gap is non-negative&lt;br /&gt;
	if imagegap &amp;lt; 0 then imagegap = 0 end&lt;br /&gt;
&lt;br /&gt;
	-- if total_width has been specified, rescale the image widths&lt;br /&gt;
	if( isnotempty(totalwidth) ) then&lt;br /&gt;
		totalwidth = tonumber(totalwidth)&lt;br /&gt;
		widthmax = 0&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local koffset = k&lt;br /&gt;
			local tw = totalwidth - (3 + imagegap) * (perrow[r] - 1) - 12&lt;br /&gt;
			local ar = {}&lt;br /&gt;
			local arsum = 0&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local h = heights[k] or 0&lt;br /&gt;
					if (h &amp;gt; 0) then&lt;br /&gt;
						ar[j] = widths[k]/h&lt;br /&gt;
						heights[k] = h&lt;br /&gt;
					else&lt;br /&gt;
						ar[j] = widths[k]/100&lt;br /&gt;
					end&lt;br /&gt;
					arsum = arsum + ar[j]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			local ht = tw/arsum&lt;br /&gt;
			local ws = 0&lt;br /&gt;
			k = koffset&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k&amp;lt;= imagecount ) then&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					widths[k] = math.floor(ar[j]*ht + 0.5)&lt;br /&gt;
					ws = ws + widths[k]&lt;br /&gt;
					if heights[k] then&lt;br /&gt;
						heights[k] = math.floor(ht)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			widthsum[r] = ws&lt;br /&gt;
			widthmax = math.max(widthmax, widthsum[r])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- start building the array of images, if there are images&lt;br /&gt;
	if( imagecount &amp;gt; 0 ) then&lt;br /&gt;
		-- compute width of outer div&lt;br /&gt;
		local bodywidth = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			if( widthmax == widthsum[r] ) then&lt;br /&gt;
				bodywidth = widthmax + (3 + imagegap) * (perrow[r] - 1) + 12&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- The body has a min-width of 100, which needs to be taken into account on specific widths&lt;br /&gt;
		bodywidth = math.max( 100, bodywidth - 8);&lt;br /&gt;
&lt;br /&gt;
		local bg = pargs[&#039;background color&#039;] or &#039;&#039;&lt;br /&gt;
		-- create the array of images&lt;br /&gt;
		local root = mw.html.create(&#039;div&#039;)&lt;br /&gt;
		root:addClass(&#039;thumb&#039;)&lt;br /&gt;
		root:addClass(&#039;tmulti&#039;)&lt;br /&gt;
		-- root:addClass(&#039;tmulti-sandbox&#039;)&lt;br /&gt;
		root:addClass(thumbclass[align] or &#039;tright&#039;)&lt;br /&gt;
&lt;br /&gt;
		if( align == &#039;center&#039; or align == &#039;centre&#039; ) then&lt;br /&gt;
			root:addClass(&#039;center&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			root:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local div = root:tag(&#039;div&#039;)&lt;br /&gt;
		div:addClass(&#039;thumbinner&#039;)&lt;br /&gt;
		div:css(&#039;width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
			:css(&#039;max-width&#039;, tostring(bodywidth) .. &#039;px&#039;)&lt;br /&gt;
		if( bg ~= &#039;&#039; ) then&lt;br /&gt;
			div:css(&#039;background-color&#039;, bg)&lt;br /&gt;
		end&lt;br /&gt;
		if( border == &#039;infobox&#039; or border == &#039;none&#039;) then&lt;br /&gt;
			div:css(&#039;border&#039;, &#039;none&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- add the header&lt;br /&gt;
		if( isnotempty(header) ) then&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;theader&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, pargs[&#039;header_align&#039;])&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;header_background&#039;])&lt;br /&gt;
					:wikitext(header)&lt;br /&gt;
		end&lt;br /&gt;
		-- loop through the images&lt;br /&gt;
		local k = 0&lt;br /&gt;
		for r=1,rowcount do&lt;br /&gt;
			local rowdiv = div:tag(&#039;div&#039;):addClass(&#039;trow&#039;);&lt;br /&gt;
			for j=1,perrow[r] do&lt;br /&gt;
				k = k + 1&lt;br /&gt;
				if( k &amp;lt;= imagecount ) then&lt;br /&gt;
					local imagediv = rowdiv:tag(&#039;div&#039;)&lt;br /&gt;
					imagediv:addClass(&#039;tsingle&#039;)&lt;br /&gt;
					if bg ~= &#039;&#039; then&lt;br /&gt;
						imagediv:css(&#039;background-color&#039;, bg);&lt;br /&gt;
					end&lt;br /&gt;
					if ((imagegap &amp;gt; 1) and (j &amp;lt; perrow[r])) then&lt;br /&gt;
						imagediv:css(&#039;margin-right&#039;, tostring(imagegap) .. &#039;px&#039;)&lt;br /&gt;
					end&lt;br /&gt;
					local i = imagenumbers[k]&lt;br /&gt;
					local img = pargs[&#039;image&#039; .. i]&lt;br /&gt;
					local w = widths[k]&lt;br /&gt;
					imagediv:css(&#039;width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
						:css(&#039;max-width&#039;, tostring(2 + w) .. &#039;px&#039;)&lt;br /&gt;
					imagediv:wikitext(renderImageCell(img, w, heights[k],&lt;br /&gt;
						pargs[&#039;link&#039; .. i], pargs[&#039;alt&#039; .. i],&lt;br /&gt;
						pargs[&#039;thumbtime&#039; .. i], pargs[&#039;caption&#039; .. i], capalign, imgstyle))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- add the footer&lt;br /&gt;
		if( isnotempty(footer) ) then&lt;br /&gt;
			local falign = string.lower(pargs[&#039;footer_align&#039;] or args[&#039;footer_align&#039;] or &#039;left&#039;)&lt;br /&gt;
			falign = (falign == &#039;centre&#039;) and &#039;center&#039; or falign&lt;br /&gt;
			div:tag(&#039;div&#039;)&lt;br /&gt;
				:addClass(&#039;trow&#039;)&lt;br /&gt;
				:css(&#039;display&#039;, (falign ~= &#039;left&#039;) and &#039;flow-root&#039; or &#039;flex&#039;)&lt;br /&gt;
				:tag(&#039;div&#039;)&lt;br /&gt;
					:addClass(&#039;thumbcaption&#039;)&lt;br /&gt;
					:css(&#039;text-align&#039;, (falign ~= &#039;left&#039;) and falign or nil)&lt;br /&gt;
					:css(&#039;background-color&#039;, pargs[&#039;footer_background&#039;])&lt;br /&gt;
					:wikitext(footer)&lt;br /&gt;
		end&lt;br /&gt;
		return tostring(root)&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.render( frame )&lt;br /&gt;
	autoscaledimages = false&lt;br /&gt;
	nonautoscaledimages = false&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag {name = &#039;templatestyles&#039;, args = {src = &#039;Multiple image/styles.css&#039;, wrapper = &amp;quot;.tmulti&amp;quot;}}&lt;br /&gt;
		.. renderMultipleImages( frame )&lt;br /&gt;
		.. (autoscaledimages and &#039;[[Category:Pages using multiple image with auto scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
		.. (nonautoscaledimages and &#039;[[Category:Pages using multiple image with manual scaled images]]&#039; or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
	<entry>
		<id>https://labwiki.maceys.net/index.php?title=Template:Multiple_image&amp;diff=1509</id>
		<title>Template:Multiple image</title>
		<link rel="alternate" type="text/html" href="https://labwiki.maceys.net/index.php?title=Template:Multiple_image&amp;diff=1509"/>
		<updated>2026-08-17T00:39:36Z</updated>

		<summary type="html">&lt;p&gt;Lynn: Created page with &amp;quot;{{#invoke:Multiple image|render}}&amp;lt;noinclude&amp;gt;{{doc}}&amp;lt;!-- PLEASE ADD CATEGORIES AND INTERWIKIS TO THE /doc SUBPAGE, THANKS --&amp;gt;&amp;lt;/noinclude&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#invoke:Multiple image|render}}&amp;lt;noinclude&amp;gt;{{doc}}&amp;lt;!-- PLEASE ADD CATEGORIES AND INTERWIKIS TO THE /doc SUBPAGE, THANKS --&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Lynn</name></author>
	</entry>
</feed>