Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
<<importTiddlers>>
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<!--{{{-->
<div class='header' role='banner' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
  <div class='headerShadow'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
  </div>
  <div class='headerForeground'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
  </div>
</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
  <div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
  <div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.header a:hover {background:transparent;}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected {
	color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard { background:[[ColorPalette::PrimaryPale]]; }
.wizard__title    { color:[[ColorPalette::PrimaryDark]]; border:none; }
.wizard__subtitle { color:[[ColorPalette::Foreground]]; border:none; }
.wizardStep { background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]]; }
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {
	color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];
}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {
	color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];
}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]]; }
.messageToolbar__button { color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none; }
.messageToolbar__button_withIcon { background:inherit; }
.messageToolbar__button_withIcon:active { background:inherit; border:none; }
.messageToolbar__icon { fill:[[ColorPalette::TertiaryDark]]; }
.messageToolbar__icon:hover { fill:[[ColorPalette::Foreground]]; }

.popup { background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]]; }
.popup li a, .popup li a:visited, .popup li a:hover, .popup li a:active {
	color:[[ColorPalette::Foreground]]; border: none;
}
.popup li a:hover { background:[[ColorPalette::SecondaryLight]]; }
.popup li a:active { background:[[ColorPalette::SecondaryPale]]; }
.popup li.disabled { color:[[ColorPalette::TertiaryMid]]; }
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged { border: 1px solid [[ColorPalette::TertiaryPale]]; background-color: [[ColorPalette::TertiaryPale]]; }
.selected .tagging, .selected .tagged { background-color: [[ColorPalette::TertiaryLight]]; border: 1px solid [[ColorPalette::TertiaryLight]]; }
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:alpha(opacity=60);}
/*}}}*/
/*{{{*/
body { font-size:.75em; font-family:arial,helvetica,sans-serif; margin:0; padding:0; }

* html .tiddler {height:1%;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}


a {text-decoration:none;}

.externalLink {text-decoration:underline;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
#mainMenu .tiddlyLinkNonExisting,
#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}


.header {position:relative;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0; top:0;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard { padding:0.1em 2em 0; }
.wizard__title    { font-size:2em; }
.wizard__subtitle { font-size:1.2em; }
.wizard__title, .wizard__subtitle { font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em; }
.wizardStep { padding:1em; }
.wizardFooter { padding:0.8em 0.4em 0.8em 0; }
.wizardFooter .status { padding:0.2em 0.7em; margin-left:0.3em; }
.wizardFooter .button { margin:0.5em 0 0; font-size:1.2em; padding:0.2em 0.5em; }

#messageArea { position:fixed; top:2em; right:0; margin:0.5em; padding:0.7em 1em; z-index:2000; }
.messageToolbar { text-align:right; padding:0.2em 0; }
.messageToolbar__button { text-decoration:underline; }
.messageToolbar__icon { height: 1em; width: 1em; } /* width for IE */
.messageArea__text a { text-decoration:underline; }

.popup {position:absolute; z-index:300; font-size:.9em; padding:0.3em 0; list-style:none; margin:0;}
.popup .popupMessage, .popup li.disabled, .popup li a { padding: 0.3em 0.7em; }
.popup li a {display:block; font-weight:normal; cursor:pointer;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation { padding: 0.5em 0.8em; margin: 0.5em 1px; }

.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0 3px 0 3px;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer pre {padding:0.5em; overflow:auto;}
pre, code { font-family: monospace, monospace; font-size: 1em; }
.viewer pre, .viewer code { line-height: 1.4em; }

.editor {font-size:1.1em; line-height:1.4em;}
.editor input, .editor textarea {display:block; width:100%; box-sizing: border-box; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0; padding-bottom:0;}

.fieldsetFix {border:0; padding:0; margin:1px 0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel { display:none; z-index:100; position:absolute; width:90%; margin-left:3em; }
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
  #mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea { display: none !important; }
  #displayArea { margin: 1em 1em 0em; }
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
//{{{
console.devlog = "----\nDevelopment log: " + new Date().toString() + "\n"
//}}}
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Commentaar bij [[Iteratiemechanismen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''

Wanneer de Lua-documentatie bij de uitleg van het ''{{tt{for&mdash;in}}}''-statement spreekt van een //invariant state//, komt een {{tt t{table}}} (als sequentie, dictionary of een hybride collectie) daar ook voor in aanmerking. Bedoeld is dan, dat het gedurende het iteratieproces dat vanuit {{tt t{for&mdash;in}}} in gang is gezet voortdurend om dezelfde {{tt t{table}}} blijft gaan. Het betekent niet dat de //inhoud// van die {{tt t{table}}} niet mag veranderen.

In [[Simulaties van for...in...-statement|Simulaties van for...in...-statement##Lua]] zagen we dat het {{tt t{for&mdash;in}}}-statement in de rol van 'pilot' de iteratie over een als 'provider' fungerende dictionary verzorgde zonder de inhoud daarvan te wijzigen, en zelf de boekhouding deed die nodig was om alle elementen van de dictionary aan de beurt te laten komen en dan het iteratieproces te beëindigen. Het kan ook anders:/%
%/
{{lf w80pct pre4{{{fgre{"""-- Script: Homebaked-stack-in-Lua.lua
-- Date  : 2023-03-07, Meindert Meindertsma
--
--   Role       Lua term          Name in this script  Variant state
--   ---------  ----------------  -------------------  -------------
--   provider   -                 stack                x
--   deliverer  iterator          pop
--   pilot      true interator    for
--   ---------  ----------------  -------------------  -------------


------====| STACK |====------"""}}}
"""
stack = {10, 20, 30}
"""
{{fgre{"""----- Delivery -----"""}}}
"""function pop (sequence)
  return table.remove(sequence)
end
"""
{{fgre{"""----- Apply for statement -----"""}}}
"""print "for:"
for n in pop, stack do print(n) end"""
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pre4{
''Uitvoer''

for:
30
20
10
}}}{{clear block{Hier is de 'provider' een sequence die fungeert als stack. Bij elke iteratie wordt het laatste element van {{tt t{stack}}} door de delivery-functie {{tt t{pop}}} verwijderd en aan de pilot overhandigd. De {{tt t{for&mdash;in}}}-routine zal na de procedure {{hitt4 z{print(n)}}} uitgevoerd te hebben {{tt t{pop}}} opnieuw aanroepen met twee argumenten, namelijk {{tt t{stack}}} (de //invariant state//) en het zojuist ontvangen element van diezelfde {{tt t{stack}}} (als besturingsinformatie). Het tweede argument wordt door {{tt t{pop}}} echter geheel genegeerd. Het is duidelijk dat wat de pilot ook aan administratieve handelingen doet, dit geen enkel effect heeft. De feitelijke staat van het iteratieproces ligt besloten in de fysieke aanwezigheid van elementen in {{tt t{stack}}}, bij de provider dus. Wanneer {{tt t{stack}}} leeg is, geeft {{tt t{pop}}} de waarde {{tt t{nil}}} terug, voor {{tt t{for—in}}} het sein om te stoppen.}}}
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Vervolg van [[Iteratiemechanismen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''
!!Constructie
Een iteratorclass is een class die een aantal specifieke componenten bevat die zich op een specifieke manier gedragen. In het UML-klassendiagram hieronder zijn de benodigde componenten in kaart gebracht.

[img[data/images/CD Python-iterators.png]]

Het linker blokje geeft de generieke opbouw van een willekeurige iterator weer: er moet een ongeparametriseerde method ''{{{__iter__}}}'' gedefinieerd zijn die een iterator&shy;object retourneert, plus een eveneens ongeparametriseerde method ''{{{__next__}}}'' die een of meer iteratie&shy;waarden retourneert. Van zo'n iterator&shy;class kunnen naar believen instances worden aangemaakt. Dat is wel prettig, want veel iterators zijn wegwerp&shy;producten: na hun kunstje gedaan te hebben zijn ze 'versleten' en daarmee waardeloos geworden. Om aan te geven dat de iterator is uitgewerkt behoort de {{tt t{"""__next__"""}}}-method de exception ''{{{StopIteration}}}'' te genereren. Als een iterator dat niet doet, is-ie òf heel slijtvast, òf pretendeert-ie dat te zijn, òf heeft alleen een iterator&shy;fluisteraar in de gaten wat er werkelijk aan de hand is. In [[Provider à la Python-iterator]] zijn twee simpele iterators gedemonstreerd: (1) een teller die van nul t/m drie kan tellen en dan 'op' is; (2) een iterator die een dictionary met drie items afwerkt en het daar dan eveneens voor altijd bij laat. Om die laatste een beetje te pesten heb ik de onderliggende dictionary tijdens het itereren gemuteerd. Heeft dat invloed op de levensduur van de iterator? Lees het verslag hiervan.

Ik ken twee iteratorclasses die in de officiële Python-documentatie expliciet als individueel object zijn beschreven. Dat zijn de twee andere blokjes in bovenstaande figuur. De ''{{{generator}}}'' heb ik in [[Provider à la Python-generator]] aan dezelfde beproevingen onderworpen als hierboven genoemd. De ''{{{enumerate}}}'' voegt (vooraan) een index toe aan de iteratie&shy;waarden die je toch al zou krijgen, zie het voorbeeld in [[Pilot à la Lua]]. Zoals de figuur laat zien, hebben ze dezelfde opbouw als de links afgebeelde class. Maar ik kan er nog wel iets specifieks over zeggen: {{hitt z{generator.iter()}}} produceert altijd een {{tt t{generator}}}-object, en {{hitt z{enumerate.iter()}}} altijd een {{tt t{enumerate}}}-object. Sterker nog: ze produceren beide {{tt t{self}}}, het eigen object. In het algemeen hoeft dat bij iteratoren niet het geval te zijn, al lijkt het me wel een recept voor ongelukken om iets anders zichzelf te retourneren. De zin van het zichzelf aanbieden komt hieronder bij de bespreking van het gedrag en de inpassing in de omgeving aan de orde. Naast {{tt t{generator}}}, {{tt t{enumerate}}}, {{tt t{filter}}}, {{tt t{map}}} en {{tt t{zip}}} kent Python nog +++(~VergetenIteratoren_Python)[tal van andere ingebouwde iteratoren. &darr;|show][tal van andere ingebouwde iteratoren. &uarr;|hide]
&nbsp;
In Python 3.6 vond ik destijds deze 17:
* {{{bytearray_iterator}}}
* {{{bytes_iterator}}}
* {{{callable_iterator}}}
* {{{dict_itemiterator}}}
* {{{dict_keyiterator}}}
* {{{dict_valueiterator}}}
* {{{fieldnameiterator}}}
* {{{formatteriterator}}}
* {{{iterator}}}
* {{{list_iterator}}}
* {{{list_reverseiterator}}}
* {{{longrange_iterator}}}
* {{{odict_iterator}}}
* {{{range_iterator}}}
* {{{set_iterator}}}
* {{{str_iterator}}}
* {{{tuple_iterator}}}
In 3.11 liep ik toevallig tegen een 18^^e^^ aan:
* {{{str_ascii_iterator}}}
Geïnspireerd door {{{list_reverseiterator}}} verkreeg ik na enig uitproberen bovendien 19 t/m 22:
* {{{dict_reverseitemiterator}}}
* {{{dict_reversekeyiterator}}}
* {{{dict_reversevalueiterator}}}
* {{{reversed}}}
Geen idee of er meer van dit soort iteratorclasses zijn. Ze hebben geen van alle een identifier die ernaar verwijst, noch is de module {{tt t{types}}} ertoe bereid daarin te voorzien:
<<<
Iterators in Python aren't a matter of type but of protocol.  A large and changing number of builtin types implement //some// flavor of iterator. Don't check the type! Use {{{hasattr}}} to check for both "{{{__iter__}}}" and "{{{__next__}}}" attributes instead.
<<<
===
&nbsp;In de officiële Python-documentatie worden ze in het geheel niet genoemd. Ze worden alleen in algemene termen beschreven, wat neerkomt op: alles wat voldoet aan het iterator&shy;protocol mag tot de categorie 'iterator' worden gerekend.

Naast de categorie 'iterator' hebben we ook te maken met de categorie 'iterabele'. Daartoe behoren objecten waarvan de class wel een {{tt t{"""__iter__"""}}}-method bevat, maar geen {{tt t{"""__next__"""}}}-method. Dergelijke objecten kunnen zelf niet itereren. Ze kunnen zich echter wel //laten// itereren door zichzelf in handen van een echte iterator te geven. De {{tt t{"""__iter__"""}}}-method geeft aan welke iterator dat dan wel zou moeten zijn.
!!Gedrag
Een beschrijving van het iteratorspel kan eigenlijk niet om de interessantste [[pilotrolspeler|Iteratiemechanismen]] van Python heen: het ''{{tt{[[for|Simulaties van for...in...-statement]]}}}''-statement. Deze maakt gebruik van de ''{{{iter}}}''-//functie//,{{ref{[[[1]|##01]]}}} dus ook daar moeten we aandacht aan besteden. Tot besluit zal ik enkele optredens van de ''{{{next}}}''-//functie// laten zien. Zo kom ik op acht scenario's, zes met {{tt t{for}}} en twee met {{tt t{next}}}.
!!!Scenario 1: misfit
[img[data/images/SC Python-iterator scenario 1.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

Het {{tt t{for}}}-statement probeert over een non-iterabele te itereren. In de eerste fase roept het {{tt t{iter}}} aan om te onderzoeken of het object in kwestie wel over een {{tt t{"""__iter__"""}}}-method beschikt.{{ref{[[[2]|##02]]}}} De uitslag is negatief en {{tt t{iter}}} probeert vervolgens of er dan misschien een method {{tt t{"""__getitem__"""}}} aanwezig is. Ook dat is niet het geval. Daarom genereert de functie een ''{{{TypeError}}}'' met de toelichting {{sans{"'&middot;&middot;&middot;&middot;&middot;' object is not iterable"}}}.{{ref{[[[3]|##03]]}}} Het {{tt t{for}}}-statement kan verder niets met deze situatie en laat het aan zijn omgeving over er iets (of niets) aan te doen.

Het geval dat het te onderzoeken object geen {{tt t{"""__iter__"""}}} maar wel een {{tt t{"""__getitem__"""}}} bevat, staat beschreven in [[Scenario 9|Het samenspel van iter en __getitem__ in Python]]./%
%/
!!!Scenario 2: delusion
[img[data/images/SC Python-iterator scenario 2.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

In dit scenario pretendeert een object iterabel te zijn, maar is het dat niet. Het heeft zelf geen {{tt t{"""__next__"""}}}-method, en het object dat het via zijn {{tt t{"""__iter__"""}}}-method retourneert, is evenmin een iterator. Daarmee loopt het alsnog tegen de lamp, want de door {{tt t{for}}} aangeroepen {{tt t{iter}}}-functie controleert of dat geretourneerde object echt wel over een {{tt t{"""__next__"""}}}-method beschikt. Zelfde afloop: {{sans{"TypeError: '&middot;&middot;&middot;&middot;&middot;' object is not iterable"}}}./%
%/
!!!Scenario 3: happy flow
[img[data/images/SC Python-iterator scenario 3.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

Een iterabele die wèl een iterator teruggeeft, komt daarentegen moeiteloos door de ballotage. Na de positieve test op de aanwezigheid van een {{tt t{"""__next__"""}}}-method geeft {{tt t{iter}}} het onderzochte object door aan het {{tt t{for}}}-statement, waarmee dit statement zijn tweede fase kan ingaan: itereren met behulp van de bereikbaar gebleken {{tt t{"""__next__"""}}}.{{ref{[[[4]|##04]]}}} Deze method zoekt in het object waartoe het behoort -- de iterator dus -- de achter&shy;liggende gegevens op. Hoe dat precies in zijn werk gaat, hangt af van hoe die iterator is ingericht. De list, dictionary en andere collecties produceren via hun {{tt t{"""__iter__"""}}}-method een iterator die geen exacte kopie van het oorspronkelijke object bevat, maar hooguit een referentie ernaar en waarschijnlijk enkele cruciale gegevens, bijvoorbeeld het aantal elementen ervan. Daar heeft {{tt t{"""__next__"""}}} dan genoeg aan om de gevraagde iteratievariabelen in te vullen. In eerste instantie op basis van een deel van de in het diagram met {{sans{//'info'//}}} aangeduide gegevens&shy;stroom van de iterator naar de method, en zo nodig aangevuld via raadpleging van het oorspronkelijke object (de gestippelde gegevensstroom linksonder in het diagram). Hoe een ''{{{dict_keyiterator}}}''-object, dat alleen de sleutels van de achter&shy;liggende dictionary aflevert, opereert, heb ik nader uitgeplozen in [[Provider à la Python-iterator]]. Daar heb ik gepoogd het gedrag van de in Python ingebouwde {{tt t{"""__next__"""}}}-method van deze iterator na te bootsen in Ruby en Lua. Niet helemaal gelukt voor gevallen dat het er echt wild aan toegaat.

Om de iteratie beheerst te laten verlopen, zal de iterator informatie over de voortgang moeten bijhouden. Die informatie, opgeslagen in de vorm van object&shy;attributen, wordt geraadpleegd en bijgewerkt door {{tt t{"""__next__"""}}} (een deel van de {{sans{'//info//'}}}-stroom en de stroom {{sans{'//control information//'}}} in z'n geheel). Wanneer {{tt t{"""__next__"""}}} niet meer kan leveren, wordt het geacht de exception ''{{{StopIteration}}}'' te genereren. Die wordt in de {{tt t{for}}}-lus vanzelf afgevangen voordat het de beoogde procedure gaat uitvoeren. Daarna stopt het iteratie&shy;proces. Als de gegevensbron //n// keer materiaal kan leveren, zal {{tt t{"""__next__"""}}} dus //n//+1 keer worden aangeroepen en de procedure //n// keer worden uitgevoerd.

Merk op dat er met de {{tt t{"""__iter__"""}}}-method van de iterator in deze configuratie niets wordt gedaan. Zie ook de volgende twee scenario's./%
%/
!!!Scenario 4: straightforward flow
[img[data/images/SC Python-iterator scenario 4.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

Het moet natuurlijk ook mogelijk zijn direct over een iterator te itereren. Wanneer je dat via een {{tt t{for}}}-lus speelt, zal er onvermijdelijk om een {{tt t{"""__iter__"""}}}-method worden gevraagd. Die moet de iterator dan wel paraat hebben. Om aan deze bureau&shy;cratische verplichting te voldoen, kan worden volstaan met {{pref hitt z{"""def __iter__(self): return self"""}}}. Wat daarna volgt, is een gestroomlijnde versie van het vorige scenario.

Hoe de iterator aan zijn data komt, is niet in het diagram weergegeven. Er is van alles mogelijk: een referentie naar een ander object dat het benodigde materiaal bevat of produceert, of anders een geheel interne opslag dan wel productie./%
%/
!!!Scenario 5: getting away with it
[img[data/images/SC Python-iterator scenario 5.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

Dit is er eentje voor de minder gezagsgetrouwe programmeurs. Een iterabel object levert via {{tt t{"""__iter__"""}}} een ander object aan dat wel een {{tt t{"""__next__"""}}}-method in stelling kan brengen maar formeel geen iterator is, omdat de {{tt t{"""__iter__"""}}}-method ontbreekt. Het is daarmee dan niet vanzelf&shy;sprekend een beunhaas, want het kan perfect werk afleveren. Het komt ermee weg omdat niemand in deze opstelling naar 'de juiste papieren' vraagt. In de configuratie volgens het vorige scenario valt zo'n onbevoegde iterator echter door de mand./%
%/
!!!Scenario 6: quality check
[img[data/images/SC Python-iterator scenario 6.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

In de vorige drie scenario's was het steeds {{tt t{"""__next__"""}}} die het signaal kon geven dat het itereren moet worden gestopt. De uiteindelijk uit te voeren procedure is daar echter net zo goed toe in staat, bijvoorbeeld op basis van de kwaliteit van de ontvangen iteratie&shy;waarden of de toestand in haar omgeving./%
%/
!!!Scenario 7: delivery impossible
[img[data/images/SC Python-iterator scenario 7.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

De ''{{{for}}}''-lus is niet de enige manier om het iteratieproces in gang te zetten en aan de gang te houden totdat het klaar is. Met enig aanvullend programmeer&shy;werk is een ''{{{while}}}''-lus tot precies dezelfde kunstjes in staat. Bovenstaande uiteenzettingen bieden daar genoeg aanknopings&shy;punten voor. Bij doe-het-zelf programmering kun je nog wel voor de vraag komen te staan: wanneer is het beter om de aanroep van de {{tt t{"""__next__"""}}}-method aan de ''{{{next}}}''-//functie// over te laten?{{ref{&#x200a;[[[4]|##04]]}}} Deze functie heeft voor zover ik kan achterhalen hooguit één ding voor op een rechtstreekse aanroep: ze checkt eerst even de aanwezigheid van {{tt t{"""__next__"""}}} en vervangt bij geconstateerde afwezigheid de exception {{sans{"AttributeError: '&middot;&middot;&middot;&middot;&middot;' object has no attribute '"""__next__"""'"}}} door {{sans{"TypeError: '&middot;&middot;&middot;&middot;&middot;' object is not iterable"}}}. (De functie {{tt t{iter}}} doet tenminste nog //twee// checks.) Bovenstaand diagram geeft weer hoe {{tt t{next}}} een non-iterabele afhandelt./%
%/
!!!Scenario 8: delivery possible
[img[data/images/SC Python-iterator scenario 8.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

En dit gebeurt er wanneer het object in staat is op afroep materiaal te leveren. Het eventuele ontbreken van {{tt t{"""__iter__"""}}} wordt niet als bezwaarlijk gezien./%
%/
!!!Meer scenario's mogelijk?
Vast en zeker ! Ik laat dat als oefening aan de programmeergrage lezer over.

----
|bare |k
|<html><a name="01">[1]</a></html>|Honderd procent zeker weet ik dat niet, want ik heb in plaats van de in C geschreven broncode van Python minutieus door te pluizen slechts met de blik van een etholoog geconcludeerd dat {{tt t{for}}} zich in elk geval //gedraagt// alsof het {{tt t{iter}}} gebruikt. |
|<html><a name="02">[2]</a></html>|Zie ook de vorige noot. Op haar beurt gebruikt {{tt t{iter}}} waarschijnlijk de {{tt t{hasattr}}}-functie, die daar volgens de documentatie {{tt t{getattr}}} voor aanroept. |
|<html><a name="03">[3]</a></html>|Als {{tt t{for}}} rechtstreeks {{pref hitt z{//non-iterable//''."""__iter__"""()''}}} had geprobeerd, dan zou er een foutmelding {{sans{"AttributeError: '&middot;&middot;&middot;&middot;&middot;' object has no attribute '"""__iter__"""'"}}} zijn gekomen. Welke exception spreekt het meest aan? Wie denkt in //typen// of //classes// vindt {{tt t{TypeError}}} waarschijnlijk het duidelijkst. Wie meegaat met het idee dat je bij iteratoren moet denken in protocollen en interfaces, zal wellicht eerder voor {{tt t{AttributeError}}} kiezen. |
|<html><a name="04">[4]</a></html>|Ik denk dat de tweede fase van de {{tt t{for}}}-loop die method rechtstreeks aanroept, want de omweg via de {{tt t{next}}}-functie zou naar mijn idee geen enkele meerwaarde bieden. |
!!The {{hitt z pblu{(eq? {{n{//obj1 obj2//}}})}}} procedure according to R5RS&ndash;R7RS
R7RS&#x200a;{{ref{[[[1]|##01]]}}} states in section 6.1:
<<<
The {{tt t{eq?}}} procedure is similar to {{tt t{eqv?}}} except that in some cases it is capable of discerning distinctions finer than those detectable by {{tt t{eqv?}}}. It must always return {{tt t{#f}}} when {{tt t{eqv?}}} also would, but may return {{tt t{#f}}} in some cases where {{tt t{eqv?}}} would return {{tt t{#t}}}.

On symbols, booleans, the empty list, pairs, and records, and also on non-empty strings, vectors, and bytevectors, {{tt t{eq?}}} and {{tt t{eqv?}}} are guaranteed to have the same behavior. On procedures, {{tt t{eq?}}} must return true if the arguments' location tags are equal. On numbers and characters, {{tt t{eq?}}}'s behavior is implementation-dependent, but it will always return either true or false. On empty strings, empty vectors, and empty bytevectors, {{tt t{eq?}}} may also behave differently from {{tt t{eqv?}}}.
<<<

|middle col1 bold1 tt capl |k
|!{{serif{Expression}}}                         |!{{serif{R5RS&ndash;R7RS}}}               |!{{serif{Chez Scheme 9.5}}} |
|(eq? 'a 'a)                                    | #t                                       | #t           |
|(eq? '(a) '(a))                                | {{serif f3m{//unspecified//}}}           | {{fred{#f}}} |
|(eq? (list 'a) (list 'a))                      | {{fred{#f}}}                             | {{fred{#f}}} |
|(eq? "a" "a")                                  | {{serif f3m{//unspecified//}}}           | {{fred{#f}}} |
|(eq? "" "")                                    | {{serif f3m{//unspecified//}}}           | #t           |
|(eq? '() '())                                  | #t                                       | #t           |
|(eq? 2 2)                                      | {{serif f3m{//unspecified//}}}           | #t {{serif{//or//}}} {{fred{#f}}}{{serif{ ^^//a//^^}}} |
|(eq? #\A #\A)                                  | {{serif f3m{//unspecified//}}}           | #t           |
|(eq? car car)                                  | #t                                       | #t           |
|(let ((n (+ 2 3)))<br>&nbsp; (eq? n n))        | {{serif f3m{//unspecified//^^ //b//^^}}} | #t           |
|(let ((x '(a)))<br>&nbsp; (eq? x x))           | #t                                       | #t           |
|(let ((x '#()))<br>&nbsp; (eq? x x))           | #t                                       | #t           |
|(let ((p (lambda (x) x)))<br>&nbsp; (eq? p p)) | #t                                       | #t           |
|(eq? #t #t)                                    | {{serif{-- ^^//c//^^}}}                  | #t           |
|(eq? #f #f)                                    | {{serif{-- ^^//c//^^}}}                  | #t           |
|{{serif z{^^//a//^^ Depends on integer size and compiler version (32 or 64 bits):<br>&nbsp;&nbsp; {{tt t{#t}}} if -2^^29^^ &le; //integer // < 2^^29^^ in a 32-bit process or<br>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -2^^60^^ &le; //integer // < 2^^60^^ in a 64-bit process.<br>&nbsp; &#x2009;Can be tested by {{hitt z pblu{''(fixnum?'' //n//'')''}}} and {{hitt z pblu{''(fixnum-width)''}}}.<br>&nbsp; &#x2009;''{{hitt z pblu{(eq? 2.0 2.0)}}}'' &rArr; {{tt t fred{#f}}} anyway.<br>^^//b//^^ [[Remarkable!|Journal 2023-08-14 (Monday): Scheme]] <br>^^//c//^^ The reports specify ''{{hitt z pblu{(eqv? #t #t))}}}'' &rArr; {{tt t{#t}}} and ''{{hitt z pblu{(eqv? #f #f))}}}'' &rArr; {{tt t{#t}}}<br>&nbsp; &#x2009;explicitly. Thereafter, they state that {{tt t{eq?}}} and {{tt t{eqv?}}} behave the same for<br>&nbsp; &#x2009;booleans and some other types.}}}|c

R7RS continues:
<<<
Rationale: It will usually be possible to implement {{tt t{eq?}}} much more efficiently than {{tt t{eqv?}}}, for example, as a simple pointer comparison instead of as some more complicated operation. One reason is that it is not always possible to compute {{tt t{eqv?}}} of two numbers in constant time, whereas {{tt t{eq?}}} implemented as pointer comparison will always finish in constant time.
<<<
{{lift{}}}
!!The {{hitt z pblu{(eqv? {{n{//obj1 obj2//}}})}}} and {{hitt z pblu{(equal? {{n{//obj1 obj2//}}})}}} procedures
<<eval [=[|bare |k
|{{hitt z pblu{''(eq?'' //obj1 obj2//'')''}}} &rArr; {{tt t{#t}}}  | &nbsp; $==> &nbsp; |{{hitt z pblu{''(eqv?'' //obj1 obj2//'')''}}} &rArr; {{tt t{#t}}} |
|{{hitt z pblu{''(eqv?'' //obj1 obj2//'')''}}} &rArr; {{tt t{#t}}} | &nbsp; $==> &nbsp; |{{hitt z pblu{''(equal?'' //obj1 obj2//'')''}}} &rArr; {{tt t{#t}}} |
]=] fblu>>

----
|plain |k
|<html><a name="01">[1]</a></html>|<<tiddler Bibliografie##RnRS>> |
<<tiddler [[{}::togglesliders]]>> The collection of commands below is nothing more than a survival kit in pocket format for the occasional Linux visitor, geared to the expected practice of my colleagues in 2017. It was not aimed at would-be system administrators or seasoned C/C++ programmers./%

%/
+++(~VisitLinuxHelp)![Help &darr;|show help][Help &uarr;|hide help]
;{{{apropos}}}
:Search the short manual page descriptions for occurrences of strings. Equivalent to''{{{ man -k}}}''.
;{{{man}}}
:Display information from reference //man//uals (''{{{man man }}}''explains itself).
;{{{whatis}}}
:Search the short manual page descriptions for occurrences of keywords. Equivalent to''{{{ man -f}}}''.
;{{{which}}}
:List the full pathnames of the files that would be executed if the named commands had been run (based on the value of the user's {{{$PATH}}} environment variable).
===/%

%/+++(~VisitLinuxShells)![Shells &darr;|show shells][Shells &uarr;|hide shells]
;{{{bash}}}
:[[Bourne-Again shell|Bash on with Linux]], the GNU version of the Bourne shell. This is the standard Linux shell. Use the built-in ''{{{help}}}'' command to get information about the built-in commands (''{{tt{help&nbsp;help }}}''will explain ''{{{help}}}'' itself).
;{{{csh}}}
:C shell. So named because of its resemblance to the C programming language. On many versions of Linux, ''{{{csh}}}'' refers to ''{{{tcsh}}}''.
;{{{ksh}}}
:Korn shell. Main versions are {{{ksh88}}} and {{{ksh93}}}.
;{{{sh}}}
:Bourne shell. The standard Unix shell. On Linux, ''{{{sh}}}'' refers to ''{{{bash}}}''.
;{{{tcsh}}}
:An enhanced version of the C shell.
;{{{zsh}}}
:Z shell (pronounced as //zee-shell//). Very similar to ''{{{ksh}}}'', but also includes some features of ''{{{bash}}}'' and ''{{{tcsh}}}''.
See also [[Scriptingfaciliteiten op Un*x]].
===/%

%/+++(~VisitLinuxScripting)![Scripting languages &darr;|show scripting][Scripting languages &uarr;|hide scripting]
;{{{awk}}}
:A program that does pattern matching, record processing, and other forms of text manipulation. Its name (pronounced as //auk//) is derived from the surnames of its creators: Alfred Aho, Peter Weinberger, and Brian Kernighan.
;@@color(red):{{tt{expect}}}@@
:@@color(red):Programmed dialogue with interactive programs.@@
;{{{gawk}}}
:The GNU version of ''{{{awk}}}''.
;{{{igawk}}}
:''{{{gawk}}}'' with include files.
;{{{lua}}}
:A simple but powerful language. Even though designed to be embedded in a host client (e.g. as PROC LUA in SAS) it is equally well suitable for stand-alone usage.
;{{{perl}}}
:A powerful text-processing language that combines many of the most useful features of shell programs, C, ''{{{awk}}}'', and ''{{{sed}}}'', as well as adding extended features of its own.
;{{{python}}}
:A powerful object-oriented scripting language, that drives many of the configuration scripts in Linux distributions and is also applied as macro language in applications.
See also [[Scriptingfaciliteiten op Un*x]].
===/%

%/+++(~VisitLinuxTerminal)![Terminal &darr;|show terminal][Terminal &uarr;|hide terminal]
;{{{clear}}}
:Clear the terminal display.
;{{{reset}}}
:A symbolic link to ''{{{tset}}}''.
;{{{tset}}}
:Initialize the terminal (which clears its display).
===/%

%/+++(~VisitLinuxFileManagement)![File management &darr;|show file management][File management &uarr;|hide file management]
See also [[Het bestandssysteem van Linux]].
;{{{basename}}}
:Remove leading directory components (and optionally suffix) from a path and print the result to STDOUT. See also ''{{{dirname}}}''.
;{{{chattr}}}
:Modify file attributes -- specific to //ext2// and //ext3// filesystems. See also ''{{{lsattr}}}''.
;{{{chgrp}}}
:Change the group of files.
;{{{chmod}}}
:Change the access mode (permissions) of files.
;{{{chown}}}
:Change the ownership of files.
;{{{cp}}}
:Copy files.
;{{{cpio}}}
:Copy files to and from archives.
;{{{dir}}}
:Briefly list contents of one or more directories. Equivalent to ''{{{ls}}} {{{-Cb}}}''.
;{{{dirname}}}
:Print pathname, excluding the last level, to STDOUT. See also ''{{{basename}}}''.
;{{{du}}}
:Print disk usage to STDOUT.
;{{{find}}}
:Locate files that meet the given conditions.
;{{{findmnt}}}
:Find a filesystem. See ''{{{mount}}}'' and ''{{{umount}}}''.
;{{{fuser}}}
:List the ~IDs of processes (and corresponding usernames) that are using the specified files or filesystems.
;{{{link}}}
:Create link between two files; same as ''{{{ln}}}'' without error checking.
;{{{ln}}}
:Create pseudonyms (hard or [[symbolic links|Symbolic links on Linux]]) for files.
;{{{locate}}}
:Search database(s) of filenames and print matches.
;{{{lockfile}}}
:Create semaphore files, used to limit access to a file.
;{{{ls}}}
:List contents of one or more directories.
;{{{lsattr}}}
:Print file attributes to STDOUT. See also ''{{{chattr}}}''.
;{{{mkdir}}}
:Create one or more directories.
;{{{mktemp}}}
:Generate a unique temporary filename.
;{{{mount}}}
:Mount a file structure. See ''{{{findmnt}}}'' and ''{{{umount}}}''.
;{{{mv}}}
:Move or rename files.
;{{{namei}}}
:Follow pathnames until a terminal point is found and report to STDOUT.
;{{{pathchk}}}
:Determine validity and portability of filenames.
;{{{pwd}}}
://P//rint full pathname of the current //w//orking //d//irectory.
;{{{readlink}}}
:Print the name of the file to which the link points to STDOUT.
;{{{rename}}}
:Rename files collectively.
;{{{rm}}}
:Remove files.
;{{{rmdir}}}
:Remove directories.
;{{{stat}}}
:Print //inode stat// of files to STDOUT.
;{{{touch}}}
:Update time attributes of files.
;{{{unmount}}}
:Unmount a filesystem. See ''{{{mount}}}'' and ''{{{findmnt}}}''.
;{{{vdir}}}
:Verbosely list contents of one or more directories. Equivalent to ''{{{ls}}} {{{-lb}}}''.
===/%

%/+++(~VisitLinuxFileContents)![File contents &darr;|show file contents][File contents &uarr;|hide file contents]
;{{{cat}}}
:Print file contents to STDOUT. See also ''{{{tac}}}''.
;{{{cksum}}}
:Print CRC checksum of files to STDOUT. See also ''{{{sum}}}''.
;{{{colrm}}}
:Remove columns from STDIN and write to STDOUT.
;{{{column}}}
:Format input from one or more files into columns, filling rows first.
;{{{csplit}}}
:Break up a file at some pattern. See also ''{{{split}}}''.
;{{{cut}}}
:Cut out one or more columns from file(s). See also ''{{{join}}}'', ''{{{paste}}}'', and ''{{{pr}}}''.
;{{{dd}}}
:Transform input file (''{{{if}}}'') to output file (''{{{of}}}'').
;{{{egrep}}}
:Search files for lines that match an extended regular expression. See also ''{{{fgrep}}}'' and ''{{{grep}}}''.
;{{{expand}}}
:Expand tabs in files to appropriate number of spaces and write to STDOUT. See also ''{{{unexpand}}}''.
;{{{fgrep}}}
:Search files for lines that match a literal text string pattern. See also ''{{{egrep}}}'' and ''{{{grep}}}''.
;{{{file}}}
:Classify files according to the type of data they contain.
;{{{fmt}}}
:Format files.
;{{{fold}}}
:Break the lines of files at some width.
;{{{grep}}}
:Search files for lines that match a regular expression. The name is derived form the command {{{g/re/p}}} in some line editors (among which ''{{{ed}}}'' and ''{{{ex}}}''), meaning '//g//lobally search for the regular expression //{{{re}}}// and //p//rint the lines containing it'. See also ''{{{egrep}}}'' and ''{{{fgrep}}}''.
;{{{head}}}
:Print first 10 lines of files to STDOUT. See also ''{{{tail}}}''.
;{{{hexdump}}}
:Dump file in hexadecimal or other format to STDOUT. See also ''{{{od}}}''.
;{{{iconv}}}
:Convert the contents of files from one character encoding to another and write the results to STDOUT.
;{{{info}}}
:GNU hypertext reader.
;{{{join}}}
:Join lines of two sorted files on a common field. See also ''{{{cut}}}'', ''{{{paste}}}'', and ''{{{pr}}}''.
;{{{less}}}
:A less primitive counterpart of ''{{{more}}}''.
;{{{mimencode}}}
:Translate to or from a MIME encoding format, for instance base64 encoding. See also ''{{{uuencode}}}'' and ''{{{uudecode}}}''.
;{{{more}}}
:Display files on a terminal, one screenful at a time. See ''{{{less}}}'' for an alternative to ''{{{more}}}''.
;{{{od}}}
:Dump files in octal or other format to STDOUT. See also ''{{{hexdump}}}''.
;{{{paste}}}
:Merge corresponding or subsequent lines of files. See also ''{{{cut}}}'', ''{{{join}}}'', and ''{{{pr}}}''.
;{{{pr}}}
:Convert files to a paginated, columned version, with headers.
;{{{pinfo}}}
:A kind of ''{{{info}}}'' that emulates the behavior of the Lynx webbrowser.
;{{{rev}}}
:Reverse the order of characters on each line of the file and print the results to STDOUT.
;{{{sed}}}
://S//tream //ed//itor. Edit files without user interaction. See also ''{{{tr}}}''.
;{{{shred}}}
:Overwrite files to make the contents unrecoverable, and optionally delete them.
;{{{sort}}}
:[[Sort|Sorting on Linux]] the lines of files. See also  ''{{{comm}}}'', ''{{{join}}}'', and ''{{{uniq}}}''.
;{{{split}}}
:Split file into equal-sized segments. See also ''{{{csplit}}}''.
;{{{strings}}}
:Search (binary) files for strings of printable characters that are at least four characters long and followed by an unprintable character.
;{{{sum}}}
:Print checksum of files to STDOUT. See also ''{{{cksum}}}''.
;{{{tac}}}
:Print lines of files in reversed order to STDOUT. See also ''{{{cat}}}''.
;{{{tail}}}
:Print last 10 lines of files to STDOUT. See also ''{{{head}}}''.
;{{{tar}}}
:Copy files to or restore files from an archive medium.
;{{{tr}}}
:Translate characters. See also ''{{{sed}}}''.
;{{{unexpand}}}
:Convert whitespace to tabs and write to STDOUT. See also ''{{{expand}}}''.
;{{{uniq}}}
:Remove duplicate adjacent lines. See also ''{{{cut}}}'', ''{{{join}}}'', and ''{{{sort}}}''.
;{{{uudecode}}}
:Re-create the original file from a ''{{{uuencode}}}''d one. See also ''{{{mimencode}}}''.
;{{{uuencode}}}
:Convert a (binary) file to '~Unix-to-Unix encoding' or base64 encoding. See also ''{{{uudecode}}}'' and ''{{{mimencode}}}''.
;{{{wc}}}
:'Word count': print statistics about the contents of files to STDOUT.
===/%

%/+++(~VisitLinuxFileComparison)![File comparison &darr;|show comparison][File comparison &uarr;|hide comparison]
;{{{cmp}}}
:Compare two files.
;{{{comm}}}
:Compare two sorted files. See also ''{{{diff}}}'' and ''{{{uniq}}}''.
;{{{diff}}}
:Compare two text files. See also ''{{{comm}}}'' and ''{{{uniq}}}''
;{{{diff3}}}
:Compare three files.
;{{{merge}}}
:Perform three-way file merge.
;{{{patch}}}
:Apply the specified patches (as produced by ''{{{diff}}}'') to a file.
;{{{sdiff}}}
:Find differences between two files and merge them interactively into a third file.
===/%

%/+++(~VisitLinuxFileCompression)![File compression &darr;|show compression][File compression &uarr;|hide compression]
;{{{bzcat}}}
:Apply ''{{{cat}}}'' to files in ''{{{bzip2}}}'' format.
;{{{bzcmp}}}
:Apply ''{{{cmp}}}'' to files in ''{{{bzip2}}}'' format.
;{{{bzdiff}}}
:Apply ''{{{diff}}}'' to files in ''{{{bzip2}}}'' format.
;{{{bzgrep}}}
:Apply ''{{{grep}}}'' to files in ''{{{bzip2}}}'' format.
;{{{bzip2}}}, {{{bunzip2}}}, {{{bzip2recover}}}
:File compression and decompression utility similar to ''{{{gzip}}}'', using a different algorithm and encoding method to get better compression; ''{{{bzip2}}}'' appends {{high1{''{{{.bz2}}}''}}} extension to the filename.
;{{{bzless}}}
:Apply ''{{{less}}}'' to files in ''{{{bzip2}}}'' format.
;{{{bzmore}}}
:Apply ''{{{more}}}'' to files in ''{{{bzip2}}}'' format.
;{{{compress}}}
:Compress files and append {{high1{''{{{.Z}}}''}}} to the filename. See also ''{{{gzip}}}'' and ''{{{bzip2}}}'', which are more commonly used now.
;{{{gunzip}}}
:Uncompress files compressed by ''{{{gzip}}}''.
;{{{gzexe}}}
:Compress executables that automatically uncompress when run.
;{{{gzip}}}
:Compress files with ~Lempel-Ziv coding (~LZ77) and append {{high1{''{{{.gz}}}''}}} to the filename.
;{{{tar}}}
:{{_{option ''{{{-j}}}'' -- ''{{{b}}}''(''{{{un}}}'')''{{{zip2}}}'' files before archiving/extracting
option ''{{{-z}}}'' -- ''{{{g}}}''(''{{{un}}}'')''{{{zip}}}'' files before archiving/extracting
option ''{{{-Z}}}'' -- (''{{{un}}}'')''{{{compress}}}'' files before archiving/extracting}}}
;{{{uncompress}}}
:Uncompress ''{{{compress}}}''ed files.
;{{{unxz}}}
:Uncompress files compressed by ''{{{xz}}}''.
;{{{xz}}}
:Compress files with ~Lempel-Ziv-Markov chain algorithm (LZMA/~LZMA2) and append {{high1{''{{{.xz}}}''}}} to the filename.
;{{{xzcat}}}
:Apply ''{{{cat}}}'' to files in ''{{{xz}}}'' format.
;{{{xzcmp}}}
:Apply ''{{{cmp}}}'' to files in ''{{{xz}}}'' format.
;{{{xzdiff}}}
:Apply ''{{{diff}}}'' to files in ''{{{xz}}}'' format.
;{{{xzgrep}}}, {{{xzegrep}}}, {{{xzfgrep}}}
:Apply ''{{{grep}}}'', ''{{{egrep}}}'', ''{{{fgrep}}}'' to files in ''{{{xz}}}'' format.
;{{{xzless}}}
:Apply ''{{{less}}}'' to files in ''{{{xz}}}'' format.
;{{{xzmore}}}
:Apply ''{{{more}}}'' to files in ''{{{xz}}}'' format.
;{{{zcat}}}
:Apply ''{{{cat}}}'' to files in ''{{{gzip}}}'' format.
;{{{zcmp}}}
:Apply ''{{{cmp}}}'' to files in ''{{{gzip}}}'' format.
;{{{zdiff}}}
:Apply ''{{{diff}}}'' to files in ''{{{gzip}}}'' format.
;{{{zforce}}}
:Rename all ''{{{gzip}}}''ped files to //{{{<filename>}}}//{{{.gz}}}.
;{{{zgrep}}}, {{{zegrep}}}, {{{zfgrep}}}
:Apply ''{{{grep}}}'', ''{{{egrep}}}'', ''{{{fgrep}}}'' to files in ''{{{gzip}}}'' format.
;{{{zless}}}
:Apply ''{{{less}}}'' to files in ''{{{gzip}}}'' format.
;{{{zmore}}}
:Apply ''{{{more}}}'' to files in ''{{{gzip}}}'' format.
;{{{znew}}}
:Uncompress {{high1{''{{{.Z}}}''}}} files and recompress them in {{high1{''{{{.gz}}}''}}} format.
===/%

%/+++(~VisitLinuxEditors)![Text editors &darr;|show editors][Text editors &uarr;|hide editors]
;{{{ed}}}
:An interactive command-based line editor. The primal editor of Unix, preserved on account of historical interest.
;{{{emacs}}}
:A text editor and all-purpose work environment ('an operating system of its own'), with a rather steep if not vertical learning curve. One side of the endless Editor wars.
;{{{ex}}}
:An interactive command-based line editor. The name is short for //ex//tended, as it was intended as an extension of the more primitive ''{{{ed}}}''. Later incorporated in ''{{{vi}}}''.
;{{{gvim}}}
:The GUI version of ''{{{vim}}}''.
;{{{nano}}}
:A small and friendly text editor.
;{{{vi}}}
:A full-screen text editor built on top of ''{{{ex}}}''. The name -- short for '//vi//sual editor' -- is pronounced as //vee-eye//. This is the other one in the never-ending Editor wars. Learning curve hardly better than that of ''{{{emacs}}}''.
;{{{vim}}}
:An enhanced version of the ''{{{vi}}}'' editor.
[img[data/images/real_programmers.png]] &nbsp; http://xkcd.com/378/
===/%

%/+++(~VisitLinuxUsers)![Users &darr;|show users][Users &uarr;|hide users]
;{{{finger}}}
:Print data about users to STDOUT. //Not installed on the SAS BI servers.//
;{{{groups}}}
:Print groups of users to STDOUT. See also ''{{{id}}}''.
;{{{id}}}
:Print information about a user to STDOUT. See also ''{{{groups}}}''.
;{{{last}}}
:Prints the most recent logins to STDOUT.
;{{{lastlog}}}
:Print the last login times to STDOUT.
;{{{logname}}}
:Print the user's login name to STDOUT.
;{{{users}}}
:Print all login sessions to STDOUT.
;{{{w}}}
:Essentially a combination of ''{{{uptime}}}'', ''{{{who}}}'', and ''{{{ps}}} {{{-a}}}''.
;{{{who}}}
:Print users currently logged in to STDOUT.
;{{{whoami}}}
:Equivalent to''{{{ id -un}}}''.
===/%

%/+++(~VisitLinuxSystemStatus)![System status &darr;|show status][System status &uarr;|hide status]
;{{{date}}}
:Print the current date and time to STDOUT.
;{{{env}}}
:Print the current environment to STDOUT, and optionally set environment variables. If a command is specified, execute it under the (modified) environment.
;{{{locale}}}
:Print locale settings to STDOUT.
;{{{printenv}}}
:Print environment variables to STDOUT.
===/%

%/+++(~VisitLinuxShellProgramming)![Shell programming &darr;|show shell programming][Shell programming &uarr;|hide shell programming]
;{{{echo}}}
:Print argument to STDOUT.
;{{{expr}}}
:Evaluate arguments as an expression and print the result to STDOUT.
;{{{false}}}
:A null command that returns an unsuccessful ({{{nonzero}}}) exit status.
;{{{printf}}}
:Print strings using the specified formats to STDOUT.
;{{{sleep}}}
:Wait some time before executing another command.
;{{{test}}}
:Verify an expression with respect to files, strings, and/or integers; return a zero exit status when the outcome is {{{true}}}, otherwise a nonzero exit status. Also formatted as ''{{{[}}}''...''{{{]}}}''.
;{{{true}}}
:A null command that returns a successful ({{{0}}}) exit status.
;{{{usleep}}}
:Wait some microseconds before executing another command.
===/%

%/+++(~VisitLinuxMiscellaneous)![Miscellaneous &darr;|show miscellaneous][Miscellaneous &uarr;|hide miscellaneous]
;{{{cal}}}
:Print calendar to STDOUT.
;{{{look}}}
:Look for words that begin with some string.
;{{{passwd}}}
:Set password.
;{{{tee}}}
:Accept data from STDIN and send it to both STDOUT and files.
;{{{time}}}
:Time the execution of a command.
;{{{uuidgen}}}
:Print a new Universal Unique Identifier (UUID) to STDOUT.
;{{{watch}}}
:Run a command repeatedly, so that you can watch the output changing.
;{{{xargs}}}
:Execute a command (with any initial arguments), but read remaining arguments from STDIN.
===/%

%/+++(~VisitLinuxMore)![Even more &darr;|show more][Even more &uarr;|hide more]
!!!Host information
*arch
*dig
*dnsdomainname
*free
*host
*hostid
*hostname
*uname/%

%/
!!!System activity and process management
*kill
*nice
*nohup
*ps
*renice
*script
*skill
*snice
*su
*sudo
*top
*uptime
*vmstat/%

%/
!!!Scheduling
*at
*atq
*atrm
*batch
*cron
*crontab/%

%/
!!!Networking
*ifconfig
*netstat
*ping/%

%/
!!!Programming
*cpp
*g++
*gcc
*ldd
*make
===
!!!!{{f2d{Broncode opgemaakt volgens //Revised Report on the Algorithmic Language ALGOL 60//}}}
{{ib d2 r ws pref b2w serif widenq{
''integer procedure'' //faculteit//(//n//)  ;  ''value'' //n//  ;
      ''integer'' //n//  ;
      //faculteit// := ''if'' //n//=0 &or; //n//=1 ''then'' 1 ''else'' //n//&times;//faculteit//(//n//-1)  ;
}}}
!!!!{{f2d{Codevoorbeeld in //ALGOL handleiding van de praktika Numerieke Analyse//}}}
{{ib pre{
__integer__ __procedure__ faculteit(n); __value__ n;
   __integer__ n;
   faculteit := __if__ n=0 V n=1 __then__ 1 __else__ n*faculteit(n-1);
}}}
!!!!{{f2d{Hoe te coderen voor de ALGOL-compilers van ICL en IBM}}}
{{ib pre{
'INTEGER' 'PROCEDURE' FACULTEIT(N); 'VALUE' N;
   'INTEGER' N;
   FACULTEIT := 'IF' N=0 'OR' N=1 'THEN' 1 'ELSE' N*FACULTEIT(N-1);
}}}
!!!!{{f2d{Voor altijd&#x200a;!}}}
https://www.algol60.org
<<tiddler [[{}::togglesliders]]>> In plaats van alle afhankelijkheden en meerwaardige feiten binnen een relatie op te sommen, kan men deze ook grafisch weergeven. Al is dit artikel dan primair gericht op visuele presentatie van de verhoudingen tussen de attributen van een relatie, aan enige tekstuele formulering valt niet geheel te ontkomen./%
%/
++++(AfhankelijkheidsdiagrammenLegenda)!![Legenda &darr;|toon legenda][Legenda &uarr;|verberg legenda]
| [img[attribute|data/images/DD - attribute.png]] |Attribuut of attributenverzameling -- wil je van een enkelvoudig attribuut aangeven of deze NULL mag zijn of niet, dan kun je dat doen met een hol respectievelijk massief bolletje in de rechter benedenhoek |
| [img[prime attribute|data/images/DD - prime attribute.png]] |Primair attribuut of verzameling van primaire attributen |
| [img[candidate key|data/images/DD - candidate key.png]] |Kandidaatsleutel bestaande uit één of meer attributen |
| [img[primary key|data/images/DD - primary key.png]] |Primaire sleutel bestaande uit één of meer attributen |
| [img[multivalued fact|data/images/DD - multivalued fact.png]] |Verzameling van meer dan één attribuut, meerwaardig feit (multivalued fact) |
| [img[candidate key (more than one attribute)|data/images/DD - candidate key (more than one attribute).png]] |Kandidaatsleutel bestaande uit meer dan één attribuut |
| [img[primary key (more than one attribute)|data/images/DD - primary key (more than one attribute).png]] |Primaire sleutel bestaande uit meer dan één attribuut |
| [img[functional dependency|data/images/DD - functional dependency.png]] |Functionele afhankelijkheid (functional dependency) |
| [img[multivalued dependency|data/images/DD - multivalued dependency.png]] |Meerwaardige afhankelijkheid (multivalued dependency) |
| [img[constraint|data/images/DD - constraint.png]] |Beperking (constraint) |
| [img[relation schema|data/images/DD - relation schema.png]] |Relatieschema |
;Supersleutel (superkey)
:Een combinatie van attributen die voor ieder tupel in de relatie een unieke waarde heeft. De combinatie van //alle// attributen is een supersleutel, omdat geen twee tupels binnen een relatie hetzelfde mogen zijn.
;Kandidaatsleutel (candidate key)
:Een supersleutel waaruit geen attributen kunnen worden weggenomen zonder bovenstaande uniciteitsregel te overtreden.
;Primair attribuut (prime attribute)
:Een attribuut in een kandidaatsleutel.
;Primaire sleutel (primary key)
:De kandidaatsleutel die als primaire sleutel is aangewezen. Een relatie //moet// nu eenmaal een primaire sleutel hebben.
===/%

%/++++(AfhankelijkheidsdiagrammenConcepten)!![Concepten in tekst en beeld &darr;|toon concepten][Concepten in tekst en beeld &uarr;|verberg concepten]
Met X, Y enz. kunnen zowel enkelvoudige attributen als samengestelde attribuutverzamelingen van een relatieschema R worden aangeduid.
|vertical-align:top;''Meerwaardig feit (multivalued fact):'' {{high2{XY}}}<br>Bij elke waarde van X kunnen verscheidene waarden van Y horen, en omgekeerd.<br>XY is een verkorte notatie voor {{high2{X&nbsp;{{stix{&cup;}}}&nbsp;Y}}} of {{high2{{X,&nbsp;Y"""}"""}}}. In algebraïsche uitdrukkingen zoals X&nbsp;{{stix{&cup;}}}&nbsp;Y worden de operandi altijd als verzameling opgevat. Stellen Griekse letters enkelvoudige attributen voor, dan wordt //&alpha;&nbsp;//{{stix{&cup;}}}&nbsp;//&beta;// uitgelegd als {//&alpha;//}&nbsp;{{stix{&cup;}}}&nbsp;{//&beta;//} oftewel {//&alpha;//,&nbsp;//&beta;//}. In de opsomming {X,&nbsp;Y} geldt de conventie dat geneste attribuutverzamelingen worden platgeslagen, met andere woorden {"""{"""//&alpha;//,&nbsp;//&beta;//},&nbsp;{//&alpha;//,&nbsp;//&gamma;//}} wordt geïnterpreteerd als {//&alpha;//,&nbsp;//&beta;//,&nbsp;//&gamma;//}. |vertical-align:top;[img[Multivalued fact|data/images/DD Multivalued fact.png]] |
|vertical-align:top;''Functionele afhankelijkheid:'' {{high2{X&nbsp;&rarr;&nbsp;Y}}}<br>Bij iedere waarde van X behoort slechts één waarde van Y.<br>Omgekeerd kunnen bij iedere waarde van Y wel verschillende waarden van X voorkomen.<br>Feitelijk is X&nbsp;&rarr;&nbsp;Y een speciaal geval van XY. |vertical-align:top;[img[Functional dependency|data/images/DD Functional dependency.png]] |
|vertical-align:top;''Bijectieve afhankelijkheid:'' {{high2{X&nbsp;&harr;&nbsp;Y}}}<br>Dit is de combinatie van X&nbsp;&rarr;&nbsp;Y en Y&nbsp;&rarr;&nbsp;X. |vertical-align:top;[img[Bijective dependency|data/images/DD Bijective dependency.png]] |
|vertical-align:top;''Triviale afhankelijkheid'':<br>XY&nbsp;&rarr;&nbsp;Y is triviaal. Algemener geformuleerd: als Y&nbsp;&sube;&nbsp;Z dan is Z&nbsp;&rarr;&nbsp;Y triviaal. Ook Z&nbsp;&rarr;&nbsp;&empty; is triviaal, wegens &empty;&nbsp;&sube;&nbsp;Z. |vertical-align:top;[img[Trivial dependency|data/images/DD Trivial dependency.png]] |
|vertical-align:top;''Volledige/gedeeltelijke functionele afhankelijkheid (full/partial functional dependency):''<br>In A&nbsp;&rarr;&nbsp;B is B is //volledig// functioneel afhankelijk van A indien er geen attribuut uit A kan worden verwijderd zonder de afhankelijkheid te verliezen, zoals bij XY&nbsp;&rarr;&nbsp;Z in het diagram hiernaast.<br> Kan dat wel, dan is er sprake van //gedeeltelijke// functionele afhankelijkheid. Vanwege de functionele afhankelijkheid Y&nbsp;&rarr;&nbsp;W is de functionele afhankelijkheid XY&nbsp;&rarr;&nbsp;W niet volledig, want attribuut X kan daar zonder gevolgen uit worden weggelaten.<br><br>''Determinant:''<br>Een attribuut of attributenverzameling is een //determinant// indien een ander attribuut er volledig functioneel afhankelijk van is. In nevenstaand voorbeeld is XY de determinant van Z, en is Y de determinant van W. |vertical-align:top;[img[Full and partial functional dependency|data/images/DD Full and partial functional dependency.png]] |
|vertical-align:top;''Transitieve afhankelijkheid:''<br> Als X&nbsp;&rarr;&nbsp;Y en Y&nbsp;&rarr;&nbsp;Z, dan is Z transitief afhankelijk van X in de functionele afhankelijkheid X&nbsp;&rarr;&nbsp;Z.|vertical-align:top;[img[Transitive dependency|data/images/DD Transitive dependency.png]] |
|vertical-align:top;''~Boyce-Codd afhankelijkheid:''<br>In de combinatie X&nbsp;&rarr;&nbsp;Y en YZ&nbsp;&rarr;&nbsp;X is Y ~Boyce-Codd afhankelijk van X (mits Z&nbsp;&ne;&nbsp;&empty;, anders zou het een bijectieve afhankelijkheid zijn). Of algemener uitgedrukt wanneer we W voor YZ substitueren: Y is ~Boyce-Codd afhankelijk van X indien W&nbsp;&rarr;&nbsp;X en Y&nbsp;&sub;&nbsp;W. |vertical-align:top;[img[Boyce-Codd dependency|data/images/DD Boyce-Codd dependency.png]] |
|vertical-align:top;''Meerwaardige afhankelijkheid (multivalued dependency):'' {{high2{X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y|Z}}}<br>Vormen XY en XZ twee onderling onafhankelijke meerwaardige feiten, dan is er sprake van twee meerwaardige afhankelijkheden {{high2{X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y}}} en {{high2{X&nbsp;{{stix{&#x21a0;}}}&nbsp;Z}}}, waarvan de uitdrukking {{muliLine{X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y|Z}}} een samensmelting is. Weliswaar kunnen er meer dan twee meerwaardige afhankelijkheden in een relatie voorkomen, maar ze treden altijd gepaard op. X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y impliceert een X&nbsp;{{stix{&#x21a0;}}}&nbsp;Z waarin Z = R &minus; Y &minus; X.<br>Terwijl functionele afhankelijkheid de aanwezigheid van bepaalde tupels uitsluit, doet meerwaardige afhankelijkheid het omgekeerde, ze stelt de aanwezigheid van bepaalde tupels juist //verplicht//. De voorwaarde voor X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y is namelijk:<br>&nbsp;&nbsp;&nbsp;&nbsp;@@color(blue):&forall;@@ //r//(R), @@color(blue):&forall;@@ //t//~~1~~, //t//~~2~~ &isin; //r// @@color(blue):: (@@ //t//~~1~~[X] = //t//~~2~~[X] @@color(blue):&rArr;@@<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@@color(blue):&exist;@@ //t//~~3~~, //t//~~4~~ &isin; //r// @@color(blue)::@@<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//t//~~3~~[X] = //t//~~1~~[X] @@color(blue):&nbsp;&and;&nbsp;@@ //t//~~3~~[Y] = //t//~~1~~[Y] @@color(blue):&nbsp;&and;&nbsp;@@ //t//~~3~~[Z] = //t//~~2~~[Z] @@color(blue):&nbsp;&and;@@<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//t//~~4~~[X] = //t//~~2~~[X] @@color(blue):&nbsp;&and;&nbsp;@@ //t//~~4~~[Y] = //t//~~2~~[Y] @@color(blue):&nbsp;&and;&nbsp;@@ //t//~~4~~[Z] = //t//~~1~~[Z]<br>&nbsp;&nbsp;&nbsp;&nbsp;@@color(blue):)@@<br>Hierin is //r//(R) een geldige relatie volgens het relatieschema R, is //t~~x~~// een tupel, en is Z = R &minus; X &minus; Y (of Z = R &minus; Y, dat maakt niet uit). Zie ook de voorbeeldrelatie //r// hiernaast: gegeven de tupels //t//~~1~~ en //t//~~2~~ dienen //t//~~3~~ en //t//~~4~~ eveneens in de relatie aanwezig te zijn. |vertical-align:top;[img[Multivalued dependency|data/images/DD Multivalued dependency.png]]<br>{{ib ml1em fwhi{|

|col1 fbla|k
|!//r//                             | !&nbsp;&nbsp;X&nbsp;&nbsp; | !&nbsp;&nbsp;Y&nbsp;&nbsp; | !&nbsp;&nbsp;Z&nbsp;&nbsp; |
| //t//~~1~~ | //x//~~1~~                 | //y//~~1~~                 | //z//~~1~~                 |
| //t//~~2~~ | //x//~~1~~                 | //y//~~2~~                 | //z//~~2~~                 |
| //t//~~3~~ | //x//~~1~~                 | //y//~~1~~                 | //z//~~2~~                 |
| //t//~~4~~ | //x//~~1~~                 | //y//~~2~~                 | //z//~~1~~                 |
}}} |
|vertical-align:top;''Triviale/niet-triviale meerwaardige afhankelijkheid:''<br>Triviale meerwaardige afhankelijkheden zijn:<br>&nbsp;&bull;&nbsp; X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y&nbsp;&nbsp;@@color(blue):&and;@@&nbsp;&nbsp;X&nbsp;{{stix{&cup;}}}&nbsp;Y&nbsp;=&nbsp;R&nbsp; (oftewel Z&nbsp;=&nbsp;&empty;)<br>&nbsp;&bull;&nbsp; X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y&nbsp;&nbsp;@@color(blue):&and;@@&nbsp;&nbsp;Y&nbsp;&sube;&nbsp;X<br>&nbsp;&bull;&nbsp; X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y&nbsp;&nbsp;@@color(blue):&and;@@&nbsp;&nbsp;X&nbsp;&rarr;&nbsp;Y&nbsp; {{ref{[[[1]|##1]]}}}<br>In deze gevallen bevat //r// vanzelf al de benodigde tupels //t//~~3~~&nbsp;=&nbsp;//t//~~1~~ en //t//~~4~~&nbsp;=&nbsp;//t//~~2~~ (eerste geval) of //t//~~3~~&nbsp;=&nbsp;//t//~~2~~ en //t//~~4~~&nbsp;=&nbsp;//t//~~1~~ (andere twee gevallen). Alleen niet-triviale meerwaardige afhankelijkheden zijn werkelijk relevant als het erom gaat of een relatie in de vierde normaalvorm staat of niet. |~|
|vertical-align:top;''Joinafhankelijkheid (join dependency):'' {{high2{R&nbsp;=&nbsp;R~~1~~&nbsp;&#x2A1D;&nbsp;R~~2~~&nbsp;&#x2A1D;&nbsp;...}}}<br>Joinafhankelijkheid houdt in dat een een join van de projectierelaties van een relatie gelijk is aan de oorspronkelijke relatie.<br><br>De joinafhankelijkheid heet ''triviaal'' als er één of meer projecties in de join zijn betrokken die alle attributen van de oorspronkelijke relatie bevatten. |vertical-align:top; [img[Join dependency|data/images/DD Join dependency.png]] |
|vertical-align:top;''Beperking:'' {{high2{X&nbsp;{{stix{{{up1px{--}}}&#x22b3;&#x22b3;}}}&nbsp;Y}}}<br>Het waardenbereik van Y kan door X worden beperkt zonder dat X daarbij geheel bepalend is. Bijvoorbeeld wanneer Y&nbsp;=&nbsp;{Z,&nbsp;W} en X&nbsp;&rarr;&nbsp;Z maar X&nbsp;{{stix{&#x219b;}}}&nbsp;W.<br>Het kan echter ook voorkomen dat de interne structuur van een enkelvoudig attribuut Y van dien aard is dat niet alle combinaties met X mogelijk zijn, zoals hiernaast getekend.<br>Het is zelfs mogelijk dat de beperking niet zozeer in de interne structuur van Y tot uiting komt, maar dat er aan X een geldig waardenbereik van Y is verbonden, of een limitatieve opsomming van geldige Y-waarden. |vertical-align:top; [img[Constraint|data/images/DD Constraint.png]] |
===/%

%/++++(AfhankelijkheidsdiagrammenFormularium)!![Formularium &darr;|toon formularium][Formularium &uarr;|verberg formularium]
Hieronder nog wat theoretisch funderingsmateriaal van wiskundige aard, te beginnen met de drie axioma's van Armstrong, gevolgd door vier afleidingsregels met betrekking tot functionele afhankelijkheden, en afgesloten met acht regels waarin meerwaardige afhankelijkheden figureren. De quantoren en logische operatoren, die een lagere prioriteit hebben, zijn omwille van de leesbaarheid blauw gekleurd. De algebraïsche operatoren {{stix{&cap;}}}, {{stix{&cup;}}} en &minus; hebben de hoogste prioriteit.
#@@color(#00c):"""Reflexiviteit:"""@@ Y&nbsp;&sube;&nbsp;X @@color(blue):&nbsp;&rArr;@@&nbsp; X&nbsp;&rarr;&nbsp;Y
#@@color(#00c):"""Augmentatie:"""@@ X&nbsp;&rarr;&nbsp;Y @@color(blue):&nbsp;&rArr;&nbsp;@@ XZ&nbsp;&rarr;&nbsp;YZ
#{{multiLine{@@color(#00c):"""Transitiviteit:"""@@ X&nbsp;&rarr;&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ Y&nbsp;&rarr;&nbsp;Z @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;&rarr;&nbsp;Z
&nbsp;}}}
#@@color(#00c):"""Vereniging:"""@@ X&nbsp;&rarr;&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ X&nbsp;&rarr;&nbsp;Z @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;&rarr;&nbsp;YZ
#@@color(#00c):"""Decompositie:"""@@ X&nbsp;&rarr;&nbsp;YZ @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;&rarr;&nbsp;Y  @@color(blue):&nbsp;&and;&nbsp;@@ X&nbsp;&rarr;&nbsp;Z
#@@color(#00c):"""Pseudotransitiviteit:"""@@ X&nbsp;&rarr;&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ YZ&nbsp;&rarr;&nbsp;W @@color(blue):&nbsp;&rArr;&nbsp;@@ XZ&nbsp;&rarr;&nbsp;W
#{{multiLine{@@color(#00c):"""Compositie:"""@@ X&nbsp;&rarr;&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ Z&nbsp;&rarr;&nbsp;W @@color(blue):&nbsp;&rArr;&nbsp;@@ XZ&nbsp;&rarr;&nbsp;YW
&nbsp;}}}
#@@color(#00c):"""Complementering:"""@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;R&nbsp;&minus;&nbsp;Y&nbsp;&minus;&nbsp;X
#@@color(#00c):"""Meerwaardige augmentatie:"""@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ Z&nbsp;&nbsp;&sube;&nbsp;R @@color(blue):&nbsp;&and;&nbsp;@@ W&nbsp;&sube;&nbsp;Z @@color(blue):&nbsp;&rArr;&nbsp;@@ XZ&nbsp;{{stix{&#x21a0;}}}&nbsp;W
#@@color(#00c):"""Meerwaardige transitiviteit:"""@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ Y&nbsp;{{stix{&#x21a0;}}}&nbsp;Z @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Z&nbsp;&minus;&nbsp;Y
#@@color(#00c):"""Replicatie:"""@@ X&nbsp;&rarr;&nbsp;Y @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y
#@@color(#00c):"""Coalescentie:"""@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ Z&nbsp;&sube;&nbsp;Y @@color(blue):&nbsp;&and;&nbsp; (&exist;@@&nbsp;W&nbsp;@@color(blue):: @@W&nbsp;&sube;&nbsp;R @@color(blue):&nbsp;&and;&nbsp;@@ W&nbsp;{{stix{&cap;}}}&nbsp;Y&nbsp;=&nbsp;&empty; @@color(blue):&nbsp;&and;&nbsp;@@ W&nbsp;&rarr;&nbsp;Z@@color(blue):) &nbsp;&rArr;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Z
#@@color(#00c):"""Meerwaardige vereniging:"""@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Z @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;YZ
#@@color(#00c):"""Doorsnede:"""@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Z @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y&nbsp;{{stix{&cap;}}}&nbsp;Z
#@@color(#00c):"""Verschil:"""@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y @@color(blue):&nbsp;&and;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Z @@color(blue):&nbsp;&rArr;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Y&nbsp;&minus;&nbsp;Z @@color(blue):&nbsp;&and;&nbsp;@@ X&nbsp;{{stix{&#x21a0;}}}&nbsp;Z&nbsp;&minus;&nbsp;Y/%
%/
Een bijzonder geval van regel 7 verkrijg je met W&nbsp;=&nbsp;&empty;: omdat Z&nbsp;&rarr;&nbsp;&empty; volgens regel 1 altijd waar is, geldt dus ook &nbsp;X&nbsp;&rarr;&nbsp;Y @@color(blue):&nbsp;&rArr;&nbsp;@@ XZ&nbsp;&rarr;&nbsp;Y.

De closure ''X^^+^^'' van een attributenverzameling ''X'' met betrekking tot de verzameling ''F'' van alle functionele afhankelijkheden is de verzameling van alle attributen die functioneel bepaald worden door ''X''. Het maakt daarbij niet uit of de afhankelijkheden misschien triviaal, onvolledig dan wel transitief zijn, alle functionele afhankelijkheden tellen mee.
*Stel ''R'' = {A,&nbsp;B,&nbsp;C,&nbsp;G,&nbsp;H,&nbsp;I}
*Stel ''F'' = {A&rarr;B,&nbsp;A&rarr;C,&nbsp;{C,&nbsp;G}&rarr;H,&nbsp;G&rarr;I}
*Dan is bijvoorbeeld (te bepalen met behulp van bovenstaande regels of een [[calculator|http://raymondcho.net/RelationalDatabaseTools/RelationalDatabaseTools]] waarin deze regels geïmplementeerd zijn):
**{A}^^+^^ = {A,&nbsp;B,&nbsp;C}
**{C}^^+^^ = {C}
**{C,&nbsp;G}^^+^^ = {C,&nbsp;G,&nbsp;H,&nbsp;I}
**{A,&nbsp;G}^^+^^ = {A,&nbsp;B,&nbsp;C,&nbsp;G,&nbsp;H,&nbsp;I}
Verwante begrippen zijn: de closure ''F^^+^^'' van ''F'', waarin alle functionele afhankelijkheden binnen de relatie, gedefinieerd of afgeleid, zijn opgenomen, en de closure ''D^^+^^'' van de verzameling ''D'' van afhankelijkheden in het algemeen, dus zowel functionele als meerwaardige.
===

----
|plain |k
| <html><a name="1">[1]</a></html>|In de literatuur heb ik nergens gevonden dat X&nbsp;&rarr;&nbsp;Y tot //triviale// vorm van meerwaardige afhankelijkheid wordt bestempeld. In elk geval zou je de meerwaardigheid //ontaard// kunnen noemen. Bij de bepaling of een relatie in de vierde normaalvorm staat of anders moet worden uitgesplitst in een aantal projecties, spelen zulke ontaarde gevallen geen rol. |
''{{up1px sans{<<showPopup tiddler:[[} Iteratie & recursie]] label: "Bundel ↘">>}}}''

According to Dominus in "From recursion to iterators", page 240:{{ref{[[[1]|##1]]}}}
<<<
{{sans{The general technique for converting such a function {{serif{[that doesn't have a tail call]}}} to one that does a tail call is to add an auxiliary parameter that records the return value so far. When the other parameters indicate that the recursion is complete, the function returns the return-value parameter. Instead of making a recursive call, waiting for the return value, modifying it, and returning the result, the modified version takes the return value parameter, modifies it appropriately, and passes it along.}}}
<<<

----
<html><a name="1">[1]</a></html> <<tiddler "Bibliografie##Dominus">> -- Chapter 5.
!!Legend
*//Abstract concept//
*@@bgcolor:#f5deaa;{{hws{Strategic layer}}}@@ -- @@bgcolor:#ffffaf;{{pref tt{ }}}@@Business layer -- @@bgcolor:#afffff;{{pref tt{ }}}@@Application layer -- @@bgcolor:#afffaf;{{pref tt{ }}}@@Technical layer -- @@bgcolor:#77dd77;{{pref tt{ }}}@@Physical layer -- @@bgcolor:#ffe0e0;{{pref tt{ }}}@@Implementation & Migration layer -- @@bgcolor:#ccccff;{{hws{Motivation aspect}}}@@
*{{hws b3w{Passive Structure}}} -- {{hws b3p{Behavior}}} -- {{hws b3l{Active Structure}}}/%

%/
!!Specializations of //Concept//
*//Element//
**//Behavior Element//
***''@@bgcolor:#f5deaa;{{hws{Capability}}}@@''
***''@@bgcolor:#f5deaa;{{hws{Course of Action}}}@@''
***//External Behavior Element//
****''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3p{Business Service}}}''
****''@@bgcolor:#afffff;&nbsp;@@{{hws b3p{Application Service}}}''
****''@@bgcolor:#afffaf;&nbsp;@@{{hws b3p{Technology Service}}}''
***//Internal Behavior Element//
****//Business Internal Behavior Element//
*****''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3p{Business Process}}}''
*****''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3p{Business Function}}}''
*****''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3p{Business Interaction}}}''
****//Application Internal Behavior Element//
*****''@@bgcolor:#afffff;&nbsp;@@{{hws b3p{Application Process}}}''
*****''@@bgcolor:#afffff;&nbsp;@@{{hws b3p{Application Function}}}''
*****''@@bgcolor:#afffff;&nbsp;@@{{hws b3p{Application Interaction}}}''
****//Technology Internal Behavior Element//
*****''@@bgcolor:#afffaf;&nbsp;@@{{hws b3p{Technology Process}}}''
*****''@@bgcolor:#afffaf;&nbsp;@@{{hws b3p{Technology Function}}}''
*****''@@bgcolor:#afffaf;&nbsp;@@{{hws b3p{Technology Interaction}}}''
***//Event//
****''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3p{Business Event}}}''
****''@@bgcolor:#afffff;&nbsp;@@{{hws b3p{Application Event}}}''
****''@@bgcolor:#afffaf;&nbsp;@@{{hws b3p{Technology Event}}}''
****''@@bgcolor:#ffe0e0;&nbsp;@@{{hws b3p{Implementation Event}}}''
***''@@bgcolor:#ffe0e0;&nbsp;@@{{hws b3p{Work Package}}}''
**//Structure Element//
***''@@bgcolor:#f5deaa;{{hws{Resource}}}@@''
***//Active Structure Element//
****''@@bgcolor:#ccccff;{{hws{Stakeholder}}}@@''
****//External Active Structure Element//
*****''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3l{Business Interface}}}''
*****''@@bgcolor:#afffff;&nbsp;@@{{hws b3l{Application Interface}}}''
*****''@@bgcolor:#afffaf;&nbsp;@@{{hws b3l{Technology Interface}}}''
****//Internal Active Structure Element//
*****//Business Internal Active Structure Element//
******''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3l{Business Actor}}}''
******''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3l{Business Role}}}''
******''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3l{Business Collaboration}}}''
*****//Application Internal Active Structure Element//
******''@@bgcolor:#afffff;&nbsp;@@{{hws b3l{Application Component}}}''
*******''@@bgcolor:#afffff;&nbsp;@@{{hws b3l{Application Collaboration}}}''
*****//Technology Internal Active Structure Element//
******''@@bgcolor:#afffaf;&nbsp;@@{{hws b3l{Node}}}''
*******''@@bgcolor:#afffaf;&nbsp;@@{{hws b3l{Device}}}''
*******''@@bgcolor:#afffaf;&nbsp;@@{{hws b3l{System software}}}''
*******''@@bgcolor:#afffaf;&nbsp;@@{{hws b3l{Technology Collaboration}}}''
*******''@@bgcolor:#77dd77;&nbsp;@@{{hws b3l{Facility}}}''
*******''@@bgcolor:#77dd77;&nbsp;@@{{hws b3l{Equipment}}}''
******''@@bgcolor:#afffaf;&nbsp;@@{{hws b3l{Path}}}''
******''@@bgcolor:#afffaf;&nbsp;@@{{hws b3l{Communication Network}}}''
******''@@bgcolor:#77dd77;&nbsp;@@{{hws b3l{Distribution Network}}}''
***//Passive Structure Element//
****//Business Passive Structure Element//
*****''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3w{Business Object}}}''
******''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3w{Contract}}}''
*****''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3w{Representation}}}''
****''@@bgcolor:#afffff;&nbsp;@@{{hws b3w{Data Object}}}''
****//Technology Object//
*****''@@bgcolor:#afffaf;&nbsp;@@{{hws b3w{Artifact}}}''
*****''@@bgcolor:#77dd77;&nbsp;@@{{hws b3w{Material}}}''
****''@@bgcolor:#ffe0e0;&nbsp;@@{{hws b3w{Deliverable}}}''
****''@@bgcolor:#ffe0e0;&nbsp;@@@@bgcolor:#afffaf;&nbsp;@@{{hws b3w{Gap}}}''
**//Motivation Element//
***''@@bgcolor:#ccccff;{{hws{Meaning}}}@@''
***''@@bgcolor:#ccccff;{{hws{Value}}}@@''
***''@@bgcolor:#ccccff;{{hws{Driver}}}@@''
***''@@bgcolor:#ccccff;{{hws{Assesment}}}@@''
***''@@bgcolor:#ccccff;{{hws{Goal}}}@@''
***''@@bgcolor:#ccccff;{{hws{Outcome}}}@@''
***''@@bgcolor:#ccccff;{{hws{Principle}}}@@''
***''@@bgcolor:#ccccff;{{hws{Requirement}}}@@''
****''@@bgcolor:#ccccff;{{hws{Constraint}}}@@''
**//Composite Element//
***''@@bgcolor:#ffffaf;&nbsp;@@{{hws b3w{Product}}}''
***''@@bgcolor:#ffbf80;{{hws{Location}}}@@''
***''@@border:1px dashed;{{hws s{Grouping}}}@@''
***''@@bgcolor:#ffe0e0;&nbsp;@@@@bgcolor:#afffaf;&nbsp;@@{{hws b3p{Platform}}}''
*//Relationship//
**//Structural Relationship//
***''{{high0 sh{C}}}omposition''
***''A{{high0 sh{g}}}gregation''
***''Ass{{high0 sh{i}}}gnment''
***''{{high0 sh{R}}}ealization''
**//Dependency Relationship//
***''Ser{{high0 sh{v}}}ing''
***''{{high0 sh{A}}}ccess''
***''I{{high0 sh{n}}}fluence''
**//Dynamic Relationship//
***''{{high0 sh{T}}}riggering''
***''{{high0 sh{F}}}low''
**//Other Relationship//
***''Ass{{high0 sh{o}}}ciation''
***''{{high0 sh{S}}}pecialization''
*//Relationship Connector//
**''(And) Junction''
**''Or Junction''
Years ago, too lazy to construct an elaborated [[ArchiMate diagram|Notation of ArchiMate concepts]], I sketched several more or less generic architectural overviews of some software products I would have to to deal with. The idea behind it was to have one comprehensable drawing of the main mechanisms and their mutual connections. Once done, I called my improvised drawing technique 'ArchiTwit', as it could be regarded as a pretty minimalistic extract of the ArchiMate language. Here is my very first ArchiTwit diagram from December 2017:
[img[data/images/ArchiMate/Kijkdoos.png]]
It consists of three types of nodes (or 'mechanisms'):
*Actor, represented by a stick figure
*Function, represented by an oval box or a box with round corners
*Passive structure, represented by a box with square corners 
and two types of connectors:
*Contribution, {{tt{{{hws{//A//}}}&mdash;&mdash;&mdash;>{{hws{//B//}}}}}} means "//A// contributes something to the benefit of //B//"
*Inclusion, {{tt{{{hws{//A//}}}&diams;&mdash;&mdash;&mdash;{{hws{//B//}}}}}} means "//A// includes //B//" (~ArchiTwit makes no distinction between aggregation and composition{{ref{&#x200a;[[[1]|##1]]&#x200a;}}})
The mechanism names and connector numbers can be used as a reference in text that describes the architecture and organization in more detail. For each mechanism and each connection the author can ask himself what is needed to realize that element, and then try to answer the question in the text.

Not all relations are represented by a connector in the diagram above. Inclusion can be rendered as well by nesting the involved nodes -- an appropriate presentation of inclusions that don't need a reference number. So actually the diagram also states:
*{{hws{Managed system}}}{{tt{&diams;&mdash;&mdash;&mdash;}}}{{hws{Defined system}}}
*{{hws{Managed system}}}{{tt{&diams;&mdash;&mdash;&mdash;}}}{{hws{Build}}}
*{{hws{Defined system}}}{{tt{&diams;&mdash;&mdash;&mdash;}}}{{hws{Use}}}
*{{hws{Defined system}}}{{tt{&diams;&mdash;&mdash;&mdash;}}}{{hws{Presentation}}}
*{{hws{Defined system}}}{{tt{&diams;&mdash;&mdash;&mdash;}}}{{hws{View}}}/%
%/
The colors have no special meaning here. They just reflect my habit of coloring the (inner) active nodes, leaving the passive nodes blank. The nestings could have been accentuated by other means than a different line color.

The decision to model presentation and view here as passive elements is highly disputable. Maybe functions would have been a better choice.

----
<html><a name="1">[1]</a></html>&nbsp;  So it might be better to draw such connectors with a hollow lozenge: {{tt{&loz;&mdash;&mdash;&mdash;}}}
The archiving tool ''{{{tar}}}'' copies to or restore files from an archive medium. It has many options, and the syntax is somewhat peculiar in that options need not to be preceded by a dash (though they may be). See also https://www.gnu.org/software/tar/manual/tar.pdf. The three examples below are just the most popular peak of the top of the iceberg:
<html><pre>
<b>tar c</b><font color="darkorange"><i>[</i><b>&#x1D10;</b><i>][</i></font><b>v</b><font color="darkorange"><i>]</i></font><b>f</b> <font color="darkorange"><i>«tarfile» ...</i></font>  <font color="green"><i># archive ... into «tarfile»</i></font>
<b>tar t</b><font color="darkorange"><i>[</i></font><b>v</b><font color="darkorange"><i>]</i></font><b>f</b> <font color="darkorange"><i>«tarfile» [...]</i></font>   <font color="green"><i># list ... in «tarfile» if ... given, otherwise list all files in «tarfile»</i></font>
<b>tar x</b><font color="darkorange"><i>[</i></font><b>v</b><font color="darkorange"><i>]</i></font><b>f</b> <font color="darkorange"><i>«tarfile» [...]</i>   <font color="green"><i># extract ... from «tarfile» if ... given, otherwise extract all files from «tarfile»</i></font>
</pre></html>/%

%/The ''{{{-v}}}'' option makes the process verbose. Recommended. When no compression is involved, the usual filename extension for @@color(darkorange)://«tarfile»//@@ is ''{{{.tar}}}''. But the  option ''{{tt{-@@color(darkorange):&#x1D10;@@}}}'' gives you the opportunity to drive files through a [[compressor|Compressing with gzip, bzip2, xz]] of your own choice while archiving them. It is common practice to add the compression suffix to the archiver suffix, or to integrate them (e.g. {{high2{{{tt{//«name»//''.tar.gz''}}}}}} or {{high2{{{tt{//«name»//''.tgz''}}}}}}). To be a bit more specific about ''{{tt{-@@color(darkorange):&#x1D10;@@}}}'':

''{{pref{{{{  -z  }}}}}}'' Compress with ''{{{gzip}}}''. See [[here|Ingepakt op Linux, uit te pakken op Windows]] for the best filename extensions for @@color(darkorange)://«tarfile»//@@.
''{{pref{{{{  -j  }}}}}}'' Compress with ''{{{bzip2}}}''. See [[here|Ingepakt op Linux, uit te pakken op Windows]] for the best filename extensions for @@color(darkorange)://«tarfile»//@@.
''{{pref{{{{  -J  }}}}}}'' Compress with ''{{{xz}}}''. See [[here|Ingepakt op Linux, uit te pakken op Windows]] for the best filename extensions for @@color(darkorange)://«tarfile»//@@.
''{{pref{{{{  -a  }}}}}}'' Use the filename extension of @@color(darkorange)://«tarfile»//@@ to determine the compression program.

Unfortunately, the ''{{{-a}}}'' option doesn't work yet for the ''{{{.xz}}}'' and ''{{{.tzx}}}'' extensions in our SAS BI environment, so you are still thrown back on the ''{{{-J}}}'' option when you want to compress with {{{xz}}}. Compression options are not needed for listing or decompressing the archive contents, even not when it was compressed by {{{xz}}}.

Avoid creating (or modifying) an archive file @@color(darkorange)://«tarfile»//@@ in the same directory as the one you are archiving. And don't do something like {{high2{''{{{tar cvf ../archive.tar *}}}''}}} when {{{child}}} is the current directory, as the globbing character ''{{{*}}}'' would skip the hidden files on the {{{child}}} level.{{ref{[[[1]|##1]]}}} Say {{pref{{{high2{''{{{tar cvf ../archive.tar .}}}''}}}}}} or {{pref{{{high2{''{{{cd ..; tar cvf archive.tar child}}}''}}}}}} instead.

----
|plain |k
| <html><a name="1">[1]</a></html>|Actually, you can do something about that by setting the proper shell options with the ''{{{shopt}}}'' command. But it wouldn't be worth it for this case. |
Met het commando ''{{{stat}}}'' kun je de bestandsattributen van een [[inode|Het bestandssysteem van Linux]] opvragen. Je krijgt dan de volgende informatie voorgezet:
:{{pref{
{{{dev      }}}//Device number of filesystem//
{{{ino      }}}//Inode number//
{{{type     }}}//[[File type|Het bestandssysteem van Linux]]//
{{{mode     }}}//File mode ([[permissions|Het bestandssysteem van Linux]])//
{{{nlink    }}}//Number of [[hard links|Het bestandssysteem van Linux]] to the file//
{{{uid      }}}//Numeric ID and/or name of the [[user who owns|Het bestandssysteem van Linux]] the inode//
{{{gid      }}}//Numeric ID and/or name of the [[group that owns|Het bestandssysteem van Linux]] the inode//
{{{rdev     }}}//Device identifier//
{{{size     }}}//File size, in bytes//
{{{atime    }}}//Last access time//
{{{mtime    }}}//Last modification time//
{{{ctime    }}}//Last change time//
{{{blksize  }}}//Preferred blocksize for filesystem I/O//
{{{blocks   }}}//Number of blocks allocated//
}}}
(Helaas werkt ''{{{stat}}}'' op onze SAS ~BI-servers niet helemaal naar behoren. Bij een [[symbolic link|Symbolic links on Linux]] wordt informatie gegeven over de inode waarnaar de link verwijst in plaats van over de link zelf. Dat zou alleen mogen gebeuren als je het commando de optie ''{{{-L}}}'' meegeeft.)

De drie tijdattributen kunnen gemakkelijk worden misverstaan. Dit is het spel dat ermee gespeeld wordt:
*{{{atime}}} wijzigt bij elke toegang tot de inhoud, zelfs als de inode leeg is
*{{{mtime}}} wijzigt bij bijstelling van de inhoud, zelfs bij onveranderd opslaan ervan
*{{{ctime}}} wijzigt bij verandering van een ander attribuut dan {{{atime}}} (dus ook bij verandering van {{{nlink}}} of {{{mtime}}}) of bij verplaatsing dan wel hernoeming van een hard link naar de betrokken inode
Bij aanmaak van een nieuwe inode krijgen ze uiteraard alle drie dezelfde beginwaarde. Kopiëren met behulp van het commando ''{{{cp}}}'' geldt daarbij ook als aanmaak van een nieuwe inode. Alleen als daarbij via de optie ''{{{-p}}}'' of ''{{{--preserve}}}'' is bedongen dat de attributen van de te kopiëren inode moeten worden overgenomen, wordt daar voor zover mogelijk gehoor aan gegeven. Van de drie timestamps krijgt de kopie toch een nieuwe {{{ctime}}}, al was het maar omdat deze kopie een nieuw {{{ino}}} heeft gekregen. Er is nog een ander verschil bij kopiëren met of zonder preserve-optie: zonder die optie wordt in de inode die moest worden gekopieerd de {{{atime}}} geactualiseerd, en mèt die optie blijft daar de oorspronkelijke waarde behouden (en gaat deze ook over naar de kopie).
!!!!!!A&S
Harold Abelson and Gerald Jay Sussman with Julie Sussman, //Structure and interpretation of computer programs//, 2^^nd^^ edition. Cambridge, MA: The MIT Press, 1996. -- Ook bekend als //The wizard book// en als //SICP//. Omwille van de nauwkeurigheid noem ik het //SICP2//.
!!!!!!Alexander
Christopher Alexander, Sara Ishikawa, Murray Silverstein, e.a., //A pattern language: Towns, buildings, construction//. New York: University Press, 1977.
!!!!!!Algol-60
Peter Naur (editor), //Revised Report on the algorithmic language ALGOL 60//. Communications of the ACM, 1960.
!!!!!!Allen
John Allen, //Anatomy of LISP//. New York: McGraw-Hill, 1978.
!!!!!!Benthem
J.F.A.K. van Benthem, H.P. van Ditmarsch, J. Ketting, W.P.M. Meyer-Viol, //Logica voor informatici//. Amsterdam: Addison-Wesley, 1991.
!!!!!!Błażewicz
Jacek Błażewicz, Klaus H. Ecker, Erwin Pesch, Günter Schmidt & Jan Węglarz, //Scheduling computer and manufacturing processes//. Heidelberg: ~Springer-Verlag, 1996.
!!!!!!Clinger
William D. Clinger, Mitchell Wand, "Hygienic macro technology" in //Proc. ACM Program. Lang.// 4, HOPL, Article 80. Juni 2020.
!!!!!!CSUG
//Chez Scheme version 9 user's guide//. Cisco Systems (2019). In januari 2020 bijgewerkt voor versie 9.5.3. -- Ook bekend als //CSUG//.
!!!!!!Dominus
Mark Jason Dominus, //Higher-order Perl: Transforming programs with programs//. San Francisco, CA: Morgan Kaufman Publishers, 2005.
!!!!!!Dybvig
R. Kent Dybvig, //The Scheme programming language//, 4^^th^^ edition. Cambridge, MA: The MIT Press, 2009. -- Ook bekend als //TSPL4//.
!!!!!!EBNF
ISO/IEC 14977:1996(en), //Information technology — Syntactic metalanguage — Extended BNF//. International Organization for Standardization (ISO) & International Electrotechnical Commission (IEC), 1996.
!!!!!!Felleisen
Matthias Felleisen and Matthew Flatt, //Programming languages and lambda calculi.// --[[old Utah|http://www.cs.utah.edu/plt/publications/pllc.pdf]]-- [[new Utah|https://users.cs.utah.edu/~mflatt/past-courses/cs7520/public_html/s06/notes.pdf]], 2003.
!!!!!!GoF
Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides ('The Gang of Four'), //Design patterns: Elements of reusable object-oriented software//. Addison-Wesley, 1994.
!!!!!!Hegener
Michiel Hegener, Fred Hekket, Aad Wobbens & Wolter Wefers Bettink, //Het formulierenboek//, 4^^e^^ geheel herziene druk. Amsterdam: Uitgeverij TEPCO, 1984.
!!!!!!Hoogendoorn
Sander Hoogendoorn, //Pragmatisch modelleren met UML 2.0: Van idee naar applicatie//. Pearson Education Benelux, 2004.
!!!!!!Ierusalimschy
Roberto Ierusalimschy, //Programming in Lua//, 4^^th^^ edition. [[Lua.org|https://www.lua.org/]], 2016. -- Deze uitgave behandelt Lua 5.3.
!!!!!!Ierusalimschy-2019
Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes, //Lua 5.4 reference manual//. [[Lua.org|https://www.lua.org/]], 2019.
!!!!!!Jackson
Daniel Jackson, //Software Abstractions: Logic, Language, and Analysis//, revised edition. Cambridge, MA: The MIT Press, 2012. -- Bestrijkt Alloy Analyser versie 4.
!!!!!!K&R
Brian W. Kernighan, Dennis M. Ritchie, //The C programming language//, 2^^nd^^ edition. Englewood Cliffs, NJ: Prentice Hall, 1988.
!!!!!!Lutz
Mark Lutz, //Learning Python//, 5^^th^^ edition. Sebastopol, CA: O'Reilly, 2013.
!!!!!!Martin
James Martin, //Recommended diagramming standards for analysts and programmers: A basis for automation.// Englewood Cliffs, N.J.: ~Prentice-Hall, 1987<br>(Nederlandse vertaling: //Schematechnieken voor systeemanalisten en programmeurs: Een basis voor automatisering//. Schoonhoven: Academic Service, 1991).
!!!!!!Martin (EN)
James Martin, //Recommended diagramming standards for analysts and programmers: A basis for automation.// Englewood Cliffs, N.J.: ~Prentice-Hall, 1987<br>(Dutch translation: //Schematechnieken voor systeemanalisten en programmeurs: Een basis voor automatisering//. Schoonhoven: Academic Service, 1991).
!!!!!!Matthews-2004
Jacob Matthews, Robert Bruce Findler, Matthew Flatt, and Matthias Felleisen, "A visual environment for developing context-sensitive term rewriting systems". In //Proc. 15th Conference on Rewriting Techniques and Applications//, Aachen, June 2004. Springer-Verlag.
!!!!!!Matthews-2005
Jacob Matthews and Robert Bruce Findler, "An operational semantics for R5RS Scheme". In J. Michael Ashley and Michael Sperber, editors, //Proceedings of the Sixth Workshop on Scheme and Functional Programming//, pages 41–54, Tallin, Estonia, September 2005. Indiana University Technical Report TR619.
!!!!!!Matthews-2007
Jacob Matthews and Robert Bruce Findler, "An operational semantics for Scheme". //Journal of Functional Programming//, 2007. From --[[old Cambridge|http://www.cambridge.org/journals/JFP/]]-- [[new Northwestern|https://users.cs.northwestern.edu/~robby/pubs/papers/jfp2008-mf.pdf]].
!!!!!!Mullins
Craigh S. Mullins, //~DB2 Developer's Guide//, 5th edition. Indianapolis, IN: Sams Publishing, 2004. -- Bestrijkt ~DB2 versie 8.
!!!!!!Prata
Stephen Prata, //C Primer Plus//, 5th edition. Indianapolis, IN: Sams Publishing, 2005. -- Bestrijkt C99.
!!!!!!Rappin
Noel Rappin with Dave Thomas (edited by Katharine Dvorzak), //Programming Ruby 3.3: The Pragmatic Programmers' Guide//. The Pragmatic Programmers, 2024.
!!!!!!RnRS
[[Revised Report on the algorithmic language Scheme]]. -- Vaak aangeduid met R//n//RS.
!!!!!!Simionato
Michele Simionato, //The adventures of a Pythonista in Schemeland//, [[Release 0.1|http://www.phyast.pitt.edu/~micheles/scheme/TheAdventuresofaPythonistainSchemeland.pdf]]. 2009.
!!!!!!Spronck
Pieter Spronck, //De programmeursleerling: Leren coderen met Python 3//. 2024 ([[Nederlandse vertaling|http://www.spronck.net/pythonbook/dutchindex.xhtml]] van [[The Coder's Apprentice|http://www.spronck.net/pythonbook]]).
!!!!!!Stoy
Joseph E. Stoy, //Denotational Semantics: The Scott-Strachey approach to programming language theory//. Cambridge, MA: The MIT Press, 1977.
!!!!!!Swan
Tom Swan, //Programmeren met Turbo Pascal 6//. Schoonhoven: Academic Service, 1992<br>(Vertaling van //Mastering Turbo Pascal 6//, 4^^th^^ edition. Howard W. Sams & Company, 1991).
!!!!!!Thomas
Dave Thomas with Chad Fowler and Andy Hunt, //Programming Ruby 1.9 & 2.0: The Pragmatic Programmers' Guide//. The Pragmatic Programmers, 2013.
!!!!!!Wright
Andrew Wright and Matthias Felleisen, "A syntactic approach to type soundness". //Information and Computation//, 115(1):38–94, 1994. First appeared as Technical Report TR160, Rice University, 1991.
!!!!!!Y&C
Edward Yourdon, Larry L. Constantine, //Structured design: Fundamentals of a disciplinie of computer program and systems design//. Englewood Cliffs, NJ: Prentice Hall, 1979.<br>(De 'Second Edition' door YOURDON Press uit 1978 is in het [[Internet Archive|https://archive.org/details/Structured_Design_Edward_Yourdon_Larry_Constantine/page/n3/mode/2up]] te vinden. Het heeft er alles van weg dat de latere uitgave door Englewood Cliffs op exact dezelfde tekst is gebaseerd.)
!!!!!!Walraet
Bob Walraet, //Programming, the impossible challenge//. Amsterdam: North-Holland (Elsevier Science Publishers), 1988 (1989).
!!!!!!Wirth
Niklaus Wirth, //The programming language Pascal (revised report)//. Eidgenössische Technische Hochschule Zürich, 1973.
/%
!info
|Name|BreadcrumbsCommand|
|Source|http://www.TiddlyTools.com/#BreadcrumbsCommand|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Requires|BreadcrumbsPlugin|
|Description|"crumbs" command displays current breadcrumbs list in a popup|
Usage
<<<
{{{
<<tiddler BreadcrumbsCommand>>
<<tiddler BreadcrumbsCommand with: label tip>>
}}}
<<<
Example
<<<
{{{<<tiddler BreadcrumbsCommand with: "crumbs">>}}}
<<tiddler BreadcrumbsCommand##show with: "crumbs">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" class="TiddlyLink" title="$2"
	onclick="var p=Popup.create(this); if (!p) return;
		var d=createTiddlyElement(p,'div');
		d.style.whiteSpace='normal'; d.style.width='auto'; d.style.padding='2px';
		wikify('\<\<breadcrumbs [[\<html\>\<hr\>\</html\>]] [[<br>]]\>\>',d);
		Popup.show();
		event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();
		return false;
">$1</a></html>
!end
%/<<tiddler {{ var src='BreadcrumbsCommand'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with:	{{'$1'!='$'+'1'?'$1':'crumbs'}}
		{{'$2'!='$'+'2'?'$2':'tiddlers viewed during this session'}}>>
/***
|Name|BreadcrumbsPlugin|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.1.5//b//|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|list/jump to tiddlers viewed during this session plus "back" button/macro|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Documentation
<<<
see [[BreadcrumbsPluginInfo]]
<<<
!!!!!Configuration
<<<
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
<<option chkBreadcrumbsSave>> prompt to save breadcrumbs when 'Home' link is pressed
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order (most recent first)
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items

<<<
!!!!!Revisions
<<<
2012.06.10 2.1.5 refactored default options to eliminate global variable and use init() handling
| Please see [[BreadcrumbsPluginInfo]] for previous revision details |
2006.02.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.BreadcrumbsPlugin = { major: 2, minor: 1, revision: 5, date: new Date(2012,6,10) };
config.macros.breadcrumbs = {
	crumbs: [], // the list of current breadcrumbs
	askMsg: "Save current breadcrumbs before clearing?\n"
		+"Press OK to save, or CANCEL to continue without saving.",
	saveMsg: 'Enter the name of a tiddler in which to save the current breadcrumbs',
	saveTitle: 'SavedBreadcrumbs',
	options: {
		chkShowBreadcrumbs:		true,
		chkReorderBreadcrumbs:		true,
		chkCreateDefaultBreadcrumbs:	true,
		chkShowStartupBreadcrumbs:	false,
		chkBreadcrumbsReverse:		false,
		chkBreadcrumbsLimit:		false,
		txtBreadcrumbsLimit:		5,
		chkBreadcrumbsLimitOpenTiddlers:false,
		txtBreadcrumbsLimitOpenTiddlers:5,
		chkBreadcrumbsHideHomeLink:	false,
		chkBreadcrumbsSave:		false,
		txtBreadcrumbsHomeSeparator:	' | ',
		txtBreadcrumbsCrumbSeparator:	' > '
	},
	init: function() {
		merge(config.options,this.options,true);
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var area=createTiddlyElement(place,"span",null,"breadCrumbs",null);
		area.setAttribute("homeSep",params[0]||config.options.txtBreadcrumbsHomeSeparator);
		area.setAttribute("crumbSep",params[1]||config.options.txtBreadcrumbsCrumbSeparator);
		this.render(area);
	},
	add: function (title) {
		var thisCrumb = title;
		var ind = this.crumbs.indexOf(thisCrumb);
		if(ind === -1)
			this.crumbs.push(thisCrumb);
		else if (config.options.chkReorderBreadcrumbs)
			this.crumbs.push(this.crumbs.splice(ind,1)[0]); // reorder crumbs
		else
			this.crumbs=this.crumbs.slice(0,ind+1); // trim crumbs
		if (config.options.chkBreadcrumbsLimitOpenTiddlers)
			this.limitOpenTiddlers();
		this.refresh();
		return false;
	},
	getAreas: function() {
		var crumbAreas=[];
		// find all DIVs with classname=="breadCrumbs"
		var all=document.getElementsByTagName("*");
		for (var i=0; i<all.length; i++)
			try{ if (hasClass(all[i],"breadCrumbs")) crumbAreas.push(all[i]); } catch(e) {;}
		// or, find single DIV w/fixed ID (backward compatibility)
		var byID=document.getElementById("breadCrumbs")
		if (byID && !hasClass(byID,"breadCrumbs")) crumbAreas.push(byID);
		if (!crumbAreas.length && config.options.chkCreateDefaultBreadcrumbs) {
			// no crumbs display... create one
			var defaultArea = createTiddlyElement(null,"span",null,"breadCrumbs",null);
		 	defaultArea.style.display= "none";
			var targetArea= document.getElementById("tiddlerDisplay");
			if (targetArea) {
				targetArea.parentNode.insertBefore(defaultArea,targetArea);
				crumbAreas.push(defaultArea);
			}
		}
		return crumbAreas;
	},
	refresh: function() {
		var crumbAreas=this.getAreas();
		for (var i=0; i<crumbAreas.length; i++) {
			crumbAreas[i].style.display = config.options.chkShowBreadcrumbs?"block":"none";  // <-- 2021-02-09: Replaced value "inline" with "block"
			removeChildren(crumbAreas[i]);
			this.render(crumbAreas[i]);
		}
	},
	render: function(here) {
		var co=config.options; var out=""
		if (!co.chkBreadcrumbsHideHomeLink) {
			createTiddlyButton(here,"Home",null,this.home,"tiddlyLink tiddlyLinkExisting");
			out+=here.getAttribute("homeSep")||config.options.txtBreadcrumbsHomeSeparator;
		}
		for (c=0; c<this.crumbs.length; c++) // remove non-existing tiddlers from crumbs
			if (!store.tiddlerExists(this.crumbs[c]) && !store.isShadowTiddler(this.crumbs[c]))
				this.crumbs.splice(c,1);
		var count=this.crumbs.length;
		if (co.chkBreadcrumbsLimit && co.txtBreadcrumbsLimit<count) count=co.txtBreadcrumbsLimit;
		var list=[];
		for (c=this.crumbs.length-count; c<this.crumbs.length; c++) list.push('[['+this.crumbs[c]+']]');
		if (co.chkBreadcrumbsReverse) list.reverse();
		out+=list.join(here.getAttribute("crumbSep")||config.options.txtBreadcrumbsCrumbSeparator);
		wikify(out,here);
	},
	home: function() {
		var cmb=config.macros.breadcrumbs;
		if (config.options.chkBreadcrumbsSave && confirm(cmb.askMsg)) cmb.saveCrumbs();
		story.closeAllTiddlers(); restart();
		cmb.crumbs = []; var crumbAreas=cmb.getAreas();
		for (var i=0; i<crumbAreas.length; i++) crumbAreas[i].style.display = "none";
		return false;
	},
	saveCrumbs: function() {
		var tid=prompt(this.saveMsg,this.saveTitle); if (!tid||!tid.length) return; // cancelled by user
		var t=store.getTiddler(tid);
		if(t && !confirm(config.messages.overwriteWarning.format([tid]))) return;
		var who=config.options.txtUserName;
		var when=new Date();
		var text='[['+this.crumbs.join(']]\n[[')+']]';
		var tags=t?t.tags:[]; tags.pushUnique('story');
		var fields=t?t.fields:{};
		store.saveTiddler(tid,tid,text,who,when,tags,fields);
		story.displayTiddler(null,tid);
		story.refreshTiddler(tid,null,true);
		displayMessage(tid+' has been '+(t?'updated':'created'));
	},
	limitOpenTiddlers: function() {
		var limit=config.options.txtBreadcrumbsLimitOpenTiddlers; if (limit<1) limit=1;
		for (c=this.crumbs.length-1; c>=0; c--) {
			var tid=this.crumbs[c];
			var elem=story.getTiddler(tid);
			if (elem) { // tiddler is displayed
				if (limit <=0) { // display limit has been reached
					if (elem.getAttribute("dirty")=="true") { // tiddler is being edited
						var msg= "'"+tid+"' is currently being edited.\n\n"
							+"Press OK to save and close this tiddler\n"
							+"or press Cancel to leave it opened";
						if (confirm(msg)) {
							story.saveTiddler(tid);
							story.closeTiddler(tid);
						}
					}
					else story.closeTiddler(this.crumbs[c]);
				}
				limit--;
			}
		}
	}
};
//}}}
// // PreviousTiddler ('back') command and macro
//{{{
config.commands.previousTiddler = {
	text: 'back',
	tooltip: 'view the previous tiddler',
	handler: function(event,src,title) {
		var crumbs=config.macros.breadcrumbs.crumbs;
		if (crumbs.length<2) config.macros.breadcrumbs.home();
		else story.displayTiddler(story.findContainingTiddler(src),crumbs[crumbs.length-2]);
		return false;
	}
};
config.macros.previousTiddler= {
	label: 'back',
	prompt: 'view the previous tiddler',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var label=params.shift(); if (!label) label=this.label;
		var prompt=params.shift(); if (!prompt) prompt=this.prompt;
		createTiddlyButton(place,label,prompt,function(ev){
			return config.commands.previousTiddler.handler(ev,this)
		});
	}
}
//}}}
// // HIJACKS
//{{{
// update crumbs when a tiddler is displayed
if (Story.prototype.breadCrumbs_coreDisplayTiddler==undefined)
	Story.prototype.breadCrumbs_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler) {
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	this.breadCrumbs_coreDisplayTiddler.apply(this,arguments);
	if (!startingUp || config.options.chkShowStartupBreadcrumbs)
		config.macros.breadcrumbs.add(title);
}

// update crumbs when a tiddler is deleted
if (TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler==undefined)
	TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler=TiddlyWiki.prototype.removeTiddler;
TiddlyWiki.prototype.removeTiddler= function() {
	this.breadCrumbs_coreRemoveTiddler.apply(this,arguments);
	config.macros.breadcrumbs.refresh();
}
//}}}
/***
|Name|BreadcrumbsPluginInfo|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.1.5|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for BreadcrumbsPlugin|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Usage
<<<
{{{
<<breadcrumbs homeSeparator crumbSeparator>>
}}}
By default, the breadcrumbs are displayed as a continuous, //horizontal// word-wrapped line of text, using default character sequences for ''homeSeparator'' (" | ") and ''crumbSeparator'' (" > ").  The //optional// ''homeSeparator'' and ''crumbSeparator'' macro parameters allow you to specify alternative separators.  For example, to display the breadcrumbs //vertically// (in a stack, rather than a row), set the separator values to use {{{[[<br>]]}}}... and, to display a horizontal line as the home separator, use {{{[[<html><hr></html>]]}}}.
{{{
<<previousTiddler>>
}}}
This macro embeds a 'back' button in your content.  Clicking the button opens/scrolls to the most recent previously viewed tiddler.  You can also add the {{{previousTiddler}}} keyword to the ~ViewToolbar slice definition in ToolbarCommands.  This adds a 'back' button directly to the toolbar of each tiddler that is displayed.
<<<
!!!!!Examples:
<<<
{{{
<<breadcrumbs>>
}}}
<<breadcrumbs>>
{{{
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
}}}
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
<<<
!!!!!Customization
<<<
Using CSS and a few of the plugin configuration options (see below), you can make the breadcrumbs display resemble browser tabs by adding the following to your [[StyleSheet]]:
{{{
.breadCrumbs { border-bottom:1px solid; }
.breadCrumbs a {
	border: 1px solid; padding: 0px 1em;
	-moz-border-radius-topleft:.5em; -moz-border-radius-topright:.5em;
	-webkit-border-top-left-radius:.5em; -webkit-border-top-right-radius:.5em;
}
}}}
and this in [[ConfigTweaks]] (tagged with systemConfig, of course):
{{{
config.options.chkShowStartupBreadcrumbs=true;
config.options.chkBreadcrumbsLimitOpenTiddlers=true;
config.options.txtBreadcrumbsLimitOpenTiddlers=1;
config.macros.breadcrumbs.homeSeparator=" ";
config.macros.breadcrumbs.crumbSeparator=" ";
}}}
<<<
!!!!!Configuration
<<<
__''display placement:''__
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
{{{<<option chkCreateDefaultBreadcrumbs>>}}}
>By default, the plugin automatically creates the "breadCrumbs" display element at the top of the story column, just above the tiddlerDisplay area.  To manually control the display and placement of the breadcrumbs display, you can define a DIV with class="breadCrumbs" in a custom [[PageTemplate]] or embed the {{{<<breadcrumbs>>}}} macro in specific tiddler content.
>
>For example, to add the breadcrumbs below the mainMenu, change this:
{{{
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
}}}
>to:
{{{
<div id='mainMenu'>
	<div refresh='content' tiddler='MainMenu'></div>
	<div id='breadCrumbs' class='breadCrumbs'></div>
</div>
}}}
>You can also block automatic creation of the breadcrumbs display by setting
{{{
config.options.chkCreateDefaultBreadcrumbs=false;
}}}
>in a [[CookieJar]]/[[ConfigTweaks]] plugin tiddler.

__''other settings:''__
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
{{{<<option chkShowBreadcrumbs>>}}}
>This checkbox toggles the visibility of the breadcrumbs display.  However, the display is not updated until the next crumb is added (or a previous crumb is clicked on).  For immediate effect, you can use [[ToggleBreadcrumbs]] to synchronize the checkbox setting and the breadcrumbs display.
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
{{{<<option chkReorderBreadcrumbs>>}}}
>When visiting a previously viewed tiddler, the title of the most-recently displayed tiddler is simply moved to the end of the list and individual breadcrumbs are not removed from the list unless the underlying tiddler is deleted.  When ''re-ordering'' is disabled, the breadcrumbs list is ''trimmed'' so that all crumbs following that tiddler are removed from the list.
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
{{{<<option chkBreadcrumbsHideHomeLink>>}}}
>Enabling this option suppresses the automatic display of the "Home" link (and home separator).  To manually add the home link elsewhere in your document, use the following HTML:
{{{
<html><a href="javascript:;" onclick="config.macros.breadcrumbs.home()">home</a></html>
}}}
<<option chkBreadcrumbsSave>> prompt to save breadcrumbs when 'Home' link is pressed
{{{<<option chkBreadcrumbsSave>>}}}
>Whenever you press the 'home' button, you can be prompted to save the current breadcrumbs in a tiddler as a space-separated list of tiddler links (default title="SavedBreadcrumbs").  
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
{{{<<option chkShowStartupBreadcrumbs>>}}}
>Breadcrumbs are usually only added for tiddlers that are opened after the document has been loaded, and not for tiddlers displayed during initial startup (e.g., [[DefaultTiddlers]]).  Enabling this option displays breadcrumbs for all viewed tiddlers, regardless of when they are opened.
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order
{{{<<option chkBreadcrumbsReverse>>}}}
>As tiddlers are displayed, breadcrumbs are usually added to the //end// of the list.  Enabling this option displays breadcrumbs in reverse order, so that the most recently visited tiddlers are listed first.
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
{{{<<option chkBreadcrumbsLimit>>}}} and {{{<<option txtBreadcrumbsLimit>>}}}
>By default, breadcrumbs are displayed for all tiddlers that have been visited (unless the list is being 'trimmed' by disabling the chkReorderBreadcrumbs option above).  Enabling this option limits the display of the list to a maximum specified number of breadcrumbs.
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items
{{{<<option chkBreadcrumbsLimitOpenTiddlers>>}}} and {{{<<option txtBreadcrumbsLimitOpenTiddlers>>}}}
>By default, tiddlers remain open (e.g., displayed in the story column) until you explicitly close them.  When this option is enabled, only the most recently opened tiddlers will remain open: ''any tiddlers in excess of the specified limit are automatically closed.''  //Note: for 'data safety', if a tiddler is being edited, you will be asked for permission to "save-and-close" that tiddler or leave it open (even if that would exceed the specified limit).//
<<<
!!!!!Revisions
<<<
2012.06.10 2.1.5 refactored default options to eliminate global variable and use init() handling
2011.02.16 2.1.4 in refresh(), use 'inline' instead of 'block' style (avoids unwanted linebreak).  In previousTiddler(), allow handling even if not in a tiddler so that back button can be placed in ~MainMenu or ~SidebarOptions.
2010.11.30 2.1.3 use story.getTiddler()
2009.10.19 2.1.2 code reduction
2009.03.22 2.1.0 added 'save breadcrumbs to tiddler' feature
2008.05.01 2.0.0 added 'limit open tiddlers' feature (with safety check for tiddler in edit mode)
2008.04.06 1.9.1 corrected 'limit' logic so that //last// N crumbs are shown instead of //first// N crumbs.  Also, added chkBreadcrumbsHideHomeLink
2008.04.04 1.9.0 added chkBreadcrumbsReverse and chk/txtBreadcrumbsLimit
2008.03.29 1.8.4 in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.24 1.8.3 include shadow tiddlers in breadcrumbs list.  Also changed settings so that "reordering" breadcrumbs is the default, instead of "trimming" the list
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.26 1.8.2 documentation cleanup
2007.10.18 1.8.1 in GetAreas(), use try/catch to avoid "Bad NPObject as private data" fatal error caused when embedded QuickTime player element is accessed by hasClass() function.
2007.10.02 1.8.0 major documentation and code cleanup.  Moved config.breadCrumbs.* to config.macros.breadcrumbs.* to consolidate objects.  Also, fixed homeSeparator and crumbSeparator default handling.
2007.10.02 1.7.0 added config.options.chkShowStartupBreadcrumbs option
2007.09.16 1.6.1 in getAreas(), removed errant use of 'place' (was causing fatal error when creating default breadcrumbs display element).  Also, added chkCreateDefaultBreadcrumbs configuration setting to enable/disable automatic creation of a default breadcrumbs display.
2007.09.16 1.6.0 re-wrote refresh() to enable multiple display instances, by finding elements with "breadCrumbs" classname.  Fallback to fixed ID (="breadCrumbs") is still used for backward-compatibility.  move rendering code from refresh() to separate render() function, and added definition for {{{<<breadCrumbs>>}}} macro to support embedding breadcrumbs displays in tiddler content.
2007.09.15 [1.5.9.1] updated documentation
2007.09.15 1.5.9 defined homeSeparator (" | ") and crumbSeparator (" > ") as object properties so that they can be redefined as desired for different layouts (e.g., using 'newline' for the crumbSeparator will arrange crumbs in a column rather than a row.
2007.06.21 [1.5.8.1] in home(), return false to prevent IE from attempting to navigate away...
2007.05.26 1.5.8 added support for {{{<<option chkReorderBreadcrumbs>>}}} to toggle trim vs. re-order behavior when visiting previously viewed tiddlers
2007.05.25 1.5.7 added support for {{{<<option chkShowBreadcrumbs>>}}} to toggle //display// of breadcrumbs
2007.05.24 1.5.6 in refresh(), remove non-existing tiddler titles from crumb list.  Also, hijack removeTiddler() so crumbs can be updated after tiddler is deleted.
2007.04.11 1.5.5 added optional params to previousTiddler macro handler() to allow alternative label and tooltip text (instead of default "back")
2007.03.02 1.5.4 in refresh(), for TW2.2, look for "storyDisplay" instead of "tiddlerDisplay" but keep fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.02.24 1.5.3 changed from hijack of onClickTiddlerLink to hijack of displayTiddler() so that ALL displayed tiddlers are recorded in the crumbs, including programmatically displayed tiddlers opened by macros, scripts, etc., (such as [[GotoPlugin]], among many others) in addition to those opened by clicks on links.
2007.02.24 [1.5.2.0] eliminated global space clutter by moving function and data declarations so they are contained inside config.breadCrumbs object.
2007.02.06 1.5.1 added "previousTiddler" macro (for use in sidebar)
2007.02.05 1.5.0 added "previousTiddler" toolbar command (aka, "back")
2006.08.04 [1.4.0.1] change spaces to tabs
2006.08.04 1.4.0 modified from 1.4.0 distro: in refresh(), set {{{display:none/block}}} instead of {{{visibility:hidden/visible}}}.  In home(), check for valid crumbArea before setting style.
2006.08.02 1.4.0 Fixed bug, the redefined onClickTiddlerLink_orig_breadCrumbs works incorrectly on IE
2006.07.20 1.3.0 Runs compatibly with TW 2.1.0 (rev #403+)
2006.02.07 1.2.0 change global array breadCrumbs to config.breadCrumbs by Eric's suggestion
2006.02.04 1.1.0 JSLint checked
2006.02.01 1.0.0 initial release
<<<
/***
|Name|CollapseTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#CollapseTiddlersPlugin|
|Version|2.0.0//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|OriginalAuthor|Bradley Meck - http://gensoft.revhost.net/Collapse.html|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|CollapsedTemplate|
|Description|show/hide content of a tiddler while leaving tiddler title visible|
This plugin provides commands to quickly switch a rendered tiddler between its current ViewTemplate display and a minimal display (title and toolbar) defined by a separate CollapsedTemplate.
!!!Usage
<<<
In [[ToolbarCommands::ViewToolbar|ToolbarCommands]], add:
{{{
collapseTiddler collapseOthers
}}}
you can also embed the following macros in tiddler content:
*{{{<<collapseAll>>}}} - adds 'collapse all' command that applies CollapsedTemplate to each displayed tiddler
*{{{<<expandAll>>}}} - adds 'expand all' command that re-applies ViewTemplate (or equivalent custom template) to each displayed tiddler
*{{{<<foldFirst>>}}} - immediately apply CollapsedTemplate to a given tiddler, as soon as it is displayed.
<<<
!!!Revisions
<<<
2021.01.18 [2.0.0a] replaced "collapse all" with "fold all" and "expand all" with "unfold all"
2009.05.04 [2.0.0] standardized documentation and added version #
2008.10.05 collapseAll() and expandAll(): added "return false" to button handlers to prevent IE page transition
2008.03.06 refactored all code for size reduction, readability, and I18N/L10N-readiness.  Also added 'folded' flag to tiddler elements (for use by other plugins that need to know if tiddler is folded (e.g., [[SinglePageModePlugin]]
2007.10.11 moved [[FoldFirst]] inline script and converted to {{{<<foldFirst>>}}} macro
2007.12.09 suspend/resume SinglePageMode (SPM/TPM/BPM) when folding/unfolding tiddlers
2007.05.06 add "return false" at the end of each command handler to prevent IE 'page transition' problem.
2007.03.30 add a shadow definition for CollapsedTemplate.  Tweak ViewTemplate shadow so "fold/unfold" and "focus" toolbar items automatically appear when using default templates.  Remove error check for "CollapsedTemplate" existence, since shadow version will now always work as a fallback.
2006.02.24 added fallback to "CollapsedTemplate" if "WebCollapsedTemplate" is not found
2006.02.06 added check for 'readOnly' flag to use alternative "WebCollapsedTemplate"
<<<
!!!Code
***/
//{{{
version.extensions.CollapseTiddlersPlugin= {major: 2, minor: 0, revision: 0, date: new Date(2009,5,4)};

config.shadowTiddlers.CollapsedTemplate=
	"<!--{{{-->\
	<div class='toolbar' macro='toolbar expandTiddler collapseOthers closeTiddler closeOthers +editTiddler permalink references jump'></div>\
	<div class='title' macro='view title'></div>\
	<!--}}}-->";

// automatically tweak shadow ViewTemplate to add "collapseTiddler collapseOthers" commands
config.shadowTiddlers.ViewTemplate=config.shadowTiddlers.ViewTemplate.replace(/closeTiddler/,"collapseTiddler collapseOthers closeTiddler");

config.commands.collapseTiddler = {
	text: "fold",
	tooltip: "Collapse this tiddler",
	collapsedTemplate: "CollapsedTemplate",
	webCollapsedTemplate: "WebCollapsedTemplate",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		// don't fold tiddlers that are being edited!
		if(story.isDirty(e.getAttribute("tiddler"))) return false;
		var t=config.commands.collapseTiddler.getCollapsedTemplate();
		config.commands.collapseTiddler.saveTemplate(e);
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","true");
		return false;
	},
	getCollapsedTemplate: function() {
		if (readOnly&&store.tiddlerExists(this.webCollapsedTemplate))
			return this.webCollapsedTemplate;
		else
			return this.collapsedTemplate
	},
	saveTemplate: function(e) {
		if (e.getAttribute("savedTemplate")==undefined)
			e.setAttribute("savedTemplate",e.getAttribute("template"));

	},
	// fold/unfold tiddler with suspend/resume of single/top/bottom-of-page mode
	display: function(title,t) {
		var opt=config.options;
		var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
		var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
		var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
		story.displayTiddler(null,title,t);
		opt.chkBottomOfPageMode=saveBPM;
		opt.chkTopOfPageMode=saveTPM;
		opt.chkSinglePageMode=saveSPM;
	}
}

config.commands.expandTiddler = {
	text: "unfold",
	tooltip: "Expand this tiddler",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		var t = e.getAttribute("savedTemplate");
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","false");
		return false;
	}
}

config.macros.collapseAll = {
	text: "fold all",
	tooltip: "Collapse all tiddlers",
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		createTiddlyButton(place,this.text,this.tooltip,function(){
			story.forEachTiddler(function(title,tiddler){
				if(story.isDirty(title)) return;
				var t=config.commands.collapseTiddler.getCollapsedTemplate();


				config.commands.collapseTiddler.saveTemplate(tiddler);
				config.commands.collapseTiddler.display(title,t);
				tiddler.folded=true;
			});
			return false;
		})
	}
}

config.macros.expandAll = {
	text: "unfold all",
	tooltip: "Expand all tiddlers",
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		createTiddlyButton(place,this.text,this.tooltip,function(){
			story.forEachTiddler(function(title,tiddler){
				var t=config.commands.collapseTiddler.getCollapsedTemplate();
				if(tiddler.getAttribute("template")!=t) return; // re-display only if collapsed
				var t=tiddler.getAttribute("savedTemplate");
				config.commands.collapseTiddler.display(title,t);
				tiddler.folded=false;
			});
			return false;
		})
	}
}

config.commands.collapseOthers = {
	text: "focus",
	tooltip: "Expand this tiddler and collapse all others",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		story.forEachTiddler(function(title,tiddler) {
			if(story.isDirty(title)) return;
			var t=config.commands.collapseTiddler.getCollapsedTemplate();
			if (e==tiddler) t=e.getAttribute("savedTemplate");
			config.commands.collapseTiddler.saveTemplate(tiddler);
			config.commands.collapseTiddler.display(title,t);
			tiddler.folded=(e!=tiddler);
		})
		return false;
	}
}

// {{{<<foldFirst>>}}} macro forces tiddler to be folded when *initially* displayed.
// Subsequent re-render does NOT re-fold tiddler, but closing/re-opening tiddler DOES cause it to fold first again.
config.macros.foldFirst = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		var e=story.findContainingTiddler(place);
		if (e.getAttribute("foldedFirst")=="true") return; // already been folded once
		var title=e.getAttribute("tiddler")
		var t=config.commands.collapseTiddler.getCollapsedTemplate();
		config.commands.collapseTiddler.saveTemplate(e);
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","true");
		e.setAttribute("foldedFirst","true"); // only when tiddler is first rendered
		return false;
	}
}
//}}}
<!--{{{-->
<!--
|Name|CollapsedTemplate|
|Source|http://www.TiddlyTools.com/#CollapsedTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Description|alternative to ViewTemplate, used by CollapseTiddlersPlugin to display tiddler when 'folded'|
|Revision| Rewritten on 2020-12-30 by Meindert Meindertsma
-->
<div class='toolbar' macro='toolbar expandTiddler collapseOthers _closeTiddler closeOthers +editTiddler > snapshotSave permalink fields references jump'></div>
<div class='title' macro='view title'></div>
<div class='tagClear' style='margin-bottom:1.5em;'></div>
<!--}}}-->
Background: #ffffff
Foreground: #000000
~PrimaryWhitened: #e3eee2
~PrimaryPale: #ccdd66
~PrimaryFair: #c5dcc4
~PrimaryLight: #9ec49c
~PrimarySoft: #7db07a
~PrimaryBright: #5c9559
~PrimaryMid: #648c62
~PrimaryDark: #456f43
~SecondaryWhitened: #f3f3f1
~SecondaryPale: #e3e3dd
~SecondaryLight: #cbcbbf
~SecondarySoft: #aeae9c
~SecondaryMid: #929272
~SecondaryDark: #6f6f5b
~TertiaryWhitened: #f0f0f0
~TertiaryPale: #e2e2e2
~TertiaryLight: #cccccc
~TertiarySoft: #b0b0b0
~TertiaryMid: #999999
~TertiaryDark: #666666
Error: #ff6633

Display:
<<eval "|>|>|>|background-color:$1P; 1P |>|background-color:$1b; @@color:white;1B@@ |
|background-color:$1w; 1W |background-color:$1f; 1F |background-color:$1l; 1L |background-color:$1s; @@color:white;1S@@ |background-color:$1m; @@color:white;1M@@ |background-color:$1d; @@color:white;1D@@ |
|background-color:$2w; 2W |background-color:$2p; 2P |background-color:$2l; 2L |background-color:$2s; @@color:white;2S@@ |background-color:$2m; @@color:white;2M@@ |background-color:$2d; @@color:white;2D@@ |
|background-color:$3w; 3W |background-color:$3p; 3P |background-color:$3l; 3L |background-color:$3s; @@color:white;3S@@ |background-color:$3m; @@color:white;3M@@ |background-color:$3d; @@color:white;3D@@ |
|>|>|>|>|>|background-color:$e; @@color:white;E@@ |
">>
!!Vrij en gepreformatteerd
{{lf{
''Serif''
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf s{
//.s//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf{
//&.s//
XX{{s{XXX}}}
XX{{s{XXX}}}
{{u1 d1{XX{{s{X}}}}}}{{s{XX}}}
X{{u1 d1{X{{s{XX}}}}}}{{s u1 d1{X}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
}}}{{lf{
//&.s.up1px//
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px u1 d1{XXX}}}{{s up1px{XX}}}
{{s up1px{X}}}{{s up1px u1 d1{XXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
}}}{{lf{
//&.s//
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{{{u1 d1{XXX}}}XX}}}
{{s{X{{u1 d1{XXXX}}}}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
}}}{{lf{
//&.z//
XX{{z{XXX}}}
XX{{z{XXX}}}
{{u1 d1{XX{{z{X}}}}}}{{s suf{XX}}}
X{{u1 d1{X{{z{XX}}}}}}{{z u1 d1{X}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
}}}{{lf{
//&.s.suf//
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
{{u1 d1{XX{{s suf{X}}}}}}{{s suf{XX}}}
X{{u1 d1{X{{s suf{XX}}}}}}{{s suf u1 d1{X}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
}}}{{lf{
//&.s.med//
XX{{s med{XXX}}}
XX{{s med{XXX}}}
{{u1 d1{XX{{s med{X}}}}}}{{s med{XX}}}
X{{u1 d1{X{{s med{XX}}}}}}{{s med u1 d1{X}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
}}}{{lf{
//&.s.low//
XX{{s low{XXX}}}
XX{{s low{XXX}}}
{{u1 d1{XX{{s low{X}}}}}}{{s low{XX}}}
X{{u1 d1{X{{s low{XX}}}}}}{{s low u1 d1{X}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
}}}{{lf{
//&.s.low//
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{{{u1 d1{XXX}}}XX}}}
{{s low{X{{u1 d1{XXXX}}}}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
}}}{{lf{
//...&//{{saco{''1.67em''}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;{{u1 d1{XXX}}}XX@@}}}
{{s low{@@line-height:1.67em;X{{u1 d1{XXXX}}}@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
}}}{{lf pref b1 d1 r scroll tt{
''Mono''
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref suf b1 d1 r scroll tt{
//.suf//
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref med b1 d1 r scroll tt{
//.med//
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{ib pref w20pct low b1 d1 r scroll tt{
//.low//
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}
{{block clear{}}}
{{sans{{{lf{
''Sans''
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf s{
//.s//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf{
//&.s//
XX{{s{XXX}}}
XX{{s{XXX}}}
{{u1 d1{XX{{s{X}}}}}}{{s{XX}}}
X{{u1 d1{X{{s{XX}}}}}}{{s u1 d1{X}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
XX{{s{XXX}}}
}}}{{lf{
//&.s.up1px//
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px u1 d1{XXX}}}{{s up1px{XX}}}
{{s up1px{X}}}{{s up1px u1 d1{XXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
{{s up1px{XXXXX}}}
}}}{{lf{
//&.s//
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{{{u1 d1{XXX}}}XX}}}
{{s{X{{u1 d1{XXXX}}}}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
{{s{XXXXX}}}
}}}{{lf{
//&.z//
XX{{z{XXX}}}
XX{{z{XXX}}}
{{u1 d1{XX{{z{X}}}}}}{{s suf{XX}}}
X{{u1 d1{X{{z{XX}}}}}}{{z u1 d1{X}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
XX{{z{XXX}}}
}}}{{lf{
//&.s.suf//
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
{{u1 d1{XX{{s suf{X}}}}}}{{s suf{XX}}}
X{{u1 d1{X{{s suf{XX}}}}}}{{s suf u1 d1{X}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
XX{{s suf{XXX}}}
}}}{{lf{
//&.s.med//
XX{{s med{XXX}}}
XX{{s med{XXX}}}
{{u1 d1{XX{{s med{X}}}}}}{{s med{XX}}}
X{{u1 d1{X{{s med{XX}}}}}}{{s med u1 d1{X}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
XX{{s med{XXX}}}
}}}{{lf{
//&.s.low//
XX{{s low{XXX}}}
XX{{s low{XXX}}}
{{u1 d1{XX{{s low{X}}}}}}{{s low{XX}}}
X{{u1 d1{X{{s low{XX}}}}}}{{s low u1 d1{X}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
XX{{s low{XXX}}}
}}}{{lf{
//&.s.low//
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{{{u1 d1{XXX}}}XX}}}
{{s low{X{{u1 d1{XXXX}}}}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
{{s low{XXXXX}}}
}}}{{lf{
//...&//{{saco{''1.67em''}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;{{u1 d1{XXX}}}XX@@}}}
{{s low{@@line-height:1.67em;X{{u1 d1{XXXX}}}@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
{{s low{@@line-height:1.67em;XXXXX@@}}}
}}}}}}
{{clear{

!!Gepreformatteerd
}}}{{lf pref ws b1 d1 r scroll tt{
''Mono''
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref ws suf b1 d1 r scroll tt{
//.suf//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref ws med b1 d1 r scroll tt{
//.med//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref ws low b1 d1 r scroll tt{
//.low//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref ws b1 d1 r scroll tt s{
//.s//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref ws suf b1 d1 r scroll tt s{
//.s.suf//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref ws med b1 d1 r scroll tt s{
//.s.med//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pref ws low b1 d1 r scroll tt s{
//.s.low//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf pre1{
//.pre1//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{ib pre1 low{
//.pre1.low//
XXXXX
XXXXX
{{u1 d1{XXX}}}XX
X{{u1 d1{XXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}
<<eval [=[|col1 bold1 thick1 even |k
|!Taal      |!Einderegel-<br>commentaar |!Universeel<br>blokcommentaar |!Regelgebonden<br>blokcommentaar |!Pseudo-<br>blokcommentaar |!Zonder meer<br>nestbaar |!Voorwaardelijk<br>nestbaar |
|ALGOL 60   |                           |{{hitt2{__comment__ $___ ;}}} |                                 |                      |         |         |
|bash       |{{hitt2{# $___}}}          |                              |   |{{block low hitt2{: """<<"""HERE<br>$___<br>HERE}}} |         | &times; |
|Basic      |{{hitt2{REM $___}}}<br>{{hitt2{' $___}}}  |               |                                 |                      |         |         |
|batch file |{{hitt2{REM $___}}}<br>{{hitt2{:: $___}}} |               |       |{{block low hitt2{GOTO HERE<br>$___<br>:HERE}}} |         | &times; |
|C          |{{hitt2{"""//""" $___}}}   |{{hitt2{/* $___ */}}}         |                                 |                      |         |         |
|Go         |{{hitt2{"""//""" $___}}}   |{{hitt2{/* $___ */}}}         |                                 |                      |         |         |
|Java       |{{hitt2{"""//""" $___}}}   |{{hitt2{/* $___ */}}}         |                                 |                      |         |         |
|JavaScript |{{hitt2{"""//""" $___}}}   |{{hitt2{/* $___ */}}}         |                                 |                      |         |         |
|Julia      |{{hitt2{# $___}}}          |{{hitt2{#= $___ =#}}}         |                                 |                      | &times; |         |
|Lua        |{{hitt2{"""--""" $___}}}   |{{hitt2{"""--[[""" $___ ]]}}} |                                 |                      |         | &times; |
|Nim        |{{hitt2{# $___}}}          |{{hitt2{#[ $___ ]#}}}         |                                 |                      | &times; |         |
|Pascal     |{{hitt2{"""//""" $___}}}   |{{hitt2{{ $___ """}"""}}}<br>{{hitt2{(* $___ *)}}} |            |                      | &times; |         |
|PCL        |{{hitt2{! $___}}}          |                              |                                 |                      |         |         |
|Perl       |{{hitt2{# $___}}}          |                              |{{block low hitt2 {=pod<br> $___<br>=cut}}}   |         |         |         |
|PowerShell |{{hitt2{# $___}}}          |{{hitt2{<# $___ #>}}}         |                                 |                      |         |         |
|Python     |{{hitt2{# $___}}}          |   | |{{hitt2{<html>"""</html> $___ <html>"""</html>}}}<br>{{hitt2{"""'''""" $___ """'''"""}}} | | &times; |
|Rebol      |{{hitt2{; $___}}}          |                   | |{{hitt2{comment { $___ """}"""}}}<br>{{hitt2{comment [ $___ ]}}} | &times; |         |
|Rexx       |{{hitt2{"""--""" $___}}}   |{{hitt2{/* $___ */}}}         |                                 |                      | &times; |         |
|Ruby       |{{hitt2{# $___}}}          |                              |{{block low hitt2 {=begin<br> $___<br>=end}}} |         |         |         |
|Scala      |{{hitt2{"""//""" $___}}}   |{{hitt2{/* $___ */}}}         |                                 |                      | &times; |         |
|Scheme     |{{hitt2{; $___}}}          |{{hitt2{"""#|""" $___ """|#"""}}} |                             |                      | &times; |         |
!!Bijzonderheden
; ALGOL 60
: Dit commentaar heeft de vorm van een statement en kan inderdaad alleen maar op plaatsen staan waar een statement zou kunnen staan.
; bash
: {{_{Blokcommentaar kan worden geëmuleerd m.b.v. een een- of meerregelige //here string//. Het begin ervan wordt aangegeven met de {{tt t{"""<<"""}}}-operator gevolgd door een woord dat het einde van de string moet aangeven. Traditioneel kiest men daar het woord {{tt t{HERE}}} voor (vandaar de stringtypeaanduiding), maar iets anders mag ook. Zulk commentaar kan worden genest, mits men maar de juiste maatregelen neemt. Bijvoorbeeld:
{{pre{
""": <<"""THERE
$___
""": <<"""HERE
$___
HERE
$___
THERE
}}}/%
%/In Perl en Ruby kan zo'n constructie -- met weglating van de dubbele punt aan het begin van het commentaar -- eveneens worden toegepast, al heb ik die daar voor commentaar&shy;doeleinden nooit toegepast gezien.}}}
; (DOS/Windows) batch file
: {{_{{{tt t{REM}}} en {{tt t{::}}} zijn niet werkelijk //einde//regel&shy;commentaar. In beide gevallen hebben we te maken met //hele//regel&shy;commentaar, dat moet beginnen met {{tt t{REM}}} of {{tt t{::}}} en hooguit mag worden voorafgegaan door spaties of iets dergelijks. Tussen beide vormen zit wel enig verschil. Het ge{{tt t{REM}}}de commentaar kan namelijk worden ge{{tt t{ECHO}}}od en bij {{tt t{::}}} gebeurt dat nooit.
Wat het blokcommentaar betreft: door over een aantal regels heen te springen (via {{tt t{IF}}} of {{tt t{GOTO}}}) fungeren die regels in feite als commentaar. Ze worden dan niet geïnterpreteerd.
[[Simon Sheppard|https://ss64.com/nt/rem.html]] beschrijft nog wat meer haken en ogen.}}}
; C
: In C++ en C# gaat het er net zo aan toe. Vóór C99 voorzag C niet in einderegel&shy;commentaar.
; Lua
: {{_{Verschillende blokcommentaren kunnen van elkaar worden onderscheiden door isgelijk&shy;tekens tussen de teksthaken te plaatsen: {{pref hitt2 z{"""--\[=\[""" $___ \]=\]}}}, {{pref hitt2 z{"""--[==[""" $___ ]==]}}} enzovoort. De bakens met gelijk aantal isgelijk&shy;tekens horen bij elkaar. Op die manier kunnen ze worden genest. Hetzelfde foefje kan overigens worden uitgehaald met meerregelige {{sc{string}}} literals  {{pref hitt2 z{"""[[""" $___ ]]}}}.
[[Terra]], waarvan de syntaxis op Lua is gebaseerd, volgt dezelfde patronen voor commentaar en string literals.}}}
; Pascal
: Turbo Pascal kende vroeger nog geen einderegel&shy;commentaar. [[Free Pascal|https://www.freepascal.org/]] nu wel.
; PCL
: Hier is niet HP's [[Printer Control Language|https://en.wikipedia.org/wiki/Printer_Command_Language]] bedoeld, doch Wolfgang Lilienfeld's [[Personal Computer Language]].
; Perl
: {{_{(Dit betreft [[Perl 5|Perl]], niet te verwarren met [[Perl 6|https://nl.wikipedia.org/wiki/Perl_6]], dat uiteindelijk [[Raku|https://raku.org/]] is gaan heten, met als enige of belangrijkste implementatie [[Rakudo Perl|https://www.rakudo.org/]].)
Het blokcommentaar is bedoeld voor Pod, het 'Plain Old Documentation format' dat met {{tt t{perldoc}}} kan worden geëxtraheerd.}}}
; Python
: {{_{Het blokcommentaar is niets anders dan een (een- of meerregelige) string literal in een zogeheten //expression statement//. Het kan dus alleen worden geplaatst waar in Python een statement mag staan. Wanneer het met drie aaneensluitende dubbele aanhalingstekens is afgebakend, kunnen erbinnen vrijelijk drie aaneensluitende enkelvoudige aanhalingstekens worden gebruikt, en omgekeerd.
Ook in veel andere talen is de Python-truc toe te passen. Bij adequate commentaar­voorzieningen ter plekke is dat meestal een nogal overbodig middel.}}}
;Rebol
: {{_{Het blokcommentaar is weliswaar echt commentaar (eh... nee, zelfs dat niet, kom ik straks op terug), maar mag toch niet zomaar overal worden geplaatst. Deels doet de situatie denken aan die van ALGOL 60-commentaar. Zo leidt {{pref hitt2 z{antwoord: comment {ja, je zag 'm al aankomen:} 42}}} tot de foutmelding {{sans{"Script Error: antwoord needs a value"}}}, omdat er gepoogd wordt //niets// i.p.v. {{tt t{42}}} aan de variabele {{tt t{antwoord}}} toe te wijzen. Er schemert hier misschien al een beetje door dat er meer aan de hand is.
Anders dan het einderegel&shy;commentaar blijft het //een onderdeel van de code die in runtime wordt geëvalueerd//. Dat levert uiteindelijk aanwezigheid zonder waarde op. De uitdrukking achter {{pref hitt z{comment}}} moet een {{sc{string}}} literal of een {{sc{block}}} zijn. Mijn ervaring is dat een {{sc{word}}} of een {{sc{paren}}} dat een willekeurige waarde oplevert ook is toegestaan. Als het maar niet niets is ({{tt t{none}}} is een waarde van het type {{tt t{none!}}}, dus {{pref hitt2 z{comment none}}} is oké). Het commentaar {{pref hitt2 z{comment pi}}} kan als zodanig door de beugel, maar bij {{pref hitt2 z{comment tau}}} kreeg ik de melding {{sans{"Script Error: tau needs a value"}}}. Ik had {{tt t{[[tau|π, de halve waarheid]]}}} niet gedefinieerd, terwijl de variabele {{tt t{pi}}} In Rebol was voorgedefinieerd als {{tt t{3.14159265358979}}}. Bij {{pref hitt2 z{comment ()}}} luidde de boodschap {{sans{"Script Error: comment is missing its value argument"}}}. Met {{pref hitt2 z{comment reduce [print "Kom erbij zitten, beste kerel!" "(Ik houd je in de gaten, gluiperd!)"]}}} heeft Rebol geen enkele moeite en voorwaar: er wordt een joviale uitnodiging afgedrukt zonder dat de achterliggende gedachte tot de buitenwereld doordringt. Erg zinvol zijn zulke capriolen natuurlijk niet, dus met het eventuele daarop volgende geweeklaag van Rebol valt wel te leven. Maar pas op je woorden.}}}
; Rexx
: Oorspronkelijk kende Rexx geen einderegel­commentaar. Modernere implementaties hebben in de lacune voorzien.
; Scheme
: Er is nog een derde commentaarvorm, het //datum comment//, dat kan worden gebruikt om een gegevenseenheid uit te commentariëren. {{pref hitt2 z{'(1 #;2 3)}}} resulteert in de list {{tt t{(1 3)}}}.
/%

%/Zie ook [[Wikipedia: Comparison of programming languages (syntax)|https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(syntax)]].]=] f2m>>
Comprehensions vormen een minitaaltje binnen Python. Helaas zit er een foutje in de syntaxbeschrijving in de documentatie van Python 3.11 (&sect; 6.2.4. "Displays for lists, sets and dictionaries"). Hieronder een verbetering en een vereenvoudigde formulering:
<<eval [=[{{pre{
//comprehension// $--> //assignmtExpr// //compFor// //compIter//$0
//assignmtExpr//  $--> $(Identifier '':=''$)$0 Expression
//compFor//       $--> ''async''$0 ''for'' TargetList ''in'' Iterable
//compIter//      $--> $(//compFor// $| //compIf//$) $___
//compIf//        $--> ''if'' Expression
}}}]=] f2m>>/%

%/De iteratievariabelen in {{sans{TargetList}}} zijn buiten de comprehension niet toegankelijk. Toepassingen:
<<eval [=[{{pre{
//listComp//      $--> ''[''//comprehension//'']''
//dictComp//      $--> ''{''//assignmtExpr//'':'' //assignmtExpr// //compFor// //compIter//$0''}''    $// {{serif{//see remarks below//}}}
//setComp//       $--> ''{''//comprehension//''}''
//generatorExpr// $--> ''(''//comprehension//'')''
}}}]=] f2m>>/%

%/In een dictionary comprehension moet iedere //{{sans{assignmtExpr}}}// die werkelijk een toekenning bevat tussen haakjes worden gezet. Bij de andere comprehensions is dat niet nodig:
<<eval [=[{{pre{
''[x := i*i for i in range(0, 5)]''              $=> [0, 1, 4, 9, 16]
''{(y := i): (x := i*i) for i in range(0, 5)}''  $=> {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
''{x := i*i for i in range(0, 5)}''              $=> {0, 1, 4, 9, 16}
''(x := i*i for i in range(0, 5))''              $=> <generator object <genexpr> at 0x.....>
}}}]=] f2m>>/%

%/De variabelen {{tt t{x}}} en {{tt t{y}}} zijn, anders dan {{tt t{i}}}, wèl met hun uiteindelijke waarden ({{tt t{16}}} resp. {{tt t{4}}}) buiten de comprehension beschikbaar. Tot besluit geef ik hier ook nog maar de corresponderende voorbeelden van comprehensions zonder zulke toekenningen, wat veel gebruikelijker is:
<<eval [=[{{pre{
''[i*i for i in range(0, 5)]''     $=> [0, 1, 4, 9, 16]
''{i: i*i for i in range(0, 5)}''  $=> {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
''{i*i for i in range(0, 5)}''     $=> {0, 1, 4, 9, 16}
''(i*i for i in range(0, 5))''     $=> <generator object <genexpr> at 0x.....>
}}}]=] f2m>>/%
The two most common [[file compressors|Ingepakt op Linux, uit te pakken op Windows]] in the Un*x world are ''{{{gzip}}}'' and ''{{{bzip2}}}''. But ''{{{xz}}}'' is an interesting third one, because it reduces the file size even further (https://tukaani.org/xz/ claims typically 30% smaller output than {{{gzip}}} and 15% smaller output than {{{bzip2}}}). They are all [[integrated in tar|Archiving with tar]], and their own command-line interfaces are almost the same:
<html><pre>
<font color="darkorange"><i>{</i></font><b>gzip</b><font color="darkorange"><i>|</i></font><b>bzip2</b><font color="darkorange"><i>|</i></font><b>xz</b><font color="darkorange"><i>} «filespecs»</i></font>        <font color="green"><i># compress, adding compressiontype suffix to filename(s)</i></font>
<font color="darkorange"><i>{</i></font><b>gunzip</b><font color="darkorange"><i>|</i></font><b>bunzip2</b><font color="darkorange"><i>|</i></font><b>unxz</b><font color="darkorange"><i>} «filespecs»</i></font>  <font color="green"><i># decompress, removing compressiontype suffix from filename(s)</i></font>
<font color="darkorange"><i>{</i></font><b>zcat</b><font color="darkorange"><i>|</i></font><b>bzcat</b><font color="darkorange"><i>|</i></font><b>xzcat</b><font color="darkorange"><i>} «filespecs»</i></font>     <font color="green"><i># write decompressed output to STDOUT</i></font>
</pre></html>/%

%/The options you'll probably use most frequently are:
|!                                                             |bgcolor(black): !{{tt{gzip}}}              |bgcolor(black): !{{tt{bzip2}}}                |bgcolor(black): !{{tt{xz}}}            |
|bgcolor(#eec):Write some help information to STDOUT           | ''{{{-h}}}''                              | ''{{{-h}}}''                                 | ''{{{-h}}}''                          |
|bgcolor(#eec):Compress (default)                              | ''{{{-z}}}''                              | ''{{{-z}}}''                                 | ''{{{-z}}}''                          |
|bgcolor(#eec):Decompress                                      | ''{{{-d}}}''                              | ''{{{-d}}}''                                 | ''{{{-d}}}''                          |
|bgcolor(#eec):Test compressed file integrity                  | ''{{{-t}}}''                              | ''{{{-t}}}''                                 | ''{{{-t}}}''                          |
|bgcolor(#eec):List compressed file information to STDOUT      | ''{{{-l}}}''                              |                                              | ''{{{-l}}}''                          |
|bgcolor(#eec):Keep (don't delete) input files                 |                                           | ''{{{-k}}}''                                 | ''{{{-k}}}''                          |
|bgcolor(#eec):Force overwrite of output files and compress links | ''{{{-f}}}''                           | ''{{{-f}}}''                                 | ''{{{-f}}}''                          |
|bgcolor(#eec):Write to STDOUT and don't delete input files    | ''{{{-c}}}''                              | ''{{{-c}}}''                                 | ''{{{-c}}}''                          |
|bgcolor(#eec):Be verbose                                      | ''{{{-v}}}''                              | ''{{{-v}}}''                                 | ''{{{-v}}}''                          |
|bgcolor(#eec):Optimal speed &rarr; optimal compression | ''{{{-1}}}'' @@color(darkorange):&rarr; ''{{{-9}}}''@@ | ''{{{-1}}}'' @@color(darkorange):&rarr;@@ ''{{{-9}}}'' | ''{{{-0}}}'' @@color(darkorange):&rarr;@@ ''{{{-9}}}'' |
|bgcolor(#eec):Default compression degree                      | 6                                         | 9                                            | 6      |
|!                                                             |bgcolor(black): !{{tt{gunzip}}}            |bgcolor(black): !{{tt{bunzip2}}}              |bgcolor(black): !{{tt{unxz}}}          |
|bgcolor(#eec):Alternative                                     | ''{{{gzip -d}}}''                         | ''{{{bzip2 -d}}}''                           | ''{{{xz -d}}}''                       |
|!                                                             |bgcolor(black): !{{tt{zcat}}}              |bgcolor(black): !{{tt{bzcat}}}                |bgcolor(black): !{{tt{xzcat}}}         |
|bgcolor(#eec):Alternatives | &nbsp;''{{{gunzip -c}}}''&nbsp;<br>''{{{gzip -dc}}}'' | &nbsp;''{{{bunzip2 -c}}}''&nbsp;<br>''{{{bzip2 -dc}}}'' | &nbsp;''{{{unxz -c}}}''&nbsp;<br>''{{{xz -dc}}}'' |
|!                                                             |bgcolor(black): !Output                    |bgcolor(black): !Output                       |bgcolor(black): !Output                |
|bgcolor(#eec):Filename extension added after compression      | ''{{{.gz}}}''                             | ''{{{.bz2}}}''                               | ''{{{.xz}}}''                         |
|bgcolor(#eec):Size after 6th-degree compression               | 7.1%                                      | 5.3%                                         | 3.9%                                  |
|bgcolor(#eec):Size after 9th-degree compression               | 6.6%                                      | 5.2%                                         | 3.8%                                  |
The resulting sizes given here are the outcome of experiments with just one (!) 1.5 GB not-compressed SAS table. I have also tested a 34 GB one, which gave really smashing reductions (shrinked to 1.44% of its original size by {{{gzip}}} and even to 0.21% by {{{xz}}}, both with option ''{{{-6}}}''). As a matter of fact, it is bad practice to create such not-compressed SAS tables. SAS itself offers instant compression options when outputting observations to a table, and they should be applied conscientiously when size could be an issue. SAS can read the tables compressed by itself on the fly, so it doesn't complicate the I/O processes.

The installed {{{xz}}} version in our SAS BI environment being a bit out of date, not everything works as expected. The ''{{{-l}}}'' option is not implemented yet in this version, and the [[integration with tar|Archiving with tar]] is somewhat incomplete.
The syntax of the ''{{{man}}}'' command goes like:
<html><pre>
<b>man</b> <i>[«options»] [«section»] [«title» ...]</i>
</pre></html>/%

%/In order to create an HTML page, first get an overview of the available manpages about the required subject:
<html><pre>
<b>man -aW</b> <i>[«section»] «title»</i>
</pre></html>/%

%/This will print a list of manpage files, each in the format {{high2{{{tt{//«dir»//''/''//«title»//''.''//«section»//''.gz''}}}}}}. Then convert the one you want to convert by the command:
<html><pre>
<b>zcat</b> <i>«dir»</i><b>/</b><i>«title»</i><b>.</b><i>«section»</i><b>.gz</b> | man2html ></b> <i>[«output-dir»</i><b>/</b><i>]«title»</i><b>.</b><i>«section»</i><b>.html</b>
</pre></html>
[[Steve Morton|http://marc.info/?l=sas-l&m=116622598350376&w=2]] heeft in 1993 een macro {{{SASXDB2}}} geschreven, waarvan de naam moet worden gelezen als 'SAS {{stix{&#x27d5;}}} ~DB2', oftewel 'left join van een ~SAS-tabel met een ~DB2-tabel'. Functioneel bekeken heeft de macro niet veel te betekenen, maar als het om performance gaat des te meer. Zoals hij zelf zegt:
<<<
Use to extract small numbers of rows from a large DB2 table by matching with a SAS dataset containing key values. This macro is more efficient than simply merging in a PROC SQL step, as the value-matching is done by DB2, which may take advantage of indices on the table, rather than having all DB2 data come to the SAS job to be 'screened' by the where condition.
<<<
De truc is dat de ~DB2-tabel eerst binnen de ~DB2-omgeving wordt gereduceerd tot de rijen die zouden voldoen aan het joincriterium. Deze rijen worden opgeslagen in een tijdelijke ~SAS-tabel, welke uiteindelijk alsnog op klassieke wijze wordt gejoind met de te verrijken ~SAS-tabel. Dat blijkt inderdaad een hoop tijd te schelen.

Ik vond de uitwerking van het op zich simpele maar evengoed slimme idee destijds toch net complex genoeg om enige toelichting te rechtvaardigen. Hieronder is de informatieprecedentie weergegeven van het opvraagproces zoals dat door de macro wordt gegenereerd. Dit betreft niet de oorspronkelijke macro van Morton, maar een latere versie die ik toen tot mijn beschikking had. Het principe wordt echter ook zo wel duidelijk.

[img[IPD SASXDB2|data/images/SAS/IPD SASXDB2.png]]/%
%/
!!!De parameters van de macro
<html><pre>
%macro sasxdb2(
         db2ssid  = db2,            <font color=darkorange>/* => <b><i>«db2»</i></b>                                         */</font>
         sastable = sasdata.table,  <font color=darkorange>/* => <b><i>«sastable»</i></b>                                    */</font>
         sas_mcol = acct_no,        <font color=darkorange>/* => <b><i>«sas-mcol»</i></b>                                    */</font>
         db2table = db2data.table,  <font color=darkorange>/* => <b><i>«db2table»</i></b>                                    */</font>
         db2_mcol = acct_no,        <font color=darkorange>/* => <b><i>«db2-mcol»</i></b>                                    */</font>
         select   = *,              <font color=darkorange>/* => <b><i>«select»</i></b>                                      */</font>
         matchtyp = NUM,            <font color=darkorange>/* => quote the values in <b><i>«value-list»</i></b> or not (<b>NUM</b>) */</font>
         output   = sasxdb2,        <font color=darkorange>/* => <b><i>«output»</i></b>                                      */</font>
         db2where = ,               <font color=darkorange>/* => <b><i>«db2where»</i></b>                                    */</font>
         distinct = Y               <font color=darkorange>/* => remove duplicate rows (<b>Y</b>) or not              */</font>
       );
</pre></html>/%

%/In mijn beschrijvingen gebruik ik de oranje symbolen om de variabele delen van het gegenereerde opvraagproces aan te geven. In sommige gevallen zijn ze exact gelijk aan een macrovariabele (@@color(darkorange):''//«db2»//''@@ = {{{&db2ssid}}}), in andere gevallen zijn ze een bewerking ervan (zo zijn er in @@color(darkorange):''//«select»//''@@ komma's tussen de items van {{{&select}}} geplaatst), en @@color(darkorange):''//«value-list»//''@@ is een kommagescheiden opsomming van alle in stap 1 verzamelde waarden, tussen enkele aanhalingstekens gezet ingeval {{{&matchtyp}}} &ne; ''{{{NUM}}}'' (hoofdletterongevoelig)./%

%/
!!!Stap 1
<html><pre>
proc sort data = <u><font color=darkorange><b><i>«sastable»</i></b></font></u> ( keep  = <font color=darkorange><b><i>«sas-mcol»</i></b></font>
                              where = (<font color=darkorange><b><i>«sas-mcol»</i></b></font> ne <font color=darkorange><i>{</i></font>.<font color=darkorange><i>|</i></font>''<font color=darkorange><i>}</i></font>)
                            )
          out  = <u>Temp9999</u>
          nodupkey
          ;
  by <font color=darkorange><b><i>«sas-mcol»</i></b></font>;
run;
</pre></html>/%

%/De eerste stap verzamelt alle non-missing numerieke waarden of niet-lege character waarden die voorkomen in de kolom @@color(darkorange):''//«sas_mcol»//''@@ van @@color(darkorange):''//«sastable»//''@@, en zet ze -- onder verwijdering van duplicaten -- in oplopende volgorde. /%

%/
!!!Stap 2
<html><pre>
proc sql;
  connect to db2 (ssid=<font color=darkorange><b><i>«db2»</i></b></font>);
  create table <u>Temp9999</u> (index=(qqqq9999)) as
    select *
      from connection to db2 (
        select <font color=darkorange><b><i>«db2-mcol»</i></b></font> as qqqq9999,
               <font color=darkorange><b><i>«select»</i></b></font>
          from <u><font color=darkorange><b><i>«db2table»</i></b></font></u> a
          where <font color=darkorange><i>[</i><b><i>«db2where»</i></b></font> and<font color=darkorange><i>]</i></font>
                <font color=darkorange><b><i>«db2-mcol»</i></b></font> in (<font color=darkorange><b><i>«value-list»</i></b></font>)
          order by qqqq9999
      );
quit;
%put &sqlxmsg;
</pre></html>/%

%/Via bovenstaande query worden alleen die rijen uit @@color(darkorange):''//«db2table»//''@@ geselecteerd die voldoen aan het joincriterium (en aan @@color(darkorange):''//«db2where»//''@@, als dit bij de aanroep als parameter was meegegeven)./%

%/
!!!Stap 3
~SQL-statements mogen niet te lang worden. De macro borgt dit door maximaal 100 regels van 80 posities beschikbaar te stellen voor de opsomming van waarden in @@color(darkorange):''//«value-list»//''@@. Wanneer het niet past, wordt het restant in onderstaande query ondergebracht.
<html><pre>
proc sql;
  insert into <u>Temp9999</u>
    select *
      from connection to db2 (
        select <font color=darkorange><b><i>«db2-mcol»</i></b></font> as qqqq9999,
               <font color=darkorange><b><i>«select»</i></b></font>
          from <u><font color=darkorange><b><i>«db2table»</i></b></font></u> a
          where <font color=darkorange><i>[</i><b><i>«db2where»</i></b></font> and<font color=darkorange><i>]</i></font>
                <font color=darkorange><b><i>«db2-mcol»</i></b></font> in (<font color=darkorange><b><i>«value-list»</i></b></font>)
          order by qqqq9999
      );
quit;
%put &sqlxmsg;
</pre></html>/%

%/Er worden net zo lang queries van dit type gegenereerd totdat alle verzamelde waarden uit @@color(darkorange):''//«sastable»//''@@ in een ~WHERE-clausule zijn opgenomen./%

%/
!!!Stap 4
Deze query wordt alleen gegenereerd indien {{{&distinct}}} = ''{{{Y}}}'' (hoofdletterongevoelig):
<html><pre>
proc sql;
  create table <u>Temp9999</u> as
    select distinct *
      from <u>Temp9999</u>
    ;
quit;
</pre></html>/%

%/Omdat de doeltabel dezelfde is als de brontabel, geeft SAS een warning. Op ~AV2 leidt dit ertoe dat het programma met condition code ''{{{4}}}'' eindigt./%

%/
!!!Stap 5
De uiteindelijke left join, die nu zeer veel sneller tot stand komt dan wanneer de oorspronkelijke @@color(darkorange):''//«db2table»//''@@ in zijn geheel aan de rechterkant had gestaan:
<html><pre>
proc sql;
  create table <u><font color=darkorange><b><i>«output»</i></b></font></u> (drop=qqqq9999) as
    select *
      from <u><font color=darkorange><b><i>«sastable»</i></b></font></u> a
           left join <u>Temp9999</u> b
           on a.<font color=darkorange><b><i>«sas-mcol»</i></b></font> = b.qqqq9999
    ;
quit;
</pre></html>
<html><big><big><i>Als de baby niet huilt en trappelt,<br>
dan is ze gelukkig.</i></big></big></html>

Bovenstaande uitspraak in natuurlijke taal heb ik aangetroffen in een bespreking van de propositielogica.{{ref{[[[1]|##1]]}}} De auteurs komen tot drie verschillende grammaticale lezingen, in een [[meer formele taal|Tweewaardige propositielogica]] uitgedrukt:

&nbsp;&nbsp;&nbsp;1.&nbsp;&nbsp; &not;(//huilt// {{stix{&and;}}} //trappelt//) &rarr; //gelukkig//
&nbsp;&nbsp;&nbsp;2.&nbsp;&nbsp; (&not;//huilt// &and; //trappelt//) &rarr; //gelukkig//
&nbsp;&nbsp;&nbsp;3.&nbsp;&nbsp; (&not;//huilt// &and; &not;//trappelt//) &rarr; //gelukkig//

Op semantisch vlak zou ik bovendien een andere interpretatie van 'als … dan' niet willen uitsluiten:

&nbsp;&nbsp;&nbsp;4.&nbsp;&nbsp; &not;(//huilt// &and; //trappelt//) &harr; //gelukkig//
&nbsp;&nbsp;&nbsp;5.&nbsp;&nbsp; (&not;//huilt// &and; //trappelt//) &harr; //gelukkig//
&nbsp;&nbsp;&nbsp;6.&nbsp;&nbsp; (&not;//huilt// &and; &not;//trappelt//) &harr; //gelukkig//

Dat zijn al zes mogelijke betekenissen van één simpel zinnetje. En daarmee zijn de mogelijkheden nog niet eens uitgeput. Ik heb nu dus beweerd dat 'Als //p// dan //q//' kan worden opgevat als //p// &rarr; //q// en tevens als //p// &harr; //q//. Maar soms leidt de inhoud van //p// en //q// tot nog andere interpretaties. Ik heb de proef op de som genomen bij mensen die er niet voor hebben doorgeleerd. Bij de uitspraken 'Als de aarde vierkant is, dan is de maan een driehoek' en 'Als de aarde vierkant is, dan is de maan rond' voelden zij zich erg ongemakkelijk, en kwamen ze uiteindelijk tot conclusies die er feitelijk op neerkomen dat de constructie 'Als //p// dan //q//' hetzelfde is als //p// &and; //q//. Als weer anderen in zo'n situatie misschien op eenvoudigweg //q// uitkomen (alleen het gedeelte achter 'dan' bepaalt of de zin waar is of onwaar), dan zou dat me ook niet eens meer verbazen. Eh... wat beweer ik nu eigenlijk precies in die vorige zin?

Eindstand: negen of misschien zelfs twaalf betekenissen als het volk mag meebeslissen. Verdorie, nou doe ik het wéér!

----
|plain |k
|<html><a name="1">[1]</a></html>|<<tiddler Bibliografie##Benthem>> |
[[Hoe verder gekomen, hoe langer te gaan]]
!!!!Dan Ingalls in [[BYTE Magazine vol. 6, no. 8, August 1981 (Smalltalk special issue)|https://archive.org/details/byte-magazine-1981-08]], p. 286&ndash;298
# ''Personal mastery''<br>If a system is to serve the creative spirit, it must be entirely comprehensible to a single individual.
# ''Good design''<br>A system should be built with a minimum set of unchangeable parts; those parts should be as general as possible; and all parts of the system should be held in a uniform framework.
# ''Purpose of language''<br>To provide a framework for communication.
# ''Scope''<br>The design of a language for using computers must deal with internal models, external media, and the interaction between these in both the human and the computer.
# ''Objects''<br>A computer language should support the concept of "object" and provide a uniform means for referring to the objects in its universe.
# ''Storage management''<br>To be truly "object-oriented", a computer system must provide automatic storage management.
# ''Messages''<br>Computing should be viewed as an intrinsic capability of objects that can be uniformly invoked by sending messages.
# ''Uniform metaphor''<br>A language should be designed around a powerful metaphor that can be uniformly applied in all areas.
# ''Modularity''<br>No component in a complex system should depend on the internal details of any other component.
# ''Classification''<br>A language must provide a means for classifying similar objects, and for adding new classes of objects on equal footing with the kernel classes of the system.
# ''Polymorphism''<br>A program should specify only the behavior of objects, not their representation.
# ''Factoring''<br>Each independent component in a system should appear in only one place.
# ''Leverage''<br>When a system is well factored, great leverage is available to users and implementers alike.
# ''Virtual machine''<br>A virtual machine specification establishes a framework for the application of technology.
# ''Reactive principle''<br>Every component accessible to the user should be able to present itself in a meaningful way for observation and manipulation.
# ''Operating system''<br>An operating system is a collection of things that don 't fit into a language. There shouldn't be one.
# ''Natural selection''<br>Languages and systems that are of sound design will persist, to be supplanted only by better ones.
[[Alloy|http://alloy.mit.edu/alloy/]] is een modelleringstaal voor software. Die taal is tekstueel, maar er is omwille van het comfort wel enige visualisatie aan toegevoegd. "A //model diagram// declares some sets and binary relations, and imposes some basic constraints on them", aldus [[[1]|##1]]. Zelfs voor ternaire relaties heeft Alloy nog wel een oplossing, al is die voor de toevallige voorbijganger niet triviaal meer. Maar in het algemeen is de notatie erg eenvoudig, zowel voor de lezer als voor de maker.

In een diagram worden leestekens gebruikt in plaats van de Alloy-keywords voor multipliciteiten:
|!Symbool     |!Betekenis  |!Keyword             |!Opmerking |
| ''{{{*}}}'' |nul of meer |&nbsp;''{{{set}}}''  |default, symbool wordt in de regel weggelaten |
| ''{{{+}}}'' |één of meer |&nbsp;''{{{some}}}'' |           |
| ''{{{?}}}'' |nul of één  |&nbsp;''{{{lone}}}'' |           |
| ''{{{!}}}'' |exact één   |&nbsp;''{{{one}}}''  |           |

Sets (entiteiten, klassen) en subsets worden in Alloy aldus weergegeven:

&nbsp; &nbsp;[img[Set boxes and subset relationships, with their correponding Alloy text|data/images/Alloy-1.png]]

Het subtiele verschil tussen ''{{{extends}}}'' (voor subtype) en ''{{{in}}}'' (voor deelverzameling) is buiten Alloy niet zo relevant. Relaties worden op onderstaande wijze verbeeld. ''{{{R}}}'' is hierin de relatienaam, en op de plaats van //m// en //n// kunnen bovengenoemde multipliciteitssymbolen (in het diagram) of -keywords (in de tekst) worden ingevuld:

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;[img[Relation arcs and their correponding Alloy text|data/images/Alloy-2.png]]

Tot besluit enkele voorbeelden:

&nbsp; &nbsp; &nbsp;[img[Textual models and corresponding model diagrams|data/images/Alloy-3.png]]

Alloy maakt geen principieel onderscheid tussen //type// (het model waarnaar een element gevormd kan zijn) en //set// (de verzameling elementen van hetzelfde type), en evenmin tussen //set// en //individuele elementen//. In het onderste schema is te zien hoe elk van de drie kleuren van een stoplicht als een singleton set oftewel scalar is gedefinieerd. Een set van één element is krek hetzelfde als dat element zelf.

----
|plain |k
|<html><a name="1">[1]</a></html>|<<tiddler Bibliografie##Jackson>> |
Bij het ontwerpen van gebruikersinterfaces zal men vaak beginnen met pen en papier, of marker en whiteboard, liefst in combinatie met een smartphone om de resultaten vast te leggen. Omdat ik [anno 2014] nog geen smartphone heb, heb ik afgelopen kerstvakantie eens voor de aardigheid gespeeld met een pc-applicatie die specifiek is toegesneden op het ontwerpen van GUI's. Met dergelijke ontwerp&shy;gereedschap zou je drie soorten producten kunnen maken:/%
%/
*//wireframes// -- schetsen van schermstructuur en -componenten, focust op de functionaliteit van de schermen
*//mockups// -- focust op de esthetiek van de schermen
*//prototypes// -- weergave van de proceslogica/%
%/
Voor dit experiment had ik de open-source applicatie [[Pencil|http://pencil.evolus.vn/]] uitgekozen, omdat die niets kostte en ik verwachtte dat de leercurve erg vlak zou zijn. De ondersteuning voor prototypes is in Pencil wat magertjes. Je kunt hyperlinks tussen de scherm&shy;ontwerpen (wireframes / mockups) aanleggen en er is de mogelijkheid om diagrammen te tekenen, maar een fysieke verbinding tussen een scherm&shy;verloop&shy;diagram en de scherm&shy;ontwerpen zelf is niet te leggen.{{ref{[[[1]|##1]]}}} Ik heb het daarom maar gelaten bij wireframes ('draadmodellen') voor een [['Kennisgeving van wijziging'|data/webpages/Pencil/index.html]], gebaseerd op formulier nr. 30 uit //Het Formulieren&shy;boek//.{{ref{[[[2]|##2]]}}} De 'Verder' en 'Terug' knoppen in deze simulatie en ook de hyperlinks doen het echt, maar behalve navigeren tussen de scherm&shy;formulieren kun je verder alleen maar naar de scherm&shy;inhoud kijken.

Het 'schetsen' van de vier schermen viel me een beetje tegen. Niet omdat Pencil zo onhandig werkte, maar omdat ik onwillekeurig toch te veel met de lay-out bezig was. Ik voel meer, althans om mee te beginnen, voor zoiets als de 'user interface diagrammen' die Sander Hoogendoorn in //Pragmatisch modelleren met UML 2.0//{{ref{&#x2009;[[[3]|##3]]}}} beschrijft. Dit zijn een soort van stroom&shy;diagrammen waarin per scherm met minimale middelen is aangegeven wat erin staat. Om een idee te geven, uitgaande van onderstaande use case:

[img[Use case|data/images/Hoogendoorn/Use case.png]]

schetst hij dit schermverloop (zo te zien biedt deze user interface wel een onsje meer dan de use case impliceert):

[img[UI-diagram met frame|data/images/Hoogendoorn/UI-diagram met frame.png]]

waarin het frame 'Aanvragen abonnement' in een apart diagram is uitgewerkt:

[img[UI-diagram in frame|data/images/Hoogendoorn/UI-diagram in frame.png]]

De zwarte stip is het beginpunt van de dialoog, en de stip met een cirkel eromheen het eindpunt. Getrokken pijlen zijn scherm&shy;overgangen met terugkeer aan het eind van de interactie, en onderbroken pijlen overgangen zonder terugkeer. Een grafische weergave van een //form// (schermformulier) bevat alleen maar een enkelvoudige business objects (binnen&shy;blokjes met naam), lijsten van business objects (binnen&shy;blokjes met naam en rechts een smal verticaal compartiment) en de mogelijkheid een zoekprofiel op te stellen (binnen&shy;blokjes zonder naam). Verdere uitwerking van deze forms&shy;componenten kan op niet-grafische wijze worden beschreven.

Het kan natuurlijk nòg eenvoudiger (onderstaand diagram is met Pencil vervaardigd -- ging niet echt lekker):

[img[Vereenvoudigd UI-diagram|data/images/Hoogendoorn/Vereenvoudigd UI-diagram.png]]

Het gaat er niet alleen om hoe te ontwerpen, maar ook hoe het eindresultaat zodanig te beschrijven dat anderen (beheerders, toekomstige ontwerpers en programmeurs) snel kunnen begrijpen hoe de dialoog in elkaar steekt.

----
|plain |k
|<html><a name="1">[1]</a></html>|Dit betrof Pencil 2.0.5, ik schreef dit verslag begin 2014. Op 1 januari 2023 is versie 3.1.1 uitgebracht. Die zal ongetwijfeld meer en betere faciliteiten bieden. |
|<html><a name="2">[2]</a></html>|<<tiddler Bibliografie##Hegener>> |
|<html><a name="3">[3]</a></html>|<<tiddler Bibliografie##Hoogendoorn>> |
/***
|Name|DisableWikiLinksPlugin|
|Source|http://www.TiddlyTools.com/#DisableWikiLinksPlugin|
|Version|1.6.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|selectively disable TiddlyWiki's automatic ~WikiWord linking behavior|
This plugin allows you to disable TiddlyWiki's automatic ~WikiWord linking behavior, so that WikiWords embedded in tiddler content will be rendered as regular text, instead of being automatically converted to tiddler links.  To create a tiddler link when automatic linking is disabled, you must enclose the link text within {{{[[...]]}}}.
!!!!!Usage
<<<
You can block automatic WikiWord linking behavior for any specific tiddler by ''tagging it with<<tag excludeWikiWords>>'' (see configuration below) or, check a plugin option to disable automatic WikiWord links to non-existing tiddler titles, while still linking WikiWords that correspond to existing tiddlers titles or shadow tiddler titles.  You can also block specific selected WikiWords from being automatically linked by listing them in [[DisableWikiLinksList]] (see configuration below), separated by whitespace.  This tiddler is optional and, when present, causes the listed words to always be excluded, even if automatic linking of other WikiWords is being permitted.  

Note: WikiWords contained in default ''shadow'' tiddlers will be automatically linked unless you select an additional checkbox option lets you disable these automatic links as well, though this is not recommended, since it can make it more difficult to access some TiddlyWiki standard default content (such as AdvancedOptions or SideBarTabs)
<<<
!!!!!Configuration
<<<
<<option chkDisableWikiLinks>> Disable ALL automatic WikiWord tiddler links
<<option chkAllowLinksFromShadowTiddlers>> ... except for WikiWords //contained in// shadow tiddlers
<<option chkDisableNonExistingWikiLinks>> Disable automatic WikiWord links for non-existing tiddlers
Disable automatic WikiWord links for words listed in: <<option txtDisableWikiLinksList>>
Disable automatic WikiWord links for tiddlers tagged with: <<option txtDisableWikiLinksTag>>
<<<
!!!!!Revisions
<<<
2008.07.22 [1.6.0] hijack tiddler changed() method to filter disabled wiki words from internal links[] array (so they won't appear in the missing tiddlers list)
2007.06.09 [1.5.0] added configurable txtDisableWikiLinksTag (default value: "excludeWikiWords") to allows selective disabling of automatic WikiWord links for any tiddler tagged with that value.
2006.12.31 [1.4.0] in formatter, test for chkDisableNonExistingWikiLinks
2006.12.09 [1.3.0] in formatter, test for excluded wiki words specified in DisableWikiLinksList
2006.12.09 [1.2.2] fix logic in autoLinkWikiWords() (was allowing links TO shadow tiddlers, even when chkDisableWikiLinks is TRUE).  
2006.12.09 [1.2.1] revised logic for handling links in shadow content
2006.12.08 [1.2.0] added hijack of Tiddler.prototype.autoLinkWikiWords so regular (non-bracketed) WikiWords won't be added to the missing list
2006.05.24 [1.1.0] added option to NOT bypass automatic wikiword links when displaying default shadow content (default is to auto-link shadow content)
2006.02.05 [1.0.1] wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.09 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.DisableWikiLinksPlugin= {major: 1, minor: 6, revision: 0, date: new Date(2008,7,22)};

if (config.options.chkDisableNonExistingWikiLinks==undefined) config.options.chkDisableNonExistingWikiLinks= false;
if (config.options.chkDisableWikiLinks==undefined) config.options.chkDisableWikiLinks=false;
if (config.options.txtDisableWikiLinksList==undefined) config.options.txtDisableWikiLinksList="DisableWikiLinksList";
if (config.options.chkAllowLinksFromShadowTiddlers==undefined) config.options.chkAllowLinksFromShadowTiddlers=true;
if (config.options.txtDisableWikiLinksTag==undefined) config.options.txtDisableWikiLinksTag="excludeWikiWords";

// find the formatter for wikiLink and replace handler with 'pass-thru' rendering
initDisableWikiLinksFormatter();
function initDisableWikiLinksFormatter() {
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="wikiLink"; i++);
	config.formatters[i].coreHandler=config.formatters[i].handler;
	config.formatters[i].handler=function(w) {
		// supress any leading "~" (if present)
		var skip=(w.matchText.substr(0,1)==config.textPrimitives.unWikiLink)?1:0;
		var title=w.matchText.substr(skip);
		var exists=store.tiddlerExists(title);
		var inShadow=w.tiddler && store.isShadowTiddler(w.tiddler.title);
		// check for excluded Tiddler
		if (w.tiddler && w.tiddler.isTagged(config.options.txtDisableWikiLinksTag))
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
		// check for specific excluded wiki words
		var t=store.getTiddlerText(config.options.txtDisableWikiLinksList);
		if (t && t.length && t.indexOf(w.matchText)!=-1)
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
		// if not disabling links from shadows (default setting)
		if (config.options.chkAllowLinksFromShadowTiddlers && inShadow)
			return this.coreHandler(w);
		// check for non-existing non-shadow tiddler
		if (config.options.chkDisableNonExistingWikiLinks && !exists)
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
		// if not enabled, just do standard WikiWord link formatting
		if (!config.options.chkDisableWikiLinks)
			return this.coreHandler(w);
		// just return text without linking
		w.outputText(w.output,w.matchStart+skip,w.nextMatch)
	}
}

Tiddler.prototype.coreAutoLinkWikiWords = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function()
{
	// if all automatic links are not disabled, just return results from core function
	if (!config.options.chkDisableWikiLinks)
		return this.coreAutoLinkWikiWords.apply(this,arguments);
	return false;
}

Tiddler.prototype.disableWikiLinks_changed = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
	this.disableWikiLinks_changed.apply(this,arguments);
	// remove excluded wiki words from links array
	var t=store.getTiddlerText(config.options.txtDisableWikiLinksList,"").readBracketedList();
	if (t.length) for (var i=0; i<t.length; i++)
		if (this.links.contains(t[i]))
			this.links.splice(this.links.indexOf(t[i]),1);
};
//}}}
<<tiddler [[{}::togglesliders]]>> The characters of the Unicode blocks //Box Drawing//, //Block Elements// and //Geometric Shapes// can be used for drawing boxes and other graphic work. This TiddlyWiki supports their application by some [[macros|ExtraMacros]] and fonts. The macros {{tt t{draw}}} and {{tt t{eval}}} convert all occurrences of {{pref hitt{''@''//xx//}}} -- with //xx// being two hexadecimal digits in lower case -- in their first argument to {{hitt{''&#x25''//xx//'';''}}}. The resulting (sub)strings can be classified by one or more class names as a second argument. The following classes represent monospace fonts with proper metrics:
* {{mono t{mono}}} and {{mono1 t{mono1}}} behave like 12pt {{tt t{tt}}} with a smaller line height (the standard monospace class {{tt t{tt}}} doesn't measure out 12pt by itself).
* {{mono0 t{mono0}}}, {{mono2 t{mono2}}} and {{mono3 t{mono3}}} behave like 12pt {{tt t{tt}}} with a bigger line height than the previous two monos.
* All widths and heights of {{monoz t{monoz}}}, {{mono0z t{mono0z}}}, {{mono1z t{mono1z}}}, {{mono2z t{mono2z}}} and {{mono3z t{mono3z}}} are 90 percent of their z-less counterparts.
In the example below, the syntax diagram is drawn by {{pref hitt z{''"""<<"""draw [=[''{{serif{......}}}'']=] "mono1z f1s"""">>"""''}}}. I've wrapped this macro call, together with the word 'program' above it, into a {{tt t{monoz}}} division, and that one in turn into a {{tt t{pre}}} division.
{{ib pre{
{{monoz{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{up1px{@b6}}}

      {{up1px{@b6}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] "mono1z f1s">>}}}}}}/%

%/{{lift{{{up{+++(~TwmlDrawInfo_MoreExamples)!!![More examples &darr;|show][More examples &uarr;|hide]
Class {{tt t{tt}}} with an incidental {{mono1{mono1}}} / {{mono2{mono2}}}:
{{lf pre{
{{_{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{w{{{mono1{@b6}}}}}}
      {{w{{{mono1{@b6}}}}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10 mono1{{{up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] f1s>>}}}}}}/%

%/{{ib pre{
{{_{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{w{{{mono2 dn1px{@b6}}}}}}
      {{w{{{mono2 dn1px{@b6}}}}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10 mono2{{{up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] f1s>>}}}}}}/%

%/
Class {{mono t{mono}}} with an incidental {{mono1{mono1}}} / {{mono2{mono2}}}:
{{lf pre{
{{mono{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{w{{{mono1 up1px{@b6}}}}}}
      {{w{{{mono1 up1px{@b6}}}}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{mono1 up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] f1s>>}}}}}}/%

%/{{ib pre{
{{mono{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{w{{{mono2 dn1px{@b6}}}}}}
      {{w{{{mono2 dn1px{@b6}}}}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{mono2 up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] f1s>>}}}}}}/%

%/
Class {{monoz t{monoz}}} with an incidental {{mono1z{mono1z}}} / {{mono2z{mono2z}}}:
{{lf pre{
{{monoz{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{w{{{mono1z up1px{@b6}}}}}}
      {{w{{{mono1z up1px{@b6}}}}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{mono1z up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] f1s>>}}}}}}/%

%/{{ib pre{
{{monoz{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{w{{{mono2z dn1px{@b6}}}}}}
      {{w{{{mono2z dn1px{@b6}}}}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{mono2z up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] f1s>>}}}}}}/%

%/
Class {{monoz t{monoz}}} with all box characters in {{mono1z{mono1z}}} / {{mono2z{mono2z}}}:
{{lf pre{
{{monoz{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{up1px{@b6}}}
      {{up1px{@b6}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] "mono1z f1s">>}}}}}}/%

%/{{ib pre{
{{monoz{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{dn1px{@b6}}}
      {{dn1px{@b6}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] "mono2z f1s">>}}}}}}/%

%/
Class {{monoz t{monoz}}} with all box characters in {{mono3z{mono3z}}}:
{{ib pre{
{{monoz{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{dn1px{@b6}}}
      {{dn1px{@b6}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] "mono3z f1s">>}}}}}}
===}}}}}}/%

%/{{lift{+++(~TwmlDrawInfo_OpenField100)![In the open field 100% &darr;|show][In the open field 100% &uarr;|hide]
{{tt{"""----+----1----+----2""" tt IBM Plex Mono}}}

{{pref mono{
"""----+----1----+----2""" mono  12pt    IBM Plex Mono
{{mono1{"""----+----1----+----2""" mono1 11.95pt DejaVu Sans Mono
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono1
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> -- end of mono1}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono1 by macro {{mono{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono1 f1s">> mono1 by macro {{mono{''draw''}}} -- end of mono
}}}/%

%/
{{mono0{
"""----+----1----+----2""" mono0 12pt IBM Plex Mono
{{mono2{"""----+----1----+----2""" mono2 12pt Source Code Pro
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono2
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> -- end of mono2}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono2 by macro {{mono0{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono2 f1s">> mono2 by macro {{mono0{''draw''}}} -- end of mono0
}}}/%

%/
{{mono0{
"""----+----1----+----2""" mono0 12pt IBM Plex Mono
{{mono3{"""----+----1----+----2""" mono3 12pt Source Code Pro Light
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono3
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> -- end of mono3}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono3 by macro {{mono{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono3 f1s">>  mono3 by macro {{mono0{''draw''}}} -- end of mono0
}}}
===}}}/%

%/+++(~TwmlDrawInfo_OpenField90)![In the open field 90% &darr;|show][In the open field 90% &uarr;|hide]
{{tt z{"""----+----1----+----2""" tt z IBM Plex Mono}}}

{{pref monoz{
"""----+----1----+----2""" monoz  10.8pt   IBM Plex Mono
{{mono1z{"""----+----1----+----2""" mono1z 10.755pt DejaVu Sans Mono
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono1z
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> -- end of mono1z}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono1z by macro {{monoz{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono1z f1s">> mono1z by macro {{monoz{''draw''}}} -- end of monoz
}}}/%

%/
{{mono0z{
"""----+----1----+----2""" mono0z 10.8pt IBM Plex Mono
{{mono2z{"""----+----1----+----2""" mono2z 10.8pt Source Code Pro
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono2z
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> -- end of mono2z}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono2z by macro {{mono0z{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono2z f1s">> mono2z by macro {{mono0z{''draw''}}} -- end of mono0z
}}}/%

%/
{{mono0z{
"""----+----1----+----2""" mono0z 10.8pt IBM Plex Mono
{{mono3z{"""----+----1----+----2""" mono3z 10.8pt Source Code Pro Light
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono3z
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> -- end of mono3z}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono3z by macro {{mono0z{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono3z f1s">>  mono3z by macro {{mono0z{''draw''}}} -- end of mono0z
}}}
===/%

%/+++(~TwmlDrawInfo_OpenFieldTrees)![Trees in the open field &darr;|show][Trees in the open field &uarr;|hide]
<<divlf 20% [=[<<draw [=[Classes {{tt t{mono}}} &  {{tt t{mono1}}}:

{{up pref mono{
''alpha''
  @1c@00@00''bravo''
  @02    @1c@00@00''charlie''
  @02    @70@00@00''delta''
  @1c@00@00''echo''
  @70@00@00''foxtrot''
]=\] "mono1 fred">\>]=]>><<divlf 20% [=[<<draw [=[Classes {{tt t{mono0}}} & {{tt t{mono2}}}:

{{up pref mono0{
''alpha''
  @1c@00@00''bravo''
  @02    @1c@00@00''charlie''
  @02    @70@00@00''delta''
  @1c@00@00''echo''
  @70@00@00''foxtrot''
]=\] "mono2 fred">\>]=]>>{{ib{<<draw [=[Classes {{tt t{mono0}}} & {{tt t{mono3}}}:

{{up pref mono0{
''alpha''
  @1c@00@00''bravo''
  @02    @1c@00@00''charlie''
  @02    @70@00@00''delta''
  @1c@00@00''echo''
  @70@00@00''foxtrot''
]=] "mono3 fred">>}}}{{clear block{}}}
<<divlf 20% [=[<<draw [=[{{z{Classes {{tt t{monoz}}} &  {{tt t{mono1z}}}:}}}

{{up pref monoz{
''alpha''
  @1c@00@00''bravo''
  @02    @1c@00@00''charlie''
  @02    @70@00@00''delta''
  @1c@00@00''echo''
  @70@00@00''foxtrot''
]=\] "mono1z fred">\>]=]>><<divlf 20% [=[<<draw [=[{{z{Classes {{tt t{mono0z}}} & {{tt t{mono2z}}}:}}}

{{up pref mono0z{
''alpha''
  @1c@00@00''bravo''
  @02    @1c@00@00''charlie''
  @02    @70@00@00''delta''
  @1c@00@00''echo''
  @70@00@00''foxtrot''
]=\] "mono2z fred">\>]=]>>{{ib{<<draw [=[{{z{Classes {{tt t{mono0z}}} & {{tt t{mono3z}}}:}}}

{{up pref mono0z{
''alpha''
  @1c@00@00''bravo''
  @02    @1c@00@00''charlie''
  @02    @70@00@00''delta''
  @1c@00@00''echo''
  @70@00@00''foxtrot''
]=] "mono3z fred">>}}}{{clear block{}}}/%
%/
<<divlf 40% [=[<<draw [=[Sequence with multiplicities
in {{tt t{mono0}}} & {{tt t{mono2}}}:

{{up pref mono0{
''alpha''
  {{zi10{{{dn{{{hdn{v}}}}}}}}}@1c@00@cb{{zi10{<}}}@00{{hws{//bravo//}}}     {{serif tight f2d{-- //zero or more//}}}
  @1c@00{{zi10{+<}}}@00@00{{hws{//charlie//}}}   {{serif tight f2d{-- //one or more//}}}
  @1c@00@cb{{zi10{+}}}@00{{hws{''delta''}}}     {{serif tight f2d{-- //optional//}}}
  @70@00@00{{zi10{+}}}@00{{hws{''echo''}}}      {{serif tight f2d{-- //mandatory//}}}
}}}]=\] mono2>\>]=]>><<div [=[<<draw [=[Structure with decision (alternatives) and fork (concurrency)
in {{tt t{mono0}}} & {{tt t{mono2}}}:

{{up pref mono0{
''alpha''
 {{www zi10{{{dn1px mono1 h3{&#x25ca;}}}}}}  @00@00@00{{hws{''bravo''}}}         {{serif tight f2d{-- //first alternative//}}}
  @70@00@00@00{{hws{''charlie''}}}       {{serif tight f2d{-- //second alternative//}}}
       {{www zi10{{{dn1px mono1 h3{○}}}}}} @1c@00@00@00{{hws{''delta''}}}
        @70@00@00@00{{hws{''echo''}}}  {{zi10 serif h1 f2m{@@position:relative;top:-0.6em;"""}"""@@}}}  {{serif f2d{@@position:relative;top:-0.8em;-- //concurrent parts of 2nd alternative//@@}}}
}}}]=\] mono2>\>]=]>>
===/%

%/+++(~TwmlDrawInfo_Pre)![Within class pre division &darr;|show][Within class pre division &uarr;|hide]
Class {{tt t{pre//«n»//}}} includes properties of class {{tt t{pretts//«n»//}}}, which includes properties of {{tt t{tt}}} (font family), {{tt t{s}}} (font size: 0.9em) and {{tt t{med}}} (line height: 1.3em).
{{{
----+----1----+----2 tt by code division
}}}
{{pre{
"""----+----1----+----2""" tt by pre division
{{z{"""----+----1----+----2""" z}}}
}}}/%

%/{{pre mono1{
"""----+----1----+----2""" mono1 by pre division
{{z{"""----+----1----+----2""" z}}}
{{tt{"""----+----1----+----2""" tt in pre division
{{z{"""----+----1----+----2""" z}}}}}}
{{mono1{"""----+----1----+----2""" mono1 in pre division
{{z{"""----+----1----+----2""" z}}}}}}
{{mono1z{"""----+----1----+----2""" mono1z in pre division
{{z{"""----+----1----+----2""" z}}}}}}
}}}/%

%/{{pre{
"""----+----1----+----2""" tt by pre division
{{monoz{
"""----+----1----+----2""" monoz in pre division
{{mono1z{"""----+----1----+----2""" mono1z nested
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono1z
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> mono1z to eol}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono1z by macro {{monoz{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono1z fred">> mono1z by macro {{monoz{''draw''}}} - back to monoz}}}}}}/%

%/{{pre{
"""----+----1----+----2""" tt by pre division
{{mono0z{
"""----+----1----+----2""" mono0z in pre division
{{mono2z{"""----+----1----+----2""" mono2z nested
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono2z
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> mono2z to eol}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono2z by macro {{mono0z{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono2z fred">> mono2z by macro {{mono0z{''draw''}}} - back to mono0z}}}}}}/%

%/{{pre{
"""----+----1----+----2""" tt by pre division
{{mono0z{
"""----+----1----+----2""" mono0z in pre division
{{mono3z{"""----+----1----+----2""" mono3z nested
<<eval [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono3z
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=]>> mono3z to eol}}}
<<draw [=[@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02 mono3z by macro {{mono0z{''draw''}}}
@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02@02]=] "mono3z fred">> mono3z by macro {{mono0z{''draw''}}} - back to mono0z}}}}}}
Don't try to set the error level this way:
{{{
set ERRORLEVEL=1
}}}
It would only set the environment variable, not the error level itself. The latter can be set by:
{{{
cmd /c exit 2
}}}
The difference is illustrated in this little batch file:
{{{
@echo off
set ERRORLEVEL=1
echo %ERRORLEVEL%
if errorlevel 1 echo One!
cmd /c exit 2
echo %ERRORLEVEL%
if errorlevel 1 if not errorlevel 2 echo One!
if errorlevel 2 echo Two!
set ERRORLEVEL=
echo %ERRORLEVEL%
}}}
As you can see from its output, the{{{ %ERRORLEVEL% }}}falls back to the error level if and only if the ERRORLEVEL variable is //not// definied:
{{{
1
1
Two!
2
}}}
The WSH interpreter{{{ CScript.exe }}}is somewhat reluctant in returning any exit code but ''0'' (zero). The script below
{{{
Dim i
i = 1 / 0
WScript.Quit Err.Number
}}}
dies with //Microsoft ~VBScript runtime error: Division by zero// before the statement''{{{ WScript.Quit Err.Number }}}''is reached, and the DOS error level returned is ''0''. Luckily this can be cured. Force the interpreter to perform the {{{Quit()}}} operation under all circumstances, which can be accomplished in an elegant way by making use of the OOP facilities of ~VBScript. Three solutions are given here. They all exploit at least one of these behavioral traits of ~VBScript:
# a runtime error within an event handler only terminates that event handler, not the entire script;
# the handler of a {{{Terminate}}} event is always (well, //almost// always) executed./%
%/
!!!Solution #1
{{{
Dim giExitCode, goMain
giExitCode = 0
Set goMain = New Main
Set goMain = Nothing
WScript.Quit giExitCode

Class Main
  Private Sub Class_Initialize
    Dim i
    i = 1 / 0
  End Sub

  Private Sub Class_Terminate
    giExitCode = Err.Number
  End Sub
End Class
}}}
The event handler (aka //event procedure//) {{{Class_Terminate}}} is guaranteed to be called, even if your script gets bogged down during the {{{Class_Initialize}}} event. Now you'll get the expected error level ''11''. If the assignment''{{{ Set goMain = Nothing }}}''is omitted, the {{{Terminate}}} event will be triggered by {{{WScript.Quit()}}}, so it's safe to leave it out. This solution can be simplified according to the next two solutions./%
%/
!!!Solution #2
{{{
Dim goMain
Set goMain = New Main
Set goMain = Nothing

Class Main
  Private Sub Class_Initialize
    Dim i
    i = 1 / 0
  End Sub

  Private Sub Class_Terminate
    WScript.Quit Err.Number
  End Sub
End Class
}}}
This model looks less vulnerable, because the {{{Quit()}}} operation is enclosed in {{{goMain.Class_Terminate}}} and therefore always to be executed, even if any other code after the initialization of {{{goMain}}} and before the finalization of {{{goMain}}} terminates the script prematurely due to an error.

But I've been faced with some odd behavior when the {{{goMain}}} object contains another object -- let's say an object instantiated by a {{{goMain.Class_Initialize}}} statement''{{{ Set moInner = New Inner }}}''-- with its own {{{Class_Terminate}}} definition. If {{{goMain.Class_Terminate}}} does not terminate this inner object explicitly by''{{{ Set moInner = Nothing }}}''before the {{{Quit()}}} operation, {{{moInner.Class_Terminate}}} is never called. The omission of the third line''{{{ Set goMain = Nothing }}}''gives error 0x80004005 saying //(null): Unspecified error// and pointing to the line number of the first statement of the inner object's {{{Class_Terminate}}} procedure, whether the inner object is terminated by {{{goMain.Class_Terminate}}} or not. The script always returns the desired exit code, so I do not think these flaws do any harm. And yet the quitting of a script by a {{{Terminate}}} event handler gives me an uneasy feeling./%
%/
!!!Solution #3
{{{
Dim goMain
Set goMain = New Main
Set goMain = Nothing
WScript.Quit Err.Number

Class Main
  Private Sub Class_Initialize
    Dim i
    i = 1 / 0
  End Sub
End Class
}}}
We really don't need a handler for the {{{Terminate}}} event. And since there is no {{{goMain.Class_Terminate}}} (that might try to quit the script by itself), we may drop''{{{ Set goMain = Nothing }}}''insouciantly. But the only code that is allowed to fail, must be placed inside of {{{goMain.Class_Initialize}}}, in order to guarantee the execution of the {{{Quit()}}} operation./%
%/
!!!Further prospects
Both event handlers together open doors to improvement of error handling by building [[Try...Catch...Finally block|Try...Catch...Finally block in VBScript]] structures.

(Based on http://my.opera.com/Lee_Harvey/blog/2007/06/03/returning-an-errorlevel-from-wsh-vbscripts)
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]] previewTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<div class='editor' macro='preview hide text'></div>
<!--}}}-->
Toen ik ALGOL leerde, werd me de vuistregel voorgehouden dat je nooit de combinatie ''{{hitt{then if}}}'' mag schrijven. Dit is niet zomaar een extra regeltje om dubbel&shy;zinnig&shy;heden te voorkomen, maar ligt diep in de syntaxis van de taal verankerd. Hieronder heb ik het desbetreffende gedeelte uitgelicht.{{ref{[[[1]|##01]]}}} De omkaderde non&shy;terminals in het rechterlid van de productieregels leiden naar het punt waar je moet concluderen dat na ''{{hitt{then}}}'' geen onverpakt //{{sans fblu{ifStmt}}}// kan worden geplaatst.

<<eval [=[{{ml2em mr1em pref tt fblu{
//statement//          $--> //unconditionalStmt//
                    $| {{hws u2d d2d r{//conditionalStmt//}}}
                    $| //forStmt//
//unconditionalStmt//  $--> //basicStmt//
                    $| //compoundStmt//
                    $| //block//
//basicStmt//          $--> //unlabeledBasicStmt//
                    $| //label// ''{{fbla{:}}}'' //basicStmt//
//unlabeledBasicStmt// $--> //assignmentStmt//
                    $| //gotoStmt//
                    $| //dummyStmt//
                    $| //procedureStmt//
//compoundStmt//       $--> //unlabeledCompound//
                    $| //label// ''{{fbla{:}}}'' //compoundStmt//
//unlabeledCompound//  $--> ''{{fbla{begin}}}'' //compoundTail//
//compoundTail//       $--> //statement// ''{{fbla{end}}}''
                    $| //statement// ''{{fbla{;}}}'' //compoundTail//
//conditionalStmt//    $--> {{hws u2d d2d r{//ifStmt//}}}
                    $| {{hws u2d d2d r{//ifStmt//}}} ''{{fbla{else}}}'' //statement//
                    $| //ifClause// //forStmt//
                    $| //label// ''{{fbla{:}}}'' //conditionalStmt//
//ifStmt//             $--> {{hws u2d d2d r{//ifClause//}}} {{hws u2d d2d r{//unconditionalStmt//}}}
//ifClause//           $--> ''{{fbla{if}}}'' //booleanExpr// ''{{fbla{then}}}''
}}}
Op deze manier kan er nooit verwarring ontstaan aan welk //{{sans fblu{ifStmt}}}// de {{tt t{else}}}-clausule gekoppeld is, een in sommige andere programmeertalen voorkomend fenomeen dat [['dangling else'|The dangling else]] wordt genoemd.

Waarschijnlijk omwille van de orthogonaliteit is de opeenvolging ''{{hitt{then if}}}'' ook in conditional //expressions//{{ref{&#x200a;[[[2]|##02]]}}} syntactisch geblokkeerd, al zou zoiets wegens de verplichte aanwezigheid van een {{tt t{else}}}-tak nooit tot ambigue constructies kunnen leiden.{{ref{[[[3]|##03]]}}}]=]>>

----
|plain |k
|<html><a name="01">[1]</a></html> |Zie de paragrafen 4.1.1 en 4.5.1 van <<tiddler Bibliografie##Algol-60>> De metataal die in dit rapport is toegepast voor het formeel definiëren van de grammatica is [[Backus-Naur Form]] (BNF) gaan heten. Daar zijn vele varianten op ontstaan, waar bovenstaande notatie van eigen makelij die ik [[Welsh Rarebit]] (WR) heb genoemd er een van is. In de oorspronkelijke BNF worden de eerste en de laatste productieregel geschreven als:<br><br>{{ml2em ib up{{{up{<<eval "$<statement$> :&#x200a;:&#x200a;= $<unconditional statement$>$|@$<conditional statement$>$|@$<for statement$><br>$<if clause$> :&#x200a;:&#x200a;= ''if'' $<Boolean expression$> ''then''">>}}}}}} |
|<html><a name="02">[2]</a></html> |Zoals het rechterlid van het assignment statement ''{{hitt z{anwer := if completed then 42 else 0}}}''. |
|<html><a name="03">[3]</a></html> |Zie de paragrafen [[3.3.1|Vertaling van een knipsel uit 'Revised Report on the algorithmic language ALGOL 60']], 3.4.1 en 3.5.1 van het rapport. |
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Opmerkingen bij [[Zichtbaarheid van Python-variabelen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Zichtbaarheid van Python-variabelen]] label: "Bundel ↘">>}}}''

Bij mijn onderzoek van de [[zichtbaarheid van classattributen|Zichtbaarheid van classattributen in Python]] maakte ik gebruik van de functie {{tt t{inspect.getclosurevars}}}. De uitkomsten daarvan waren in eerste instantie nogal verwarrend. Om beter te begrijpen wat ik aan deze functie had, heb ik er wat proeven mee gedaan. Sindsdien weet ik in elk geval dat ik -- voor een zo schoon mogelijke rapportage -- gekwalificeerde namen (d.w.z. {{hitt z{//qualification//''.''//name//}}}) in aldus onderzochte functies moet zien te vermijden. Het komt er feitelijk op neer dat {{tt t{getclosurevars}}} niet goed kan omgaan met object­attributen, om het even of het nu om gekwalificeerde namen of om attribuut­namen in class­definities gaat. Dat heeft ongetwijfeld te maken met de wat schimmige rol die attributen in de scope[[LOGI|Zichtbaarheid van Python-variabelen]]ca spelen.

Onderstaand programma illustreert waar de schoen zoal wringt.
{{lf w50pct pre{
{{fgre{"""# Script: getclosurevars.py
# Date  : 2023-07-08, Meindert Meindertsma"""}}}
"""
"""''import inspect''"""

say  = print
vars = 0

def fun():
    object."""{{fblu{"""__dir__"""}}}"""."""{{fblu{"""__class__"""}}}"""."""{{fblu{"""__repr__"""}}}"""
    try: """''whiskey''"""
    except Exception as e:
        say(f"fun: {type(e)."""{{fora{''"""__name__"""''}}}"""}: {e}")
    say(f"\n{fun."""{{fora{''print''}}}"""} {fun."""{{fora{''vars''}}}"""}")

fun.print = "fun's"
fun.vars  = "closure variables:"

fun()

cv = inspect.getclosurevars(fun)

for item in dir(cv):
    if item in ("builtins", "globals", "nonlocals", "unbound"):
        say(f"    {item}:")
        attr = getattr(cv, item)
        if isinstance(attr, dict):
            for var, val in getattr(cv, item).items():
                say(f"        {var:9s} =", val)
        else:
            for var in attr:
                say(f"        {var:9s}")"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w45pct pre{
''Uitvoer''
"""
fun: NameError: name 'whiskey' is not defined

fun's closure variables:
    builtins:
        object    = <class 'object'>
        Exception = <class 'Exception'>
        type      = <class 'type'>
        """{{fora{''print''     = <built-in function print>}}}"""
    globals:
        say       = <built-in function print>
        """{{fora{''"""__name__"""''  = """__main__"""}}}"""
        fun       = <function fun at 0x000001EF1075A020>
        """{{fora{''vars''      = 0}}}"""
    nonlocals:
    unbound:
        """''whiskey''"""
        """{{fblu{"""__dir__
        __class__
        __repr__"""}}}
}}}
{{clear block{
Met kleuren heb ik aangegeven waar het gedrag van {{tt t{inspect.getclosurevars}}} te wensen overlaat. De categorisering van de blauwe attributen als 'unbound' variabelen vind ik bedenkelijk en die van de oranje als 'builtins' en 'globals' ronduit fout. Maar nu ik deze onvolkomenheden{{ref{&#x200a;[[[1]|##1]]}}} eenmaal ken, valt er wel mee te leven.

----
|plain |k
|<html><a name="1">[1]</a></html>|Zie https://stackoverflow.com/questions/61964532/inspect-getclosurevars-classifies-attributes-as-global-or-unbound-how-to-distin. |
In veel Excel-sheets is het gebruikelijk om de eerste regel vast te zetten, afwijkend op te maken en van filters te voorzien. Verder pleegt men de kolombreedte vaak aan te passen aan de inhoud ervan. Met onderstaande ~Add-In {{{Kopopmaak.xlam}}} kan dit allemaal via één muisklik worden bewerkstelligd. Dit is de ~VBA-code:

{{{
Sub Kopopmaak()
'
' Kopopmaak Macro
'

    Range("A1").Select
    Range(Selection, Selection.End(xlToRight)).Select
    Selection.Font.Bold = True
    With Selection.Interior
        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .ThemeColor = xlThemeColorDark1
        .TintAndShade = -0.249977111117893
        .PatternTintAndShade = 0
    End With
    Selection.AutoFilter
    Cells.Select
    Cells.EntireColumn.AutoFit
    Range("A2").Select
    ActiveWindow.FreezePanes = True
End Sub
}}}
!!!Aanleg
Het gemakkelijkst is het om het hier bijgesloten Excel-bestand {{hitt{[[data/documents|data/documents]]/Kopopmaak.xlam}}} te kopiëren naar de gewenste doellocatie. Maar je kunt ook zelf aan de slag gaan. Begin dan met een nieuw Excel-bestand en maak hierin een ~VBA-module met bovenstaande inhoud aan (de naam van de module doet er niet zo toe, het voorgestelde "Module1" is al goed genoeg). Sla het werkboek op als een //~Add-In//-bestand, d.w.z. met bestandindeling "Excel-invoegtoepassing (*.xlam)" (Engels: "Excel ~Add-In (*.xlam)"):
* //Op Windows// komt het bestand dan in de map {{hitt z{C:\__Gebruikers__\//"""<naam>"""//\~AppData\Roaming\Microsoft\~AddIns\}}}{{ref{[[[1]|##1]]}}}{{ref{[[[2]|##2]]}}} terecht, tenzij je zelf expliciet een andere locatie kiest.
* Op //macOS// stelt Excel simpelweg je thuismap {{hitt z{/__Gebruikers__//"""/<naam>"""///}}}{{ref{[[[3]|##3]]}}} voor, wat ik niet zo'n handige plek vind. Zelf heb ik voor {{hitt z{/__Gebruikers__//"""/<naam>"""///__Bibliotheek__/Group Containers/''{{fe{~UBF8T346G9}}}''.Office/__Gebruikersinhoud__/__Invoegtoepassingen__/}}}{{ref{[[[4]|##4]]}}} gekozen, passend in de systematiek die het huidige Office voor bijvoorbeeld zijn sjablonen aanhoudt. Of het oranje gedeelte van de mapnaam voor iedereen hetzelfde is, weet ik niet. En anders valt {{hitt z{/__Gebruikers__//"""/<naam>"""///__Bibliotheek__/Preferences/Microsoft/~Add-Ins/}}}{{ref{[[[5]|##5]]}}} te overwegen. Het pad volgend op {{hitt z{Preferences/}}} moet je dan waarschijnlijk zelf nog even aanleggen, en de mapnaam {{hitt z{~Add-Ins}}} zou je daarbij door {{hitt z{~AddIns}}} of {{hitt z{Invoegtoepassingen}}} kunnen vervangen, als dat beter smaakt./%
%/
!!!Aansluiting (Windows)
Vanuit een willekeurige Excel-sessie kun je via //Opties voor Excel// (Engels: //Excel Options//) de Invoegtoepassingen oftewel ~Add-Ins managen. Kruis daar in het pop-upvenster met beschikbare ~Add-Ins "Kopopmaak" aan -- als het nog niet in het lijstje staat, kun je het zelf toevoegen via de knop "Bladeren" (Engels: "Browse"). Eveneens onder //Opties voor Excel// bevindt zich de voorziening "Werkbalk Snelle toegang" (Engels: "Customize the Quick Access Toolbar"). Kies onder "Opdrachten kiezen van" (Engels: "Choose commands from") voor "Macro's", en de rest wijst zichzelf. Het resultaat is een ministroomschemaatje in de werkbalk waarop je kunt klikken om de Kopopmaak-macro aan het werk te zetten./%

%/
!!!Aansluiting (macOS)
Vanuit een willekeurige Excel-sessie kun je via de hoofdmenu "Extra" (Engels: "Tools") de Invoegtoepassingen oftewel ~Add-Ins managen. Kruis daar in het pop-upvenster met beschikbare ~Add-Ins "Kopopmaak" aan -- als het nog niet in het lijstje staat, kun je het zelf toevoegen via de knop "Bladeren" (Engels: "Browse"). Via het laatste knopje in de //Werkbalk Snelle toegang// (Engels: //Quick Access Toolbar//) kun je deze werkbalk aanpassen. Kies onder "Opdrachten kiezen van" (Engels: "Choose commands from") voor "Macro's", en de rest wijst zichzelf. Het resultaat is een ministroomschemaatje in de werkbalk waarop je kunt klikken om de Kopopmaak-macro aan het werk te zetten.

----
{{z{
{{lf{<html><a name="1">[1]</a></html>}}} {{ib mlqem w95pct{De Nederlandse versies van Windows en macOS tooien sommige mappen met een Nederlandse naam. De Verkenner resp. Finder -- en de meeste applicaties eveneens -- laten die aangepaste namen zien. Het zijn echter slechts aliassen, want de werkelijke mapnamen zijn niet veranderd. Die zijn nog steeds Engelstalig, zoals je kunt zien wanneer je 'onder de motorkap' kijkt.}}}
{{lf{<html><a name="2">[2]</a></html>}}} {{ib mlqem w95pct{Engels: {{hitt z{C:\__Users__\//"""<naam>"""//~AppData\Roaming\Microsoft\~AddIns\}}}.}}}
{{lf{<html><a name="3">[3]</a></html>}}} {{ib mlqem w95pct{Engels: {{hitt z{/__Users__//"""/<naam>"""///}}}.}}}
{{lf{<html><a name="4">[4]</a></html>}}} {{ib mlqem w95pct{Engels: {{hitt z{/__Users__//"""/<naam>"""///__Library__/Group Containers/''{{fe{~UBF8T346G9}}}''.Office/__User Content.localized__/__~Add-Ins.localized__/}}}.}}}
{{lf{<html><a name="5">[5]</a></html>}}} {{ib mlqem w95pct{Engels: {{hitt z{/__Users__//"""/<naam>"""///__Library__/Preferences/Microsoft/~Add-Ins/}}}.}}}
}}}
De constructie van dit stelsel:
# De tien Arabische cijfers ''0'' t/m ''9'' gevolgd door de 26 letters van het Latijnse alfabet, evenals bij hexadecimale cijfers zonder betekenisverschil tussen hoofd- en kleine letters -- dat levert dus vier letters te veel op.
# De letters ''I'', ''L'', ''O'' en ''W'' worden overgeslagen wegens mogelijk te sterke gelijkenis met andere cijfers ( ''I'' en ''l'' {{sy{&asymp;}}} ''1''; ''O'' en ''o'' {{sy{&asymp;}}} ''0''; ''W'' {{sy{&asymp;}}} ''VV'' -- al pakken ''B'' naast ''8'' en ''S'' naast ''5'' natuurlijk ook niet altijd geweldig uit).{{ref{[[[1]|##1]]}}}
<script>
digits = "0123456789ABCDEFGHJKMNPQRSTUVXYZ";
let header = "|!|";
for (let i = 0; i < 32; i++) header += " !" + digits.substr(i, 1) + " |";
let table = "++++(~Ditricesimaal10)!![Van ditricesimaal naar decimaal &darr;|show][Van ditricesimaal naar decimaal &uarr;|hide]<<eval [=[|col1 tt zz |k\n" + header;
for (let i = 0; i < 32; i++) {
  let row = "\n|padding-right:1em;padding-left:1em; ''" + digits.substr(i, 1) + "''|";
  if (i % 8 == 0 && i > 0) row = "\n" + header + row;
  for (let j = 0; j < 32; j++) {
    if (j % 8 == 0) row += "border-left-width:2px;";
    let value = i*32 + j;
    if (value < 1000) value = value.toString();
    else value = "{{z{{{z{{{z{"+ value.toString() + "}}}}}}}}}";
    row += " " + value + " |";
  }
  table += row;
}
return table + "]=]>>\n===";
</script>/%

%/<script>
digits = "0123456789ABCDEFGHJKMNPQRSTUVXYZ";
let header = "|!|";
for (let i = 0; i < 32; i++) header += " !" + digits.substr(i, 1) + " |";
let table = "++++(~Ditricesimaal16)!![Van ditricesimaal naar hexadecimaal &darr;|show][Van ditricesimaal naar hexadecimaal &uarr;|hide]<<eval [=[|col1 tt zz |k\n" + header;
for (let i = 0; i < 32; i++) {
  let row = "\n|padding-right:1em;padding-left:1em; ''" + digits.substr(i, 1) + "''|";
  if (i % 8 == 0 && i > 0) row = "\n" + header + row;
  for (let j = 0; j < 32; j++) {
    if (j % 8 == 0) row += "border-left-width:2px;";
    let value = i*32 + j;
    value = value.toString(16).toUpperCase();
    row += " " + value + " |";
  }
  table += row;
}
return table + "]=]>>\n===";
</script>
----
|plain |k
| <html><a name="1">[1]</a></html>|Aanvankelijk wilde ik de ''U'' in plaats van de ''W'' overslaan, om klinkers zoveel mogelijk te vermijden. Met de handhaving van de ''U'' krijgt bijvoorbeeld het decimale getal 20.346 een niet door alle Nederlandstaligen op prijs gesteld voorkomen. |
See also http://www.windows-scripting.info/wsus-error-codes and http://computerperformance.co.uk/Logon/code/index.htm (the latter especially for the 0x800????? errors).

|!Error#|!Message|
|     5|Invalid procedure call or argument|
|     6|Overflow|
|     7|Out of memory|
|     9|Subscript out of range|
|    10|Array fixed or temporarily locked|
|    11|Division by zero|
|    13|Type mismatch|
|    14|Out of string space|
|    28|Out of stack space|
|    35|Sub or Function not defined|
|    48|Error in loading DLL|
|    51|Internal error|
|    53|File not found|
|    57|Device I/O error|
|    58|File already exists|
|    61|Disk full|
|    67|Too many files|
|    70|Permission denied|
|    75|Path/File access error|
|    76|Path not found|
|    91|Object variable or With block variable not set|
|    92|For loop not initialized|
|    94|Invalid use of Null|
|   322|Can't create necessary temporary file|
|   424|Object required|
|   429|~ActiveX component can't create object|
|   430|Class doesn't support Automation|
|   432|File name or class name not found during Automation operation|
|   438|Object doesn't support this property or method|
|   440|Automation error|
|   445|Object doesn't support this action|
|   446|Object doesn't support named arguments|
|   447|Object doesn't support current locale setting|
|   448|Named argument not found|
|   449|Argument not optional|
|   450|Wrong number of arguments or invalid property assignment|
|   451|Object not a collection|
|   453|Specified DLL function not found|
|   455|Code resource lock error|
|   457|This key already associated with an element of this collection|
|   458|Variable uses an Automation type not supported in ~VBScript|
|   500|Variable is undefined|
|   501|Illegal assignment|
|   502|Object not safe for scripting|
|   503|Object not safe for initializing|
|  1001|Out of memory|
|  1002|Syntax error|
|  1003|Expected ':'|
|  1004|Expected ';'|
|  1005|Expected '('|
|  1006|Expected ')'|
|  1007|Expected ']'|
|  1008|Expected '{'|
|  1009|Expected '}'|
|  1010|Expected identifier|
|  1011|Expected '='|
|  1012|Expected 'If'|
|  1013|Expected 'To'|
|  1014|Expected 'End'|
|  1015|Expected 'Function'|
|  1016|Expected 'Sub'|
|  1017|Expected 'Then'|
|  1018|Expected 'Wend'|
|  1019|Expected 'Loop'|
|  1020|Expected 'Next'|
|  1021|Expected 'Case'|
|  1022|Expected 'Select'|
|  1023|Expected expression|
|  1024|Expected statement|
|  1025|Expected end of statement|
|  1026|Expected integer constant|
|  1027|Expected 'While' or 'Until'|
|  1028|Expected 'While', 'Until', or end of statement|
|  1029|Too many locals or arguments|
|  1030|Identifier too long|
|  1031|Invalid number|
|  1032|Invalid character|
|  1033|Unterminated string constant|
|  1034|Unterminated comment|
|  1035|Nested comment|
|  1037|Invalid use of 'Me' keyword|
|  1038|'Loop' without 'Do'|
|  1039|Invalid 'Exit' statement|
|  1040|Invalid 'For' loop control variable|
|  1041|Name redefined|
|  1042|Must be first statement on the line|
|  1043|Can't assign to non-~ByVal argument|
|  1044|Can't use parens when calling a Sub|
|  1045|Expected literal constant|
|  1046|Expected 'In'|
| 32766|True|
| 32767|False|
| 32811|Element not found|

This script generates a list of error numbers and their descriptions:
{{{
Dim errDef, i

WScript.Echo "VBScript-Errors:"
WScript.Echo "Number", "Description"

On Error Resume Next
Err.Raise 1
errDef = Err.Description

For i=1 to 2^16-1
  Err.Clear
  Err.Raise i
  If Err.Description <> errDef Then
    WScript.Echo Left(Err.Number & ":" & Space(6), 6), Err.Description
  End if
Next
}}}
Character codes {{hitt z{''$''//prefix//{{ww{&#x25a2;}}}//suffix//}}} as evaluated by the ''{{tt{[[eval|ExtraMacros]]}}}'' macro (the {{ww tt z{&#x25a2;}}} symbol denotes the expression in the respective column headers). The operators on a {{pref hws b1 r{colored background}}} have a natural width, i.e. not an enforced multiple of 0.6em (the character width of the applied monospace font).
<<eval [=[!!!Circumfix operators
|tt col1 col2 bold1 bold2 |k
| !{{saco{Prefix}}} | !{{saco{Suffix}}} | !(( )) | !&nbsp;( )&nbsp; | !"""[[ ]]""" | !&nbsp;[ ]&nbsp; | !"""{{ }}""" | !&nbsp;{ }&nbsp; | !<: >: | !&nbsp;< >&nbsp; | !&nbsp;` '&nbsp; | !/* */ |
| | @ |         | $(@ $)@ |         | $[@ $]@ |         | ${@ $}@ |         | $<@ $>@ |       |         |
| | + |         | $(+ $)+ |         | $[+ $]+ |         | ${+ $}+ |         | $<+ $>+ |       |         |
| | - |         | $(- $)- |         | $[- $]- |         |         |         | $<- $>- | &nbsp; &nbsp; &nbsp; |         |
| | = |         | $(= $)= |         | $[= $]= | | | {{serif ws b1 r{$<:= $>:=}}} | {{serif ws b1 r{$<= $>=}}} | $`= $'= | {{serif ws b1 r{$/*= $*/=}}} |
| |   | $(( $)) | $(  $)  | $[[ $]] | $[  $]  | ${{ $}} | ${  $}  | $<: $>: | $<  $>  | $` $' | $/* $*/ |
]=]>>/%

%/<<eval [=[!!!Infix operators
|tt col1 col2 bold1 bold2 |k
| !{{saco{Prefix}}} | !{{saco{Suffix}}} | !"""||""" | !"""|""" | !: | !& | !~ | !-> | !-< | !-? | !-^ | !=> | !=< | !=? | != | !. | !"""//""" | !{{saco{Remark}}} |
| - | +     |&nbsp; &nbsp;|&nbsp; &nbsp;|&nbsp; &nbsp;|&nbsp; &nbsp;|&nbsp; &nbsp;| $-->+ | $--<+ | $--?+ |&nbsp; &nbsp;| | | |&nbsp; &nbsp;|&nbsp; &nbsp;|&nbsp; &nbsp;|{{serif{//3 positions//}}} |
| - |       |      |     |     |     |     | $--> | $--< | $--? |      |       |       |       |     |     |      |{{serif{//2 positions//}}} |
| = | +     |      |     |     |     |     |      |      |      |      | $==>+ | $==<+ | $==?+ |     |     |      |{{serif{//3 positions//}}} |
| = |       |      |     |     |     |     |      |      |      |      | $==>  | $==<  | $==?  |     |     |      |{{serif{//2 positions//}}} |
| | @       | $||@ | $|@ |     |     |     |      |      |      |      |       |       |       | $=@ | $.@ |      | |
| | +       | $||+ | $|+ | $:+ |     |     |      |      |      |      |       |       |       | $=+ | $.+ |      | |
| | -       |      | $|- |     |     |     |      |      |      |      |       |       |       | $=- | {{hws b1 r{$.-}}} | | |
| | =       | $||= | $|= | {{hws b1 r{$:=}}} | $&= | | | |      |      |       |       |       | $== | $.= |      | |
| | """!""" |      |     | $:! | $&! | $~! | $->! | $-<! |      | $-^! | $=>!  | $=<!  |       |     | $.! | $//! | |
| |         | $||  | $|  | $:  | $&  | $~  | $->  | $-<  |      | $-^  | $=>   | $=<   |       | $=  | $.  | $//  | |
]=]>>/%

%/<<eval [=[!!!Postfix operators
|tt col1 col2 bold1 bold2 |k
| !{{saco{Prefix}}} | !{{saco{Suffix}}} | !&nbsp;*&nbsp; | !&nbsp;+&nbsp; | !&nbsp;?&nbsp; | !&nbsp;0&nbsp; | !&nbsp;1&nbsp; | !"""___"""         |
|                   |                   | $*             | $+             | $?             | $0             | $1             | {{hws b1 r{$___}}} |
All superscripts are shifted slightly to the left.]=]>>
Export van een Word-bestand (DOCX) naar PDF kan op verschillende manieren en op verschillende platforms./%
%/
!!Windows
*''Vanuit Word printen naar //Microsoft Print to PDF//'' -- Alle tekst wordt als tekst in het ~PDF-bestand opgeslagen, maar dat betekent nog niet dat alle tekst ook daadwerkelijk als tekst in de reader (Acrobat Reader of Voorvertoning ({{{Preview.app}}}) beschikbaar is, d.w.z. als tekst kan worden geselecteerd en gekopieerd. Indien niet, dan is er een grafische representatie van hoge kwaliteit voor in de plaats gekomen. Het is moeilijk er een vinger achter te krijgen in welke gevallen er omzetting van tekst naar bitmaps plaatsvindt. De A3-opmaakvellen voor 't Rovaal #55&half; (de preview) en #56 (de glossy) worden geheel grafisch. Bij de wat kleinere opmaakvellen zoals {{{Rovaal56-schemas--008-mijlpaal-Echo.docx}}} is wel tekstbehoud waar te nemen, evenals bij {{{Curly quotes.docx}}}, dat A4-formaat heeft. In laatstgenoemde worden echter de lettertypen //Alkes// (~OTF-font) en //~InputMonoCompressed// (~TTF-font) grafisch opgenomen.
*''Vanuit Word exporteren naar PDF met optie //Bitmap text when fonts may not be embedded// aangevinkt'' -- ~OTF-fonts worden als bitmap van matige kwaliteit weergegeven. Bij ~TTF-fonts lijkt de tekst altijd beschikbaar te blijven.
*''Vanuit Word exporteren naar PDF met optie //Bitmap text when fonts may not be embedded// __niet__ aangevinkt'' -- Bij ~OTF-fonts worden gekrulde aanhalingstekens en vaak ook de hele betrokken regel of een deel ervan als bitmap weergegeven. Deze bitmap is van matige kwaliteit. ~TTF-fonts lijken er geen last van te hebben.
*''Vanuit ~LibreOffice Writer printen naar //Microsoft Print to PDF//'' -- Zelfde beeld als printen vanuit Word. Met dit verschil, dat Writer de opmaak van {{{t Rovaal #55,5.docx}}} eerst behoorlijk overhoop heeft gegooid.
*''Vanuit ~LibreOffice Writer exporteren naar PDF'' -- Alle tekst blijft in de reader beschikbaar (getest met {{{Curly quotes.docx}}} en {{{t Rovaal #55,5.docx}}}).
*''Een ~PDF-bestand vanuit Acrobat Reader printen naar //Microsoft Print to PDF//'' (toegepast om het A4-centrum van een A3-vel apart op te slaan) leidt altijd tot een geheel grafische representatie./%
%/
!!macOS
*''Vanuit Word printen naar //Microsoft Print to PDF//'' -- Alle tekst in {{{Curly quotes.docx}}} en {{{t Rovaal #55,5.docx}}} is als zodanig in de reader beschikbaar. De maatvoering van Word voor macOS kan afwijken van Word voor Windows, blijkt bij laatstgenoemd document.
*''Vanuit Word exporteren naar PDF'' -- Zelfde resultaat als bij printen.
*''Vanuit ~LibreOffice'' -- Niet getest.
/***
!!gotoTiddlerTop/%------------------------------------------------------------%/
***/
//{{{
config.commands.gotoTiddlerTop = {
  text: "top",
  tooltip: "Go to the top of this tiddler",
  handler: function(event, src, title) {
    story.displayTiddler(src, title);
  }
};
//}}}
/***
!!div/%------------------------------------------------------------%/
***/
//{{{
config.macros.div = {
  handler: function(place, macroName, params, wikifier, paramString, tiddler) {
    params = paramString.parseParams("params", null, true, false, true);
    if (!params[1]) return;
    var text = params[1].value;

    text = text.replace(/&/g     , "&amp;" );    // mask   &      as &amp;
    text = text.replace(/\\\\/g  , "&#x5C;");    // mask   \\     as &#x5C;
    text = text.replace(/\\/g    , ""      );    // remove \
    text = text.replace(/&#x5C;/g, "\\"    );    // unmask &#x5C; as \
    text = text.replace(/&amp;/g , "&"     );    // unmask &amp;  as &

    e = createTiddlyElement(place, "div", null, null, null, {"style": "overflow:hidden;"});
    tiddler = new Tiddler("temp");
    var wikifier = new Wikifier(text, getParser(tiddler), null, tiddler);
    wikifier.subWikify(e);
  }
};
//}}}
/***
!!divlf/%------------------------------------------------------------%/
***/
//{{{
config.macros.divlf = {
  handler: function(place, macroName, params, wikifier, paramString, tiddler) {
    params = paramString.parseParams("params", null, true, false, true);
    if (!params[2]) return;
    var width = params[1].value;
    var text  = params[2].value;

    text = text.replace(/&/g     , "&amp;" );    // mask   &      as &amp;
    text = text.replace(/\\\\/g  , "&#x5C;");    // mask   \\     as &#x5C;
    text = text.replace(/\\/g    , ""      );    // remove \
    text = text.replace(/&#x5C;/g, "\\"    );    // unmask &#x5C; as \
    text = text.replace(/&amp;/g , "&"     );    // unmask &amp;  as &

    e = createTiddlyElement(place, "div", null, null, null, {"style": "overflow:hidden; float:left; width:" + width});
    tiddler = new Tiddler("temp");
    var wikifier = new Wikifier(text, getParser(tiddler), null, tiddler);
    wikifier.subWikify(e);
  }
};
//}}}
/***
!!draw/%------------------------------------------------------------%/
***/
//{{{
config.macros.draw = {
  handler: function(place, macroName, params, wikifier, paramString, tiddler) {
    params = paramString.parseParams('params', null, true, false, true);
    if (!params[1]) return;
    var text    = params[1].value;
    var classes = params[2] ? params[2].value : "";

    /*--- Preparation ---*/
    text = text.replace(/&/g       , "&amp;" );    // mask    &            as   &amp;
    text = text.replace(/\\\\/g    , "&#x5C;");    // mask    \\           as   &#x5C;
    text = text.replace(/\\@/g     , "&#x40;");    // mask    \@           as   &#x40;
    text = text.replace(/\\/g      , ""      );    // remove  \

    /*--- Unicode Box Drawing, Block Elements, Geometric Shapes ---*/
    text = text.replace(/@([\da-f][\da-f])/g, "{{_ " + classes + "{&amp;#x25\$1;}}}");

    /*--- Clearance ---*/
    text = text.replace(/&#x40;/g, "$"     );    // unmask &#x40; as @
    text = text.replace(/&#x5C;/g, "\\"    );    // unmask &#x5C; as \
    text = text.replace(/&amp;/g , "&"     );    // unmask &amp;  as &
    text = text.replace(/\\\0/g  , ""      );    // remove NULL character

    e = createTiddlyElement(place, "span");
    tiddler = new Tiddler("temp");
    var wikifier = new Wikifier(text, getParser(tiddler), null, tiddler);
    wikifier.subWikify(e);
  }
};
//}}}
/***
!!eval/%------------------------------------------------------------%/
***/
//{{{
config.macros.eval = {
  handler: function(place, macroName, params, wikifier, paramString, tiddler) {
    var edit = function(color) {
      return store.getTiddlerText( color
                                 , " "
                                 ).replace( /^#([0-9A-F])([0-9A-F])([0-9A-F])$/i
                                          , "#$1$1$2$2$3$3"
                                          );
    }

    params = paramString.parseParams('params', null, true, false, true);
    if (!params[1]) return;
    var text = params[1].value;
    var color = params[2] ? params[2].value : "";

    /*--- Preparation ---*/
    text = text.replace(/&/g       , "&amp;" );    // mask    &            as   &amp;
    text = text.replace(/\\\\/g    , "&#x5C;");    // mask    \\           as   &#x5C;
    text = text.replace(/\\\$/g    , "&#x24;");    // mask    \$           as   &#x24;
    text = text.replace(/\\@/g     , "&#x40;");    // mask    \@           as   &#x40;
    text = text.replace(/\\\]/g    , "]"     );    // replace \]           with ]
    text = text.replace(/\\\|\n/g  , "<br>"  );    // replace \|«newline»  with <br>
    text = text.replace(/\\\n/g    , "<br>"  );    // replace \«newline»   with <br>
    text = text.replace(/\$\$\|\n/g, ""      );    // remove  $$|«newline»
    text = text.replace(/\$\|\n/g  , "\n"    );    // replace $|«newline»  with «newline»
    text = text.replace(/\$!/g     , "\0"    );    // replace $!           with NULL character
    text = text.replace(/\\/g      , ""      );    // remove  \

    /*--- Colors---*/
    text = text.replace(/\$B/ig , edit("ColorPalette::Background"       ));
    text = text.replace(/\$F/ig , edit("ColorPalette::Foreground"       ));
    text = text.replace(/\$1W/ig, edit("ColorPalette::PrimaryWhitened"  ));
    text = text.replace(/\$1P/ig, edit("ColorPalette::PrimaryPale"      ));
    text = text.replace(/\$1F/ig, edit("ColorPalette::PrimaryFair"      ));
    text = text.replace(/\$1L/ig, edit("ColorPalette::PrimaryLight"     ));
    text = text.replace(/\$1S/ig, edit("ColorPalette::PrimarySoft"      ));
    text = text.replace(/\$1B/ig, edit("ColorPalette::PrimaryBright"    ));
    text = text.replace(/\$1M/ig, edit("ColorPalette::PrimaryMid"       ));
    text = text.replace(/\$1D/ig, edit("ColorPalette::PrimaryDark"      ));
    text = text.replace(/\$2W/ig, edit("ColorPalette::SecondaryWhitened"));
    text = text.replace(/\$2P/ig, edit("ColorPalette::SecondaryPale"    ));
    text = text.replace(/\$2L/ig, edit("ColorPalette::SecondaryLight"   ));
    text = text.replace(/\$2S/ig, edit("ColorPalette::SecondarySoft"    ));
    text = text.replace(/\$2M/ig, edit("ColorPalette::SecondaryMid"     ));
    text = text.replace(/\$2D/ig, edit("ColorPalette::SecondaryDark"    ));
    text = text.replace(/\$3W/ig, edit("ColorPalette::TertiaryWhitened" ));
    text = text.replace(/\$3P/ig, edit("ColorPalette::TertiaryPale"     ));
    text = text.replace(/\$3L/ig, edit("ColorPalette::TertiaryLight"    ));
    text = text.replace(/\$3S/ig, edit("ColorPalette::TertiarySoft"     ));
    text = text.replace(/\$3M/ig, edit("ColorPalette::TertiaryMid"      ));
    text = text.replace(/\$3D/ig, edit("ColorPalette::TertiaryDark"     ));
    text = text.replace(/\$E/ig , edit("ColorPalette::Error"            ));

    /*--- Circumfix operators ---*/
    text = text.replace(/\$\(\(/g  , "{{w " + color + "{{{stix{&#x2985;}}}}}}");
    text = text.replace(/\$\)\)/g  , "{{w " + color + "{{{stix{&#x2986;}}}}}}");
    text = text.replace(/\$\(@/g   , "{{w " + color + "{{{sy h3{@@position:relative;top:0.08em;(@@}}}}}}");
    text = text.replace(/\$\)@/g   , "{{w " + color + "{{{sy h3{@@position:relative;top:0.08em;)@@}}}}}}");
    text = text.replace(/\$\(\+/g  , "{{w " + color + "{{{h3w{(}}}}}}");
    text = text.replace(/\$\)\+/g  , "{{w " + color + "{{{h3w{)}}}}}}");
    text = text.replace(/\$\(-/g   , "{{w " + color + "{{{sy z{@@position:relative;top:-0.85em;left:-0.1em;font-weight:bold;&#x256d;@@}}}}}}");
    text = text.replace(/\$\)-/g   , "{{w " + color + "{{{sy z{@@position:relative;top:-0.85em;left:-0.2em;font-weight:bold;&#x256e;@@}}}}}}");
    text = text.replace(/\$\(=/g   , "{{w " + color + "{{{h4 tight{@@position:relative;left:-0.05em;&#x2e02;@@}}}}}}");
    text = text.replace(/\$\)=/g   , "{{w " + color + "{{{h4 tight{@@position:relative;left:-0.05em;&#x2e03;@@}}}}}}");
    text = text.replace(/\$\(/g    , "{{w " + color + "{@@position:relative;top:-0.1em;&amp;#x207d;@@}}}");
    text = text.replace(/\$\)/g    , "{{w " + color + "{@@position:relative;top:-0.1em;&amp;#x207e;@@}}}");
    text = text.replace(/\$\[\[/g  , "{{w " + color + "{{{stix{&#x27e6;}}}}}}");
    text = text.replace(/\$\]\]/g  , "{{w " + color + "{{{stix{&#x27e7;}}}}}}");
    text = text.replace(/\$\[@/g   , "{{w " + color + "{{{sy h3{@@position:relative;top:0.08em;[@@}}}}}}");
    text = text.replace(/\$\]@/g   , "{{w " + color + "{{{sy h3{@@position:relative;top:0.08em;]@@}}}}}}");
    text = text.replace(/\$\[\+/g  , "{{w " + color + "{{{h3w{[}}}}}}");
    text = text.replace(/\$\]\+/g  , "{{w " + color + "{{{h3w{]}}}}}}");
    text = text.replace(/\$\[-/g   , "{{w " + color + "{{{sy{@@position:relative;top:-0.7em;left:-0.2em;&amp;#x250c;@@}}}}}}");
    text = text.replace(/\$\]-/g   , "{{w " + color + "{{{sy{@@position:relative;top:-0.7em;left:-0.2em;&amp;#x2510;@@}}}}}}");
    text = text.replace(/\$\[=/g   , "{{w " + color + "{{{h4 tight{@@position:relative;left:-0.05em;&#x2e22;@@}}}}}}");
    text = text.replace(/\$\]=/g   , "{{w " + color + "{{{h4 tight{@@position:relative;left:-0.05em;&#x2e23;@@}}}}}}");
    text = text.replace(/\$\[/g    , "{{w " + color + "{^^[^^}}}");
    text = text.replace(/\$\]/g    , "{{w " + color + "{^^]^^}}}");
    text = text.replace(/\$\{\{/g  , "{{w " + color + "{{{stix{&#x2983;}}}}}}");
    text = text.replace(/\$\}\}/g  , "{{w " + color + "{{{stix{&#x2984;}}}}}}");
    text = text.replace(/\$\{@/g   , "{{w " + color + "{{{sy h3{@@position:relative;top:0.08em;{@@}}}}}}");
    text = text.replace(/\$\}@/g   , "{{w " + color + "{{{sy h3{@@position:relative;top:0.08em;}@@}}}}}}");
    text = text.replace(/\$\{\+/g  , "{{w " + color + "{{{h3w{{}}}}}}");
    text = text.replace(/\$\}\+/g  , "{{w " + color + "{{{h3w{\"\"\"}\"\"\"}}}}}}");
    text = text.replace(/\$\{/g    , "{{w " + color + "{^^{^^}}}");
    text = text.replace(/\$\}/g    , "{{w " + color + "{^^}^^}}}");
    text = text.replace(/\$<:=/g   , "{{_ " + color + "{{{sy h4 tight{&Lang;}}}}}}");
    text = text.replace(/\$>:=/g   , "{{_ " + color + "{{{sy h4 tight{&Rang;}}}}}}");
    text = text.replace(/\$<:/g    , "{{w " + color + "{{{sy h4 tight{&Lang;}}}}}}");
    text = text.replace(/\$>:/g    , "{{w " + color + "{{{sy h4 tight{&Rang;}}}}}}");
    text = text.replace(/\$<@/g    , "{{w " + color + "{{{sy z{{{z{&#x2b9c;}}}}}}}}}");
    text = text.replace(/\$>@/g    , "{{w " + color + "{{{sy z{{{z{&#x2b9e;}}}}}}}}}");
    text = text.replace(/\$<\+/g   , "{{w " + color + "{^^<^^}}}");
    text = text.replace(/\$>\+/g   , "{{w " + color + "{^^>^^}}}");
    text = text.replace(/\$<-/g    , "{{w " + color + " up{&amp;lsaquo;}}}");
    text = text.replace(/\$>-/g    , "{{w " + color + " up{&amp;rsaquo;}}}");
    text = text.replace(/\$<=/g    , "{{_ " + color + "{{{sy h4 tight{&lang;}}}}}}");
    text = text.replace(/\$>=/g    , "{{_ " + color + "{{{sy h4 tight{&rang;}}}}}}");
    text = text.replace(/\$</g     , "{{w " + color + "{{{sy h4 tight{&lang;}}}}}}");
    text = text.replace(/\$>/g     , "{{w " + color + "{{{sy h4 tight{&rang;}}}}}}");
    text = text.replace(/\$`=/g    , "{{w " + color + "{{{sy{@@position:relative;left:-0.5em;&#x301d;@@}}}}}}");
    text = text.replace(/\$'=/g    , "{{w " + color + "{{{sy{@@position:relative;left:0.1em;&#x301e;@@}}}}}}");
    text = text.replace(/\$`/g     , "{{w " + color + "{{{sy h3 tight{@@position:relative;top:0.15em;&#x2e0c;@@}}}}}}");
    text = text.replace(/\$'/g     , "{{w " + color + "{{{sy h3 tight{@@position:relative;top:0.15em;&#x2e0d;@@}}}}}}");
    text = text.replace(/\$\/\*=/g , "{{_ " + color + "{{{sy{&amp;#x269e;}}}}}}");
    text = text.replace(/\$\*\/=/g , "{{_ " + color + "{{{sy{&amp;#x269f;}}}}}}");
    text = text.replace(/\$\/\*/g  , "{{ww " + color + "{{{sy{&amp;#x269e;}}}}}}");
    text = text.replace(/\$\*\//g  , "{{ww " + color + "{{{sy{&amp;#x269f;}}}}}}");

    /*--- Infix operators ---*/
    text = text.replace(/\$\|\|@/g , "{{w " + color + "{{{sy h3{@@position:relative;top:0.08em;&amp;#x2016;@@}}}}}}");
    text = text.replace(/\$\|\|\+/g, "{{w " + color + "{{{stix h3{&amp;#x2016;}}}}}}");
    text = text.replace(/\$\|\|=/g , "{{w " + color + "{{{stix{&amp;#x2016;}}}}}}");
    text = text.replace(/\$\|\|/g  , "{{w " + color + "{{{stix{^^&amp;#x2016;^^}}}}}}");
    text = text.replace(/\$\|@/g   , "{{w " + color + "{{{sy h3{@@position:relative;top:0.08em;|@@}}}}}}");
    text = text.replace(/\$\|\+/g  , "{{w " + color + "{{{h3w{|}}}}}}");
    text = text.replace(/\$\|-/g   , "{{w " + color + "{^^{{stix{&amp;or;}}}^^}}}");
    text = text.replace(/\$\|=/g   , "{{w " + color + "{{{sy h4 tight{@@position:relative;top:-0.03em;left:-0.08em;&amp;or;@@}}}}}}");
    text = text.replace(/\$\|/g    , "{{w " + color + "{^^|^^}}}");
    text = text.replace(/\$:\+/g   , "{{w " + color + "{{{sy{@@position:relative;left:-0.2em;&amp;#x250a;@@}}}}}}");
    text = text.replace(/\$:=/g    , "{{_ " + color + "{&amp;brvbar;}}}");
    text = text.replace(/\$:!/g    , "{{w " + color + "{{{sy h4 tight{@@position:relative;top:0.05em;&#x205d;@@}}}}}}");
    text = text.replace(/\$:/g     , "{{w " + color + "{^^&amp;brvbar;^^}}}");
    text = text.replace(/\$&amp;=/g, "{{w " + color + "{{{sy h4 tight{@@position:relative;top:-0.03em;left:-0.08em;&amp;and;@@}}}}}}");
    text = text.replace(/\$&amp;!/g, "{{w " +         "{{{fred{^^&amp;^^}}}}}}");
    text = text.replace(/\$&amp;/g , "{{w " + color + "{^^&amp;^^}}}");
    text = text.replace(/\$~!/g    , "{{w " +         "{{{fred up{&amp;not;}}}}}}");
    text = text.replace(/\$~/g     , "{{w " + color + "{{{up{&amp;not;}}}}}}");
    text = text.replace(/\$-->\+/g , "{{www " + color + "{{{stix{&amp;xrarr;}}}}}}");
    text = text.replace(/\$--<\+/g , "{{www " + color + "{{{stix{@@position:relative;left:-0.05em;&amp;xlarr;@@}}}}}}");
    text = text.replace(/\$--\?\+/g, "{{www " + color + "{{{stix{@@position:relative;left:-0.05em;&amp;xharr;@@}}}}}}");
    text = text.replace(/\$-->/g   , "{{ww " + color + "{&amp;xrarr;}}}");
    text = text.replace(/\$--</g   , "{{ww " + color + "{&amp;xlarr;}}}");
    text = text.replace(/\$--\?/g  , "{{ww " + color + "{&amp;xharr;}}}");
    text = text.replace(/\$->!/g   , "{{w " + color + "{{{stix{@@position:relative;left:-0.18em;&amp;#x21a6;@@}}}}}}");
    text = text.replace(/\$->/g    , "{{w " + color + "{{{sans{@@position:relative;left:-0.1em;&amp;rarr;@@}}}}}}");
    text = text.replace(/\$-<!/g   , "{{w " + color + "{{{stix{@@position:relative;left:-0.22em;&amp;#x21a4;@@}}}}}}");
    text = text.replace(/\$-</g    , "{{w " + color + "{{{sans{@@position:relative;left:-0.15em;&amp;larr;@@}}}}}}");
    text = text.replace(/\$-\^!/g  , "{{w " + color + "{{{stix{&amp;#x21a5;}}}}}}");
    text = text.replace(/\$-\^/g   , "{{w " + color + "{&amp;uarr;}}}");
    text = text.replace(/\$==>\+/g , "{{www " + color + "{{{stix{&amp;xrArr;}}}}}}");
    text = text.replace(/\$==<\+/g , "{{www " + color + "{{{stix{@@position:relative;left:-0.05em;&amp;xlArr;@@}}}}}}");
    text = text.replace(/\$==\?\+/g, "{{www " + color + "{{{stix{@@position:relative;left:-0.05em;&amp;xhArr;@@}}}}}}");
    text = text.replace(/\$==>/g   , "{{ww " + color + "{{{stix z{@@position:relative;left:-0.2em;&amp;xrArr;@@}}}}}}");
    text = text.replace(/\$==</g   , "{{ww " + color + "{{{stix z{@@position:relative;left:-0.25em;&amp;xlArr;@@}}}}}}");
    text = text.replace(/\$==\?/g  , "{{ww " + color + "{{{stix z{@@position:relative;left:-0.25em;&amp;xhArr;@@}}}}}}");
    text = text.replace(/\$=>!/g   , "{{w " + color + "{{{stix{@@position:relative;left:-0.2em;&amp;#x2907;@@}}}}}}");
    text = text.replace(/\$=>/g    , "{{w " + color + "{{{stix{@@position:relative;left:-0.15em;&amp;rArr;@@}}}}}}");
    text = text.replace(/\$=<!/g   , "{{w " + color + "{{{stix{@@position:relative;left:-0.2em;&amp;#x2906;@@}}}}}}");
    text = text.replace(/\$=</g    , "{{w " + color + "{{{stix{@@position:relative;left:-0.2em;&amp;lArr;@@}}}}}}");
    text = text.replace(/\$=\+/g   , "{{w " + color + "{{{sy z{@@position:relative;left:-0.1em;&#x2bce;@@}}}}}}");
    text = text.replace(/\$=-/g    , "{{w " + color + "{{{stix{^^&#x22ce;^^}}}}}}");
    text = text.replace(/\$==/g    , "{{w " + color + "{{{stix z up1px{&amp;equiv;}}}}}}");
    text = text.replace(/\$=@/g    , "{{w " + color + " pref{{{w{@@position:relative;top:0.18em;left:0.18em;{{stix tight h3{&amp;nbsp;&amp;#x0311;}}}@@}}}{{w{@@position:relative;top:0.9em;left:-0.42em;{{stix tight h3{&amp;nbsp;&amp;#x0306;}}}@@}}}}}}");
    text = text.replace(/\$=/g     , "{{_ " + color + "{{{tt{&amp;#x2e17;}}}}}}");
    text = text.replace(/\$\.@/g   , "{{w " + color + "{{{sy{@@position:relative;left:-0.1em;&amp;#x23f9;@@}}}}}}");
    text = text.replace(/\$\.\+/g  , "{{w " + color + "{@@font-weight:bold;&amp;bull;@@}}}");
    text = text.replace(/\$\.-/g   , "{{_ " + color + "{&amp;middot;}}}");
    text = text.replace(/\$\.=/g   , "{{w " + color + "{{{stix{&amp;compfn;}}}}}}");
    text = text.replace(/\$\.!/g   , "{{w " + color + "{{{sy{&amp;#x1d17;}}}}}}");
    text = text.replace(/\$\./g    , "{{w " + color + "{{{sy h3{&#x2e1c;}}}}}}");
    text = text.replace(/\$\/\/!/g , "{{ww " + color + "{{{sy z up1px{{{z up1px{&amp;#x26ff;}}}}}}}}}");
    text = text.replace(/\$\/\//g  , "{{w " + color + "{{{h6{&amp;para;}}}}}}");

    /*--- Postfix operators ---*/
    text = text.replace(/\$\*/g    , "{{w " + color + " hup{@@margin:0 0.05em 0 -0.05em;^^*^^@@}}}");
    text = text.replace(/\$\+/g    , "{{w " + color + " hup{@@margin:0 0.05em 0 -0.05em;^^+^^@@}}}");
    text = text.replace(/\$\?/g    , "{{w " + color + " hup{@@margin:0 0.05em 0 -0.05em;^^?^^@@}}}");
    text = text.replace(/\$0/g     , "{{w " + color + " hup{@@margin:0 0.05em 0 -0.05em;&amp;deg;@@}}}");
    text = text.replace(/\$1/g     , "{{w " + color + "{@@position:relative;top:-0.28em;left:-0.05em;{{sy tight s{^^&#x23fa;^^}}}@@}}}");
    text = text.replace(/\$___/g   , "{{_ " + color + "{&amp;middot;&amp;middot;&amp;middot;}}}");

    /*--- Unicode Box Drawing, Block Elements, Geometric Shapes ---*/
    text = text.replace(/@([\da-f][\da-f])/g, "{{_ " + color + "{&amp;#x25\$1;}}}");

    /*--- Clearance ---*/
    text = text.replace(/&#x40;/g, "@"     );    // unmask &#x40; as @
    text = text.replace(/&#x24;/g, "$"     );    // unmask &#x24; as $
    text = text.replace(/&#x5C;/g, "\\"    );    // unmask &#x5C; as \
    text = text.replace(/&amp;/g , "&"     );    // unmask &amp;  as &
    text = text.replace(/\\\0/g  , ""      );    // remove NULL character

    e = createTiddlyElement(place, "span");
    tiddler = new Tiddler("temp");
    var wikifier = new Wikifier(text, getParser(tiddler), null, tiddler);
    wikifier.subWikify(e);
  }
};
//}}}
''{{up1px sans{<<showPopup tiddler:[[} Iteratie & recursie]] label: "Bundel ↘">>}}}''
{{lf pr3em{
!!!@@position:relative;top:2px;One of Theo's __recursive__ Tower of Hanoi algorithms:@@
{{ib pre{{{_{
def __''hanoiR''__(''{{fpur{n}}}'', {{fred{van}}}, {{fblu{naar}}}, {{fgre{tussen}}}):
    if ''{{fpur{n}}}'' <= ''{{fpur{0}}}'':
        return 0
    aantal = __''hanoiR''__(''{{fpur{n - 1}}}'', {{fred{van}}}, {{fgre{tussen}}}, {{fblu{naar}}})
    ''{{fora{print}}}''('Schijf', ''{{fpur{n}}}'', 'van', {{fred{van}}}, 'naar', {{fblu{naar}}})
    return aantal + 1 + __''hanoiR''__(''{{fpur{n - 1}}}'', {{fgre{tussen}}}, {{fblu{naar}}}, {{fred{van}}})     
}}}}}}
''//{{h4 saco{Another recursive (and faster) solution:}}}//''
{{ib pre{{{_{
def __''hanoiQ''__(''{{fpur{n}}}'', {{fred{van}}}, {{fblu{naar}}}, {{fgre{tussen}}}):
    if ''{{fpur{n}}}'' <= ''{{fpur{1}}}'':
        ''{{fora{print}}}''('Schijf', ''{{fpur{abs(n)}}}'', 'van', {{fred{van}}}, 'naar', {{fblu{naar}}})    
        return 1
    aantal  = __''hanoiQ''__(''{{fpur{n - 1}}}'', {{fred{van}}}   , {{fgre{tussen}}}, {{fblu{naar}}}  )
    aantal += __''hanoiQ''__(''{{fpur{-n}}}''   , {{fred{van}}}   , {{fblu{naar}}}  , {{fgre{tussen}}})
    aantal += __''hanoiQ''__(''{{fpur{n - 1}}}'', {{fgre{tussen}}}, {{fblu{naar}}}  , {{fred{van}}}   )
    return aantal
}}}}}}
''//{{h4 saco{An imaginable (and slower) prototype of hanoiR:}}}//''
{{ib pre{{{_{
def __''hanoiP''__(schijf, ''{{fpur{n}}}'', {{fred{van}}}, {{fblu{naar}}}, {{fgre{tussen}}}, aantal=0):
    if ''{{fpur{n}}}'' <= ''{{fpur{0}}}'':
        if ''{{fpur{n}}}'' == ''{{fpur{0}}}'':
            return aantal
        ''{{fora{print}}}''('Schijf', schijf, 'van', {{fred{van}}}, 'naar', {{fblu{naar}}})
        return aantal + 1
    aantal = __''hanoiP''__(0, ''{{fpur{n - 1}}}'', {{fred{van}}}   , {{fgre{tussen}}}, {{fblu{naar}}}  , aantal)
    aantal = __''hanoiP''__(''{{fpur{n}}}'', ''{{fpur{-1}}}''   , {{fred{van}}}   , {{fblu{naar}}}  , {{fgre{tussen}}}, aantal)
    aantal = __''hanoiP''__(0, ''{{fpur{n - 1}}}'', {{fgre{tussen}}}, {{fblu{naar}}}  , {{fred{van}}}   , aantal)
    return aantal
}}}}}}
}}}
{{lf dn{<<div [=[{{ib xhdn h3 saco{''//One of Theo's __iterative__ Tower of Hanoi algorithms://''&nbsp;}}}{{qup{+++(~FromMultipleRecursionToIteration_Iter)[&darr;|show][&uarr;|hide]
@@position:relative;top:5px;{{ib pre{{{_{
def __hanoiS__(''{{fpur{n}}}'', {{fred{van}}}, {{fblu{naar}}}, {{fgre{tussen}}}):
    aantal = 0
    __''stack''__ = [ ]
    {{byel{mode}}} = {{byel{'s'}}}    //# stack / print//
    __''while True''__:
        if ''{{fpur{n}}}'' == ''{{fpur{1}}}'' or {{byel{mode}}} == {{byel{'p'}}}:
            {{fora{print}}}('Schijf', ''{{fpur{n}}}'', 'van', {{fred{van}}}, 'naar', {{fblu{naar}}})
            aantal += 1
        else:           //# achterstevoren op stack//
            __''stack''__.extend((({{byel{'s'}}}, ''{{fpur{n - 1}}}'', {{fgre{tussen}}}, {{fblu{naar}}}  , {{fred{van}}}   ),
                          ({{byel{'p'}}}, ''{{fpur{n}}}''    , {{fred{van}}}   , {{fblu{naar}}}  , {{fgre{tussen}}}),
                          ({{byel{'s'}}}, ''{{fpur{n - 1}}}'', {{fred{van}}}   , {{fgre{tussen}}}, {{fblu{naar}}}  )))
        if not __''stack''__:
            break
        {{byel{mode}}}, ''{{fpur{n}}}'', {{fred{van}}}, {{fblu{naar}}}, {{fgre{tussen}}} = __''stack''__.pop()
    return aantal
}}}}}}/%

%/@@{{clear block{}}}
===]=]>>/%

%/
{{ib xhdn h3 saco{''//Performance on my laptop when n = 27//''&nbsp;}}}{{qup{+++(~FromMultipleRecursionToIteration_Perf)[&darr;|show][&uarr;|hide]
|sans col1 capl |k
| !Function         | !Elapsed time (average of 3) | !Range size |
|{{tt{hanoi''P''}}} |                          91 s|          2 s|
|{{tt{hanoi''Q''}}} |                          28 s|          1 s|
|{{tt{hanoi''R''}}} |                          41 s|          2 s|
|{{tt{hanoi''S''}}} |                          49 s|          6 s|
{{_{
|plain sans |k
|Number of moves is 2^^//n//^^ &minus; 1                                                             | &rArr; |134 217 727|
|''P:'' number of calls is (2^^//n//^^ &minus; 1 ) &times; 3 + 1                                     | &rArr; |402 653 182|
|''Q:'' number of calls is (2^^//n//&minus;1^^ &minus; 1) &times; 3 + 1                              | &rArr; |201 326 590|
|''R:'' number of calls is (2^^//n//^^ &minus; 1) &times; 2 + 1{{{ }}}={{{ }}}2^^//n//+1^^ &minus; 1 | &rArr; |268 435 455|
|''S:'' number of iterations is (2^^//n//&minus;1^^ &minus; 1) &times; 3 + 1                         | &rArr; |201 326 590|
}}}===
}}}
}}}
''{{up1px sans{<<showPopup tiddler:[[} Iteratie & recursie]] label: "Bundel ↘">>}}}'' <<tiddler [[{}::togglesliders]]>>
!!!Tail recursion, a recipe
[img[<tail recursion>|data/images/Recursion-TailCall-TCO-Iteration.png]]
//Left:// Tail call recursion -- //Center:// Tail call elimination/optimalization -- //Right:// Iteration

{{lf pre{{{_{
''{{rr bbla fwhi{0}}} {{serif{Original}}}''



def ''f(''//{{serif f2m{parameters}}}//'')'':
    //{{f2m{{{u2d d2d rr stix{&alpha;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
    if //{{serif f2m{carry_on}}}//:
        //{{f2m{{{u2d d2d rr stix{&beta;}}}{{serif{-logic}}}}}}//
         {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
        return ''f(''//{{serif f2m{arguments}}}//'')''
    //{{f2m{{{u2d d2d rr stix{&gamma;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
    return //{{serif f2m{expressions}}}//


print(''f(''//{{serif f2m{arguments}}}//'')'')
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{1}}} {{serif{Normalize}}}''



def ''f(''//{{serif f2m{parameters}}}//'')'':
    //{{f2m{{{u2d d2d rr stix{&alpha;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
{{b2p{
    if ''//{{fred serif{stop}}}//'':
        //{{f2m{{{u2d d2d rr stix{&gamma;}}}{{serif{-logic}}}}}}//
         {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
        return //{{serif f2m{expressions  }}}//
    //{{f2m{{{u2d d2d rr stix{&beta;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
    return ''f(''//{{serif f2m{arguments}}}//'')'' 
}}}

print(''f(''//{{serif f2m{arguments}}}//'')'')
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{2}}} {{serif{Globalize}}}''

''//{{fred{{{serif{global logic}}}}}}//''

def ''f{{fred{()}}}'':
    //{{f2m{{{u2d d2d rr stix{&alpha;}}}{{serif{-logic with}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}''{{fred{{{serif{   //results//}}} =}}}'' //{{serif f2m{expressions  }}}//
{{b2p{
    if ''//{{fora serif{stop}}}//'':
        //{{f2m{{{u2d d2d rr stix{&gamma;}}}{{serif{-logic with}}}}}}//
         {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}''{{fred{{{serif{   //results//}}} =}}}'' //{{serif f2m{expressions  }}}//
        return ''{{fred{//{{serif{ nothing}}}//}}}'' 
    //{{f2m{{{u2d d2d rr stix{&beta;}}}{{serif{-logic with}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}''{{fred{{{serif{   //results//}}} =}}}'' //{{serif f2m{arguments  }}}//
    return ''{{fred{f()}}}''
}}}
''{{fred{f()}}}''
print(''//{{serif fred{results}}}//'')
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{3}}} {{serif{Flatten}}}''

''//{{fora{{{serif{global logic}}}}}}//''

''{{fred{while True}}}'':
    //{{f2m{{{u2d d2d rr stix{&alpha;}}}{{serif{-logic with}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}''{{fora{{{serif{   //results//}}} =}}}'' //{{serif f2m{expressions  }}}//
{{b2p{
    if ''//{{fora serif{stop}}}//'':
        //{{f2m{{{u2d d2d rr stix{&gamma;}}}{{serif{-logic with}}}}}}//
         {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}''{{fora{{{serif{   //results//}}} =}}}'' //{{serif f2m{expressions  }}}//
        ''{{fred{break}}}''
    //{{f2m{{{u2d d2d rr stix{&beta;}}}{{serif{-logic with}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}''{{fora{{{serif{   //results//}}} =}}}'' //{{serif f2m{arguments  }}}//
    ''//@@color:#ff9999;{{serif{(no operation)}}}@@//''
}}}
''//@@color:#ffbbbb;{{serif{(no operation)}}}@@//''
print(''//{{serif fora{results}}}//'')
}}}}}}{{mlqem lf pre{
''{{rr bbla fwhi{4}}} {{serif{Simplify}}}''

//{{serif{Mobilize your craftsmanship ...}}}//
}}}{{clear block{}}}/%


%/+++(~Journal20231217_Example)!!![Example &darr;|show][Example &uarr;|hide]
{{lf pre{{{_{
''{{rr bbla fwhi{0}}} {{serif{Original, already normalized}}}''

def ''f(''n, fac=1, i=1'')'':
    if i > n:
        return fac
    return ''f(''n, fac*i, i+1'')''

print(''f(''5'')'')
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{2}}} {{serif{Globalize}}}'' +++(~Journal20231217_2)[&darr;|show][&uarr;|hide]
&nbsp;
''{{fred{n = 5}}}''

def ''f{{fred{()}}}'':
''{{fred{    global n,{{serif{ }}}fac,{{serif{ }}}i,{{serif{ }}}result
    try: fac
    except:}}}'' fac = 1
''{{fred{    try: i
    except:}}}'' i = 1
    if i > n:
''{{fred{        result =}}}'' fac
        return ''{{fred{None
    n   =}}}'' n
    ''{{fred{fac =}}}'' fac * i
    ''{{fred{i   =}}}'' i + 1
    return ''{{fred{f()

f()}}}''
print(''{{fred{result}}}'')
===
}}}}}}{{lf mlqem pre{{{_{
''{{rr bbla fwhi{3}}} {{serif{Flatten}}}'' +++(~Journal20231217_3)[&darr;|show][&uarr;|hide]
&nbsp;
''{{fora{n = 5}}}''

''{{fred{while True}}}'':
''@@color:#ffbbbb;    #{{serif{ }}}(no{{serif{ }}}declaration)@@''
''{{fora{    try: fac
    except:}}}'' fac = 1
''{{fora{    try: i
    except:}}}'' i = 1
    if i > n:
''{{fora{        result =}}}'' fac
''{{fred{        break}}}''
''{{fora{    n   =}}}'' n
''{{fora{    fac =}}}'' fac * i
''{{fora{    i   =}}}'' i + 1
''@@color:#ffbbbb;    pass

pass@@''
print(''{{fora{result}}}'')
===
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{4//a//}}} {{serif{Simplify}}}'' +++(~Journal20231217_4a)[&darr;|show][&uarr;|hide]
&nbsp;
''{{fora{n   = 5}}}''
''{{b2p fred{fac = 1
i   = 1}}}''

''{{fora{while True:}}}''
    if i > n:
''{{fora{        break}}}''
''{{fora{    fac =}}}'' fac * i
''{{fora{    i   =}}}'' i + 1

print(''{{b2p fred{fac}}}'')
===
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{4//b//}}} {{serif{Simplify again}}}'' +++(~Journal20231217_4b)[&darr;|show][&uarr;|hide]
&nbsp;
''{{b2p fred{fac = i = 1}}}''

''{{fora{while {{b2p fred{i <= 5}}}:}}}''
''{{fora{    fac {{fred{*}}}=}}}'' i
''{{fora{    i   {{fred{+}}}=}}}'' 1

print(''{{b2p fora{fac}}}'')
===
}}}}}}{{clear block{}}}
===/%


%/+++(~Journal20231217_Nontailcall)!!![Non-tail recursion, a more extensive recipe &darr;|show][Non-tail recursion, a more extensive recipe &uarr;|hide]
[img[<tail recursion>|data/images/Recursion-TailCall-NonTailCall.png]]
{{lift{//Left:// Tail call recursion -- //Right:// Non-tail call recursion}}}
{{lf pre{{{_{
''{{rr bbla fwhi{0}}} {{serif{Normalized}}}''

def ''f(''//{{serif f2m{parameters}}}//'')'':
    //{{f2m{{{u2d d2d rr stix{&alpha;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
    if {{serif f2m{//stop//}}}:
        //{{f2m{{{u2d d2d rr stix{&gamma;}}}{{serif{-logic}}}}}}//
         {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
        return //{{serif f2m{expressions}}}//
    //{{f2m{{{u2d d2d rr stix{&beta;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
{{b2p{
    {{f2m{//{{u2d d2d rr stix{&delta;}}}{{serif{-logic}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}{{serif{   //calls//  }}}''{{tt fbla{f}}}''//{{serif{  at start, or}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}{{serif{   //defers it to// {{tt fbla{return}}}}}}}}}
    return //{{serif f2m{{{stix{&phi;}}}&#x200a;( }}}//{{hi2 u2s d2s r{''f''//{{serif f2m{ ,}}}//}}}//{{serif f2m{&deg;  expressions&#x200a;)}}}// 
}}}
print(''f(''//{{serif f2m{arguments}}}//'')'')
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{{{h3 sy n{&#x05d0;}}}}}} {{serif{Disentangle}}}''

def ''f(''//{{serif f2m{parameters}}}//'')'':
    //{{f2m{{{u2d d2d rr stix{&alpha;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
    if {{serif f2m{//stop//}}}:
        //{{f2m{{{u2d d2d rr stix{&gamma;}}}{{serif{-logic}}}}}}//
         {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
        return //{{serif f2m{expressions}}}//
    //{{f2m{{{u2d d2d rr stix{&beta;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
 {{zi10 h3{{{hdn{@@color:#ff9999;&#x21b1;@@}}}}}}   ''{{fred{//{{serif{results}}}// =}}} f(''//{{serif f2m{arguments}}}//'')''
{{b2p{
    {{f2m{//{{u2d d2d rr stix{&delta;}}}{{serif{-logic}}}//}}}
    {{fred{''//{{serif{results}}}// = //{{stix{&chi;}}}({{serif{{{n f2m{expressions}}}&#x200a;, results)  }}}//''}}}
}}} {{zi10 h3{{{hup{@@color:#ff9999;&#x21b3;@@}}}}}}   return ''//{{fred serif{results}}}//''

print(''f(''//{{serif f2m{arguments}}}//'')'')
}}}}}}{{mlqem lf pre{{{_{
{{rr bbla fwhi{{{h3 sy n{&#x05d1;}}}}}} ''{{serif{Reshuffle}}}''

def ''f(''//{{serif f2m{parameters}}}//''{{fred{, //{{serif{result}}}//={{serif{//init//}}},{{serif{&#x200a;&middot;&middot;&middot;}}}}}})'':
    //{{f2m{{{u2d d2d rr stix{&alpha;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
    if {{serif f2m{//stop//}}}:
        //{{f2m{{{u2d d2d rr stix{&gamma;}}}{{serif{-logic}}}}}}//
        ''{{fred{//{{serif{results}}}// = //{{stix{&psi;}}}({{hi u2 d2 r{{{serif n f2m{expressions{{fred{&#x200a;'',''}}}}}}}}}{{n{&deg;}}}{{serif{ results)}}}//}}}''
        return ''//{{fred serif{results}}}//''
    //{{f2m{{{u2d d2d rr stix{&beta;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
|wfull plain pref |k
|bgcolor:#ffdddd;&nbsp;   {{f2m{//{{u2d d2d rr stix{&delta;}}}{{serif{-logic}}}//}}} |
|bgcolor:#ffdddd;&nbsp;   {{fora{''//{{serif{results}}}// = //{{stix{&chi;}}}({{serif{{{n f2m{expressions}}}&#x200a;, results)  }}}//''}}} |
{{zi10 h3{@@color:#ff9999;&uarr;{{qup back serif{ """__"""}}}@@}}}    ''{{fora{//{{serif{results}}}// =}}} f(//{{serif n f2m{arguments}}}//{{fred{,//{{serif{ results}}}//}}})''
    return ''//{{fora serif{results}}}//''

print(''f(''//{{serif f2m{arguments}}}//'')'')
}}}}}}{{mlqem lf pre{{{_{
{{rr bbla fwhi{{{h3 sy n{&#x05d2;}}}}}} ''{{serif{Move call to tail}}}''

def ''f(''//{{serif f2m{parameters}}}//''{{fora{, //{{serif{result}}}//={{serif{//init//}}},{{serif{&#x200a;&middot;&middot;&middot;}}}}}})'':
    //{{f2m{{{u2d d2d rr stix{&alpha;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
    if {{serif f2m{//stop//}}}:
        //{{f2m{{{u2d d2d rr stix{&gamma;}}}{{serif{-logic}}}}}}//
        ''{{fora{//{{serif{results}}}// = //{{stix{&psi;}}}({{hi u2 d2 r{{{serif n f2m{expressions{{fora{&#x200a;//,//}}}}}}}}}{{n{&deg;}}}{{serif{ results)}}}//}}}''
        return ''//{{fora serif{results}}}//''
    //{{f2m{{{u2d d2d rr stix{&beta;}}}{{serif{-logic}}}}}}//
     {{w qdn{{{h3w sy f2m{&#x205d;}}}}}}
|wfull plain pref |k
|bgcolor:#ffeecc;&nbsp;   {{f2m{//{{u2d d2d rr stix{&delta;}}}{{serif{-logic}}}//}}} |
|bgcolor:#ffeecc;&nbsp;   {{fora{''//{{serif{results}}}// = //{{stix{&chi;}}}({{serif{{{n f2m{expressions}}}&#x200a;, results)  }}}//''}}} |

    return @@border:solid red 1px;{{hws{''f(//{{serif n f2m{arguments}}}//{{fora{,//{{serif{ results}}}//}}})''}}}@@{{zi10 h1 sans{{{up{{{qup{@@color:#ff9999;&#x21a9;@@}}}}}}}}}

print(''f(''//{{serif f2m{arguments}}}//'')'')
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{2}}} {{serif{Globalize}}}

{{rr bbla fwhi{3}}} {{serif{Flatten}}}

{{rr bbla fwhi{4}}} {{serif{Simplify}}}''

}}}}}}{{clear block{}}}
===/%


%/+++(~Journal20231217_Example2)!!![Example &darr;|show][Example &uarr;|hide]
{{lf pre{{{_{
''{{rr bbla fwhi{0}}} {{serif{Original, 
         already normalized}}}''

def ''f(''n'')'':
    if n <= 1:
        return 1
{{b2p{
    return n * ''f(''n-1'')''
}}}
print(''f(''5'')'')
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{{{h3 sy n{&#x05d0;}}}}}} {{serif{Disentangle}}}'' +++(~Journal20231217_Aleph)[&darr;|show][&uarr;|hide]
&nbsp;
def ''f(''n'')'':
    if n <= 1:
        return 1
 {{zi10 h3{{{hdn{@@color:#ff9999;&#x21b1;@@}}}}}}   ''{{fred{fac =}}}'' ''f(''n-1'')''
{{b2p{
    ''{{fred{fac =}}}'' n * ''{{fred{fac}}}'' 
}}} {{zi10 h3{{{hup {@@color:#ff9999;&#x21b3;@@}}}}}}   return ''{{fred{fac}}}'' 

print(''f(''5'')'')
===
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{{{h3 sy n{&#x05d1;}}}}}} {{serif{Reshuffle}}}'' +++(~Journal20231217_Beth)[&darr;|show][&uarr;|hide]
&nbsp;
def ''f(''n''{{fred{, fac=1}}})'':
    if n <= 1:
        ''{{fred{fac = fac}}}''
        return ''{{fred{fac}}}''
|full plain pref |k
|bgcolor:#ffdddd;&nbsp;   ''{{fora{fac =}}}'' n * ''{{fora{fac}}}'' |
{{zi10 h3{@@color:#ff9999;&uarr;{{qup back serif{ _}}}@@}}}    ''{{fora{fac =}}}'' ''f(''n-1''{{fred{, fac}}})''
    return ''{{fora{fac}}}''

print(''f(''5'')'')
===
}}}}}}{{mlqem lf{
{{pre{
{{_{
''{{rr bbla fwhi{{{h3 sy n{&#x05d2;}}}}}} {{serif{Move call to tail}}}'' +++(~Journal20231217_Gimel)[&darr;|show][&uarr;|hide]
&nbsp;
def ''f(''n''{{fora{, fac=1}}})'':
    if n <= 1:
        ''{{fora{fac = fac}}}''
        return ''{{fora{fac}}}''
|wfull plain pref |k
|bgcolor:#ffeecc;&nbsp;   ''{{fora{fac =}}}'' n * ''{{fora{fac}}}'' |
    return{{serif{ &#x2009;}}}@@border:solid red 1px;{{hws{''f(''n-1''{{fora{,{{serif{ }}}fac}}})''}}}@@

print(''f(''5'')'')
===
}}}}}}<br>}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{2}}} {{serif{Globalize}}}'' +++(~Journal20231217_Two)[&darr;|show][&uarr;|hide]
&nbsp;
''{{fred{n = 5}}}''

def ''{{fred{f()}}}'':
''{{fred{    global n,{{serif{ }}}fac,{{serif{ }}}result
    try: fac
    except:}}}'' fac = 1
    if n <= 1:
        ''{{fora{fac    = fac}}}''
        ''{{fred{result =}}}'' fac
        return ''{{fred{None}}}''
|wfull plain pref |k
|bgcolor:#ffeecc;&nbsp;   ''{{fora{fac =}}}'' n * ''{{fora{fac}}}'' |
    ''{{fred{n   =}}}'' n - 1
    ''{{fred{fac =}}}'' fac
    return{{serif{ &#x2009;}}}@@border:solid gold 1px;{{hws{''{{fred{f()}}}''}}}@@

''{{fred{f()}}}''
print(''{{fred{result}}}'')
===
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{3}}} {{serif{Flatten}}}'' +++(~Journal20231217_Three)[&darr;|show][&uarr;|hide]
&nbsp;
''{{fora{n = 5}}}''

''{{fred{while True}}}'':
''@@color:#ffbbbb;    #{{serif{ }}}(no{{serif{ }}}declaration)@@''
''{{fora{    try: fac
    except:}}}'' fac = 1
    if n <= 1:
        ''{{fora{fac    = fac}}}''
        ''{{fora{result =}}}'' fac
        ''{{fred{break}}}''
|wfull plain pref |k
|bgcolor:#ffeecc;&nbsp;   ''{{fora{fac =}}}'' n * ''{{fora{fac}}}'' |
    ''{{fora{n   =}}}'' n - 1
    ''{{fora{fac =}}}'' fac
   {{serif{&#x2005;}}}''@@border:solid gold 1px;color:#ffbbbb;{{hws{pass}}}@@

@@color:#ffbbbb;pass@@''
print(''{{fora{result}}}'')
===
}}}}}}{{mlqem lf pre{{{_{
''{{rr bbla fwhi{4}}} {{serif{Simplify}}}'' +++(~Journal20231217_Four)[&darr;|show][&uarr;|hide]
&nbsp;
''{{fora{n   = 5}}}
{{fred{fac = 1}}}''

''{{fora{while {{fred{n > 1}}}}}}'':
|plain |k
|bgcolor:#ffeecc;&nbsp;   ''{{fora{fac {{fred{*}}}=}}}'' n&nbsp; |
    ''{{fora{n   {{fred{-}}}=}}}'' 1

print(''{{fred{fac}}}'')
===
}}}}}}{{clear block{}}}
===
!!!!!Lettertype {{n{(font-family, font-style, font-weight)}}}
*@@font-size:1.1em;font-family:serif;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //serif// (''bold, //bolditalic//'')@@
*@@font-size:1.1em;font-family:sans-serif;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //sans-serif// (''bold, //bolditalic//'')@@
*@@font-size:1.1em;font-family:monospace;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //monospace// (''bold, //bolditalic//'')@@
*@@font-size:1.1em;font-family:cursive;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //cursive// (''bold, //bolditalic//'')@@
*@@font-size:1.1em;font-family:fantasy;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //fantasy// (''bold, //bolditalic//'')@@
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Vervolg op [[Zichtbaarheid van Python-variabelen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Zichtbaarheid van Python-variabelen]] label: "Bundel ↘">>}}}''
!!Inleiding
<<tiddler [[{}::togglesliders]]>> In deze uiteenzetting heb ik niet alle programmalistings en -uitvoer opgenomen. Het leek me in een aantal gevallen beter alleen de kernpunten van de onderhavige programma's en hun verwerking in kaart te brengen. De programma's zelf zijn allemaal wel [[beschikbaar|Python-scopescripts (downloads)]].

Ik zal eenvoudig beginnen. Het testprogramma {{sans t{use-justthat.py}}} importeert de module {{tt t{justthat}}}, een eenregelig bestandje {{sans t{justthat.py}}} met slechts één statement: ''{{pref hitt z{justthat_globals = globals()}}}''. De uitvoer van dit programma laat het volgende zien:
* de naam van het hoofdprogramma (opgeslagen in de globale variabele {{tt t{"""__name__"""}}}) krijgt automatisch de waarde ''{{hitt z{""""__main__""""}}}'' (dat geldt per definitie voor elk hoofdprogramma)
* de naam van de geïmporteerde module (vanuit het hoofdprogramma te verkrijgen via {{tt t{justthat."""__name__"""}}}) krijgt automatisch de waarde ''{{hitt z{"justthat"}}}''
* {{tt t{justthat.justthat_globals}}} verwijst naar dezelfde dictionary als {{tt t{justthat."""__dict__"""}}}
* {{tt t{"""__builtins__"""}}} verwijst naar een ingebouwde module met de naam ''{{hitt z{"builtins"}}}''
* {{tt t{"""justthat.__builtins__"""}}} verwijst naar dezelfde dictionary als {{tt t{"""__builtins__.__dict__"""}}}
Dat het gegevenstype van de globale variabele {{tt t{"""__builtins__"""}}} afhangt van de context waarin de module draait, als hoofdprogramma of als geïmporteerde code, vind ik wel verrassend. Behalve in +++(~Python___builtins__)[twee one-liners &darr;|show][twee one-liners &uarr;|hide]
:{{z{Het programmaatje {{sans t{print"""__builtins__class.py"""}}} met inhoud ''{{pref hitt z{print("""__builtins__""")}}}'' print {{hitt{<class 'module'>}}} en het programmaatje {{pref sans t{use-print"""__builtins__class.py"""}}} met inhoud ''{{pref hitt z{import """print__builtins__class"""}}}'' print {{hitt{<class 'dict'>}}}.}}}
=== is dit in de programma's {{sans t{main.py}}} en {{pref sans t{use-main.py}}} (zie verderop) ook nog eens zichtbaar gemaakt./%

%/
!!Modules nesten
Voor mijn eerste experiment met geneste modules had ik er vier gecreëerd die elkaar op de volgende manier importeren (de Romeinse cijfers geven de volgorde van imports binnen een module aan):

{{ml3em hdn{[img[data/images/Python-modules-importing.png]]}}}

De essentie van hun inhoud is in onderstaande tabel samengevat:
|tt |k
| !module0.py | !module1.py | !module2.py | !module3.py |
|n0 = ''0''<br>import ''module1'' |n1 = ''10''<br>import ''module0''<br>module0.n0 += 1<br>import ''module2''<br>import ''module3'' |n2 = ''20''<br>import ''module2''<br>module2.n2 += 1<br>import ''module3'' |n3 = ''30'' |

Achtereenvolgens heb ik {{sans t{module{{{0}}}.py}}}, {{sans t{module1.py}}} en {{sans t{module2.py}}} vanaf de console aangeroepen. Wat zich dan afspeelt, is in respectievelijk het linker, middelste en rechter schema weergegeven:

{{ml3em hdn{[img[data/images/Python-modules-running.png]]}}}

Bevindingen bij de run van {{sans t{module{{{0}}}.py}}}:
* Bij de import van {{tt t{module0}}} binnen {{tt t{module1}}} wordt {{tt t{module0}}} nog eens geactiveerd.
* Bij de import van {{tt t{module1}}} binnen de door {{tt t{module1}}} geïmporteerde en geactiveerde {{tt t{module0}}} wordt {{sans t{module1}}} niet meer geactiveerd.
* Evenzo wordt {{tt t{module2}}} slecht één keer geactiveerd, de zelfimport leidt niet tot heractivering.
* Het statement ''{{pref hitt z{module2.n2 += 1}}}'' in {{sans t{module2}}} heeft hetzelfde effect als wanneer er ''{{pref hitt z{n2 += 1}}}'' had gestaan.
* De import van {{tt t{module3}}} door {{tt t{module1}}}, die plaatsvindt nadat {{tt t{module3}}} reeds door de in {{tt t{module1}}} geneste {{tt t{module2}}} geïmporteerd en geactiveerd was, leidt niet tot heractivering van {{tt t{module3}}}. 
/%

%/Bevindingen bij de run van {{sans t{module1.py}}}:
* Bij de import van {{tt t{module1}}} binnen {{tt t{module0}}} wordt {{tt t{module1}}} nog eens geactiveerd.
* Bij de import van {{tt t{module0}}} binnen de door {{tt t{module0}}} geïmporteerde en geactiveerde {{tt t{module1}}} wordt {{sans t{module0}}} niet meer geactiveerd.
* De ophoging ''{{pref hitt z{module0.n0 += 1}}}'' door de door {{tt t{module0}}} geïmporteerde geactiveerde {{tt t{module1}}} en vervolgens nog eens door de als hoofdprogramma draaiende {{tt t{module1}}} heeft inderdaad het effect dat {{tt t{n0}}} in {{tt t{module0}}} van beginwaarde {{tt t{0}}} op waarde {{tt t{2}}} uitkomt.
* Wat {{tt t{module2}}} en {{tt t{module3}}} betreft dezelfde twee bevindingen als genoemd bij de run van {{sans t{module{{{0}}}.py}}}.
/%

%/Bevindingen bij de run van {{sans t{module2.py}}}:
* Anders dan bij de runs van {{sans t{module{{{0}}}.py}}} en {{sans t{module1.py}}} wordt {{tt t{module2}}} nu wel geactiveerd bij het importeren vanuit de als hoofdprogramma draaiende {{tt t{module2}}}. De module draait dus twee keer, als hoofdprogramma en vervolgens als geïmporteerde module.
* Bij import vanuit de geïmporteerde {{tt t{module2}}} wordt {{tt t{module2}}} echter niet meer geactiveerd.
* Omdat {{tt t{module2}}} twee keer wordt uitgevoerd, geldt dat ook voor het ingesloten statement ''{{pref hitt z{module2.n2 += 1}}}''. De beginwaarde {{tt t{20}}} van {{tt t{module2.n2}}} groeit dus via {{tt t{21}}} aan tot {{tt t{22}}}. Maar de {{tt t{n2}}} in het hoofdprogramma wordt niet geraakt, die blijft {{tt t{20}}}.
/%

%/Het algemene patroon hierin is, dat een een via {{pref hitt z{''import'' //mod//}}} geïmporteerde module {{tt t{//mod//}}} alleen bij de eerste import wordt geladen en geactiveerd (dat laatste betekent dat de erin besloten programmacode wordt uitgevoerd). Bij elke volgende import worden alleen de tijdens die activering ontstane gegevensobjecten van {{tt t{//mod//}}} bereikbaar gemaakt voor de importerende module. Bereikbaar voor raadpleeg-, wijzig-, aanmaak- en verwijder&shy;operaties.

Dit patroon gaat evenzeer op voor import via {{pref hitt z{''from'' //mod// ''import'' //var//}}}. Bij de beslissing 'laden en activeren, of niet?' geldt dat het antwoord bij het eerste voorkomen van een van de {{tt t{import}}}- of {{tt t{from}}}-statements 'ja' is, en bij ieder volgend van een van beide m.b.t. dezelfde module 'nee':
{{lf{

|tt |k
| !use-module3.py                                            |
|from module3 import n3<br>n3 -= 1<br>import module3<br>module3.n3 += 1 |
}}}{{lf{

{{ml3em hdn{[img[data/images/Python-use-module3.png]]}}}

}}}{{clear block lift{Maar hoe komt het nu dat in alle drie de scenario's het hoofdprogramma een module die op dezelfde broncode is gebaseerd toch laadt en activeert? Om dat inzichtelijk te maken heb ik een variant op {{sans t{module2.py}}} gebouwd in de vorm van {{sans t{+++(~Python_omweg2)[module4.py &darr;|show][module4.py &uarr;|hide]
{{serif n{{{lf w55pct n pre{
{{fgre{"""# Script: module4.py
# Date  : 2023-07-04, Meindert Meindertsma"""}}}
"""
print()
print(__name__, "activated")

import sys
this = sys.modules[__name__]
print("id(this) =", id(this), "-- this.__name__ =", this.__name__)

"""''import module4''"""
that = module4.this

print()
print("__name__ =", __name__)
print("id(this) =", id(this), "-- this.__name__ =", this.__name__)
print("id(that) =", id(that), "-- that.__name__ =", that.__name__)

print()
print(__name__, "ends")"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w40pct{{{pre{
''Uitvoer''
"""
__main__ activated
id(this) = 1603626612064 -- this.__name__ = __main__

module4 activated
id(this) = 1603628770752 -- this.__name__ = module4

__name__ = module4
id(this) = 1603628770752 -- this.__name__ = module4
id(that) = 1603628770752 -- that.__name__ = module4

module4 ends

__name__ = __main__
id(this) = 1603626612064 -- this.__name__ = __main__
id(that) = 1603628770752 -- that.__name__ = module4

__main__ ends"""
}}}}}}{{clear block{}}}}}}
===}}}, die alleen rapporteert over de identiteit van de actuele of beëindigde programmatuur. Daaruit blijkt dat deze wijze van importeren van de broncode van {{sans t{module4.py}}} een ander Python-object oplevert dan het omvattende hoofdprogramma.}}}/%


%/<<div [=[!!De module {{{__main___}}} nesten
Import van de module {{tt t{"""__main__"""}}} geeft een nogal ander beeld te zien. Deze naam verwijst in een {{tt t{import}}}- of {{tt t{from}}}-statement namelijk altijd naar het hoofdprogramma, ongeacht of dit statement in het hoofdprogramma of in een andere module voorkomt. Ja, zelfs als er een bestand {{sans t{"""__main__.py"""}}} op het zoekpad voor modules ligt, wordt de aanwezigheid ervan straal genegeerd. Onderstaande toepassingen van {{sans t{main.py}}} en {{pref sans t{use-main.py}}} laten zien wat voor effect zo'n import heeft:]=]>>/%
%/
{{ml3em hdn{[img[data/images/Python-main-running.png]]}}}

Aanvankelijk had ik het zichzelf importerende {{tt t{main.py}}} alleen als hoofdprogramma in gedachten, om te laten zien dat het {{tt t{import}}}-statement nu niet tot een tweede activering van {{tt t{"""__main__"""}}} leidt en dat ''{{pref hitt z{"""__main___.n += 1"""}}}'' de waarde {{tt t{100}}} van {{tt t{n}}} ophoogt tot {{tt t{101}}}. Terwijl {{sans t{module4.py}}} dezelfde broncode //wel// tweemaal laadt en activeert (als twee //verschillende// objecten), is in {{sans t{main.py}}} de geïmporteerde {{tt t{"""__main__"""}}} echt het hoofdprogramma zelf. Dat hoeft daarom niet meer te worden geladen en uitgevoerd.

Wanneer {{tt t{main}}} wordt geïmporteerd in {{sans t{use-main.py}}}, wordt {{tt t{"""__main__"""}}} evenmin binnen {{tt t{main}}} geactiveerd, omdat het hoofdprogramma waar het naar verwijst al draait. Met als gevolg dat {{tt t{"""__main__""".n}}} niet meer de variabele {{tt t{n}}} in {{tt t{main}}} aanduidt, maar de gelijknamige variabele in het hoofdprogramma zoals gecodeerd in {{pref sans t{use-main.py}}}. Die {{tt t{n}}} was gelijk aan {{tt t{0}}} en wordt dus {{tt t{1}}}. We zien bovendien nog eens dat de variabele {{tt t{"""__builtins__"""}}} binnen {{tt t{main}}} in deze context een andere betekenis heeft gekregen, zoals ik in de inleiding bij de behandeling van {{sans t{justthat.py}}} en {{pref sans t{use-justthat.py}}} al besproken heb./%

%/
!!Modules nesten in een functie
Een {{tt t{import}}}- of {{tt t{from}}}-statement binnen een functie zorgt voor nieuwe (of vernieuwde) lokale variabelen binnen die functie in plaats van globale variabelen op moduleniveau. Geïmplementeerd in {{sans t{use-module3-in-function.py}}}, draagt beproeving van deze constructie verder geen nieuwe inzichten aan./%

%/
+++(~Python_ModulesCreerenBinnenPrograma)!![Modules creëren binnen een programma &darr;|show][Modules creëren binnen een programma &uarr;|hide]
We kennen het fenomeen //Python-module// als een bestand met Python-programmacode dat door een een andere Python-module of een in Python geschreven hoofdprogramma in het werkgeheugen kan worden geladen en vervolgens worden uitgevoerd. Het is echter tevens mogelijk een module binnen een bestaand programma te definiëren zonder dat daar een afzonderlijk bestand aan te pas komt. Technisch gesproken is een module in Python niet meer dan een object van de class {{tt t{module}}}, dat volgens het gebruikelijke patroon via de constructor van {{tt t{module}}} zou moeten kunnen woren geïnstantieerd. Dat is inderdaad het geval: ik heb zoiets geïmplementeerd in ondermeer het programma {{sans t{inner.py}}}. Dit is een globale schets van de opstelling:

{{ml3em hdn{[img[data/images/Python-module-inner.png]]}}}

en dit is de programmacode:
{{lf w50pct pre{
{{fgre{"""# Script: inner.py
# Date  : 2023-07-06, Meindert Meindertsma"""}}}

import types


{{fgre{"""#---- Create inline module "inner" ----#"""}}}"""
def inner():
    """''self = types.ModuleType("inner")''"""    """{{fgre{# new module instance}}}"""

    self.aleph = 42             """{{fgre{# an integer}}}"""

    def builtins():             """{{fgre{# a function}}}"""
        return __builtins__     """{{fgre{# returning a global variable}}}"""
    self.builtins = builtins

    def update():               """{{fgre{# a pseudomethod}}}"""
        self.aleph += 1
        return self.aleph
    self.update = update

    def create():               """{{fgre{# a pseudomethod}}}"""
        self.zero = 0
        return self.zero
    self.create = create

    def delete():               """{{fgre{# a pseudomethod}}}"""
        del self.aleph
        return repr(f"{self.__name__}.aleph deleted")
    self.delete = delete

    return self                 """{{fgre{# the whole module}}}"""
inner = inner()

"""
{{fgre{"""#---- Operate under a false name from now on ----#"""}}}"""
inside = inner
del inner

print("inside            =", inside, "--", id(inside))
print("inside.aleph      =", inside.aleph)
print("inside.update()   =", inside.update())
print("inside.create()   =", inside.create())
print("inside.delete()   =", inside.delete())
print("inside.builtins() =", inside.builtins())
inside.__name__ = "inside"
print("inside            =", inside, "--", id(inside))

print("\ninside.__dict__:")
for k, v in inside.__dict__.items():
    if k != "__builtins__":
        print(f"    {k:11s}   = {v}")

print("\ninside.builtins:")
print("    __name__      =", inside.builtins.__name__)
print("    __qualname__  =", inside.builtins.__qualname__)
print("    __module__    =", inside.builtins.__module__)"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w45pct{{{pre{
''Uitvoer''
"""
inside            = <module 'inner'> -- 2326080071664
inside.aleph      = 42
inside.update()   = 43
inside.create()   = 0
inside.delete()   = 'inner.aleph deleted'
inside.builtins() = <module 'builtins' (built-in)>
inside            = <module 'inside'> -- 2326080071664

inside.__dict__:
    __name__      = inside
    __doc__       = None
    __package__   = None
    __loader__    = None
    __spec__      = None
    builtins      = <function inner.<locals>.builtins at 0x0000021D952D9760>
    update        = <function inner.<locals>.update at 0x0000021D952DA700>
    create        = <function inner.<locals>.create at 0x0000021D952DA7A0>
    delete        = <function inner.<locals>.delete at 0x0000021D952DA840>
    zero          = 0

inside.builtins:
    __name__      = builtins
    __qualname__  = inner.<locals>.builtins
    __module__    = __main__"""
}}}Het aanleggen van passieve attributen zoals {{tt t{alpha}}} is een koud kunstje: het rechttoe-rechtaan statement ''{{pref hitt z{inner.alpha = 42}}}'' zou al volstaan. Het construeren van callables is lastiger, als je wilt dat die callables de module kennen waarin ze zijn opgenomen. Er zijn verschillende manieren om dit op te lossen. Ik heb er in {{sans t{inner.py}}} voor gekozen de module en al haar attributen te definiëren in een closure {{tt t{inner}}} waarin de module zelf bereikbaar is via de lokale variabele {{tt t{self}}}. Aan het eind van alle definities wordt de closure via de aanroep ''{{pref hitt z{inner = inner()}}}'' omgezet naar een module. De syntactische beperkingen van Python noopten me telkens eerst via het {{tt t{def}}}-statement de functie of pseudo&shy;method op closureniveau te definiëren en deze dan vervolgens via een toekenningsstatement in de beoogde module onder te brengen (alleen bij lambda's is deze omweg niet nodig). Te overwegen valt de functie- of pseudo&shy;method&shy;namen op closure&shy;niveau via een {{tt t{del}}}-statement weer te verwijderen. De closure&shy;variable {{tt t{self}}} moet na de uitvoering van {{tt t{inner}}} echter blijven bestaan.

Een 'pseudomethod' is technisch gezien niets anders dan een gewone Python-functie. Het enige verschil is dat de functie&shy;definitie een verwijzing naar {{tt t{self}}} bevat. Het verschil met 'echte' Python-methods is, dat {{tt t{self}}} geen parameter van de callable is.

Dit is een robuuste oplossing, in de zin dat naams&shy;wijziging van de module de verbinding van de pseudo&shy;methods met de module niet verbreekt.}}}{{clear block{}}}/%
%/
Hieronder een variant op dit model:
{{lf w50pct pre{
{{fgre{"""# Script: inner-with-renamed-functions.py
# Date  : 2023-07-06, Meindert Meindertsma"""}}}

import types


{{fgre{"""#---- Create inline module "inner" ----#"""}}}"""
def _():
    """''self = types.ModuleType("inner")''"""    """{{fgre{# new module instance}}}"""

    self.aleph = 42             """{{fgre{# an integer}}}"""
"""
''    def rename(name):
        """_.__qualname__""" = "inner." + name
        return _''
"""
    def _():                    """{{fgre{# a function}}}"""
        return __builtins__     """{{fgre{# returning a global variable}}}"""
    self.builtins = """''rename''"""("builtins")

    def _():                    """{{fgre{# a pseudomethod}}}"""
        self.aleph += 1
        return self.aleph
    self.update = """''rename''"""("update")

    def _():                    """{{fgre{# a pseudomethod}}}"""
        self.zero = 0
        return self.zero
    self.create = """''rename''"""("create")

    def _():                    """{{fgre{# a pseudomethod}}}"""
        del self.aleph
        return repr(f"{self.__name__}.aleph deleted")
    self.delete = """''rename''"""("delete")

    return self                 """{{fgre{# the whole module}}}"""
inner = _()

"""
{{fgre{"""#---- Operate under a false name from now on ----#"""}}}"""
inside = inner
del inner

print("inside            =", inside, "--", id(inside))
print("inside.aleph      =", inside.aleph)
print("inside.update()   =", inside.update())
print("inside.create()   =", inside.create())
print("inside.delete()   =", inside.delete())
print("inside.builtins() =", inside.builtins())
inside.__name__ = "inside"
print("inside            =", inside, "--", id(inside))

print("\ninside.__dict__:")
for k, v in inside.__dict__.items():
    if k != "__builtins__":
        print(f"    {k:11s}   = {v}")

print("\ninside.builtins:")
print("    __name__      =", inside.builtins.__name__)
print("    __qualname__  =", inside.builtins.__qualname__)
print("    __module__    =", inside.builtins.__module__)"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w45pct{{{pre{
''Uitvoer''
"""
inside            = <module 'inner'> -- 1996241053520
inside.aleph      = 42
inside.update()   = 43
inside.create()   = 0
inside.delete()   = 'inner.aleph deleted'
inside.builtins() = <module 'builtins' (built-in)>
inside            = <module 'inside'> -- 1996241053520

inside.__dict__:
    __name__      = inside
    __doc__       = None
    __package__   = None
    __loader__    = None
    __spec__      = None
    builtins      = <function inner.builtins at 0x000001D0C93DA7A0>
    update        = <function inner.update at 0x000001D0C93DA840>
    create        = <function inner.create at 0x000001D0C93DA8E0>
    delete        = <function inner.delete at 0x000001D0C93DA980>
    zero          = 0

inside.builtins:
    __name__      = _
    __qualname__  = inner.builtins
    __module__    = __main__"""
}}}Alle callables worden initieel onder de naam ''{{hitt z{_}}}'' gecreëerd en vervolgens onder een definitieve naam in de module opgeborgen. Op deze manier kun je hun representatie manipuleren. Vergelijk {{pref hitt z{<function ''inner''.<locals>.''builtins'' at ...>}}} uit de vorige oplossing met {{pref hitt z{<function ''inner.builtins'' at ...>}}} in deze. Wat het beste is, daar valt over te twisten.}}}{{clear block{}}}/%
%/
In onderstaand programma heb ik nog een aantal andere alternatieven bijeengebracht die mij wat minder bevielen:
{{lf w50pct pre{
{{fgre{"""# Script: more-inners.py
# Date  : 2023-07-09, Meindert Meindertsma"""}}}

import types


{{fgre{"""#---- Create inline module "inner" ----#"""}}}"""
inner = types.ModuleType("inner")
"""
{{fgre{"""# Create inner variable:"""}}}"""
inner.alpha = 42
"""
{{fgre{"""# Create inner functions:"""}}}"""
def _():
    self = inner
    def _():
        return self.alpha
    return _
inner.robust = _()

def _():
    return inner.alpha
inner.fragile = _

exec("""&quot;&quot;&quot;"""
def solitary():
    return alpha
"""&quot;&quot;&quot;""", inner.__dict__)

"""
{{fgre{"""#---- Operate under a false name from now on ----#"""}}}"""
inside = inner
del inner
"""
{{fgre{"""# Execute inner functions:"""}}}"""
print("inside.alpha      =", inside.alpha)
print("inside.robust()   =", inside.robust())
try: print("inside.fragile()  =", inside.fragile())
except Exception as e: print("Error in inside.fragile():", e)
print("inside.solitary() =", inside.solitary())
print("\ninside.__dict__:")
for k, v in inside.__dict__.items():
    if k != "__builtins__":
        print(f"    {k:13s} = {v}")"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w45pct{{{pre{
''Uitvoer''
"""
inside.alpha      = 42
inside.robust()   = 42
Error in inside.fragile(): name 'inner' is not defined
inside.solitary() = 42

inside.__dict__:
    __name__      = inner
    __doc__       = None
    __package__   = None
    __loader__    = None
    __spec__      = None
    alpha         = 42
    robust        = <function _.<locals>._ at 0x000001AFC83389A0>
    fragile       = <function _ at 0x000001AFC833A660>
    solitary      = <function solitary at 0x000001AFC833A700>"""
}}}De functie {{tt t{robust}}} heeft een nogal anonieme representatie {{pref hitt z{<function ''_''.<locals>.''_'' at ...>}}}.

Functie {{tt t{fragile}}} is niet bestand tegen naamswijziging van {{tt t{inner}}}. Het is de vraag of we dat problematisch moeten vinden. Misschien dat de module beter {{tt t{Inner}}} of {{tt t{INNER}}} had kunnen heten, om aan te geven dat het als constante moet worden opgevat. Anderzijds plegen we ons daar bij naar zichzelf verwijzende functies ook niet druk om te maken.

Van {{tt t{solitary}}} kunnen we tenslotte vaststellen dat deze de inrichting van een conventionele module het best benadert: geen gedoe met een closure&shy;variabele {{tt t{self}}}, want {{tt t{alpha}}} is gewoon een globale variabele binnen {{tt t{inner}}}. Maar doet dat er werkelijk toe? Het voordeel van de oplossingen met een {{tt t{self}}}-qualifier is dat de interne functies en pseudo&shy;methods toegang tot zowel de eigen variabelen als die van de omvattende module hebben.}}}{{clear block{}}}/%
%/
Goed, het kan dus, zo'n inline module. In Ruby zou het een voor de hand liggende methode voor de aanleg van een aparte namespace zijn. In Python vergt het echter nogal wat plichtplegingen in vergelijking met [[alternatieve constructies|Singletons in Python]], zoals de aanleg van een class voor direct gebruik zonder ooit instances van die class te maken.
===/%


%/+++(~Python_VroegsteModuleExperimenten)!![Vroegste experimenten &darr;|show][Vroegste experimenten &uarr;|hide]
De programma's {{pref sans t{inspect-modules.py}}} en {{sans t{outer.py}}} volgens onderstaand schema bevatten mijn eerste probeersels.

{{ml3em hdn{[img[data/images/Python-inspect-modules.png]]}}}

Het is een beetje overladen geheel geworden. Daarom heb ik de verschillende in de vorige paragrafen behandelde aspecten gaandeweg ondergebracht in afzonderlijke programmatuur. Hoewel dit oude materiaal me bij deze stand van zaken overbodig geworden lijkt, lever ik het toch maar met de [[downloads|Python-scopescripts (downloads)]] mee.
===
/***
!!Favicon/%------------------------------------------------------------%/
***/
//{{{
var link = document.createElement("link");
link.rel = "shortcut icon";
link.type = "image/x-icon";
link.href = "core/favicon.ico";
document.getElementsByTagName("head")[0].appendChild(link);
//}}}
/***
!!Fonts/%------------------------------------------------------------%/
***/
//{{{
var style = document.createElement("style");
style.type = "text/css";
var text = document.createTextNode('@import "core/fonts.css";');
style.appendChild(text)
document.getElementsByTagName("head")[0].appendChild(style);
//}}}
Enter your username for signing your edits: <<option txtUserName>>

Raadpleeg zonodig de [[Stijlgids]] of de samenvatting van de [[TiddlyWiki Markup Language]].
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Vervolg van [[Iteratiemechanismen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''

{{ml3em mr3em{[img[data/images/SC each(Number)-a-la-Ruby.png]]}}} [[Legenda|Structuurdiagrammen à la Constantine]]

<<tiddler [[{}::togglesliders]]>> Het linker structuurdiagram verbeeldt hoe de routine {{sans t{eachNumber}}} intern een opeenvolging van natuurlijke getallen produceert, terwijl het rechter diagram laat zien hoe de routine {{sans t{each}}} over de elementen van een collectie itereert. De subroutine {{sans t{//procedure//}}} die telkens wordt aangeroepen om iets met het geleverde materiaal te doen, is in staat in te grijpen in het aanroepende proces. Niet via een gewone expliciete of impliciete {{tt t{return}}} met een speciale waarde, maar langs een andere weg. Deze is daarom als een aparte vorm van aansturing ingetekend. Let op het zwarte bolletje bij het vertrekpunt van de desbetreffende pijl, dat //onvoorwaardelijke overdracht van de besturing// betekent. Omwille van bondigheid heb ik zo'n ingreep alleen bij {{sans t{eachNumber}}} in de scripts uitgewerkt. Bij {{sans t{each}}} gaat het net zo./%

%/
!!Ruby
De wijze waarop Ruby omspringt met iteraties is exemplarisch voor hoe deze taal zaken pleegt aan te pakken. Zoals in 'The pickaxe' verwoord:{{ref{&#x200a;[[[1]|##1]]}}}
<<<
A Ruby iterator is simply a method that can invoke a block of code.
&nbsp; &nbsp; &nbsp; (...)
In Ruby, the basic iterator is internal to the collection -- it's simply a method, identical to any other, that happens to call {{tt t{yield}}} whenever it generates a new value. The thing that uses the iterator is just a block of code associated with a call to this method.
&nbsp; &nbsp; &nbsp; In other languages, collections don't contain their own iterators. Instead, they implement methods that generate external helper objects (for example, those based on Java's {{tt t{Iterator}}} interface) that carry the iterator state. In this, as in many other ways, Ruby is a transparent language. When you write a Ruby program, you concentrate on getting the job done, not on building scaffolding to support the language itself.
<<<
Onderstaande methods {{tt t{one}}} en {{tt t{multiple}}} zijn dus beide gekwalificeerd als 'iterator' (en de ingebouwde method {{tt t{//integer//.times}}}, die ik rechts heb toegepast, natuurlijk ook):
{{lf w45pct pref tt s med ws pred d2p r scroll{
"""def one(text)
  yield text
end

one("world") {|addressee| puts "Hello, #{addressee}!" }
"""
----
''Uitvoer''
Hello, world!


}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{w45pct pref tt s med ws pred d2p r scroll{
"""def multiple(n, text)
  n.times { yield text }
end

multiple(3, "reader") {|addressee| puts "Hello, #{addressee}!" }
"""
----
''Uitvoer''
Hello, reader!
Hello, reader!
Hello, reader!
}}}/%

%/(Ik had {{tt t{one}}} wat omstandiger kunnen definiëren, namelijk als {{pref hitt pred{def one(text, &procedure); procedure[text]; end}}}. Dan had het ook gewerkt. Maar dankzij het {{tt t{yield}}}-statement hebben we die ballast van een extra variabele helemaal niet nodig.) 

Veel ingebouwde classes, waaronder ''{{{Hash}}}'', het Ruby-equivalent van de dictionary, zijn al van een method ''{{{each}}}'' voorzien. Daar hoef ik dus niets meer aan te doen. Alleen de teller, een stukje maatwerk, heb ik zelf als een method gebouwd. De {{sans t{//procedure//}}} is geïmplementeerd als een naamloos block.
+++(~Each_Ruby)!!![Het volledige Ruby-script &darr;|show][Het volledige Ruby-script &uarr;|hide]
{{lf w80pct pref tt s med ws pred d2p r scroll{
{{fpur{"""# Script: Integrated-provider-deliverer-pilot-a-la-Ruby.rb
# Date  : 2023-03-13, Meindert Meindertsma
#
#   Role       Ruby term         Name in this script     Variant state
#   ---------  ----------------  ----------------------  -------------
#   provider   -                 eachNumber, dictionary  x
#   deliverer  iterator          eachNumber, each        x
#   pilot      iterator          eachNumber, each        x
#   ---------  ----------------  ----------------------  -------------


#-----====| NUMBERS |====-----#

#---- Provider/deliverer/pilot ----#"""}}}
def ''eachNumber''(increment = 1)
"""  value = 0
  while value < 4 * increment do
    value += increment
    yield value
  end
end
"""
{{fpur{"""#---- Deliver all even numbers ----#"""}}}
''eachNumber''(2) {|n| puts n }
"""
puts "---"
"""
{{fpur{"""#---- Deliver just 3 numbers ----#"""}}}
''eachNumber'' {|n| puts n; break if n >= 3 }
"""
puts "---"

"""
{{fpur{"""#-----====| DICTIONARY |====-----#

#----- Provider ----#"""}}}
''dictionary'' = {"A" => 10, "B" => 11, "C" => 12}

{{fpur{"""#---- Deliver all key/value pairs ----#"""}}}
''dictionary.each'' {|k, v| puts "#{k} #{v}" }
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pref tt s med ws pred d2p r scroll{
''Uitvoer door Ruby 1.9+''

"""2
4
6
8
---
1
2
3
---
A 10
B 11
C 12"""
}}}{{clear block{Het ''{{{yield}}}''-statement in de {{tt t{eachNumber}}}-method roept de naamloze procedure aan die als laatste argument aan de method was meegegeven. Op haar beurt krijgt die procedure bij aanroep het argument {{tt t{value}}} mee.}}}/%
%/
Het block {{pref hitt z pred{{|n| puts n; @@background-color:#ffcccc;break@@ if n >= 3 """}"""}}} vergt wat meer toelichting. Wat in veel andere talen //functie// wordt genoemd, kent in Ruby drie stadia:
* Een //code block// ({{pref hitt z pred{{ ... """}"""}}} of {{pref hitt z pred{do ... end}}}) is het embryonale stadium van een functie. Het is géén object en je kunt het alleen maar als laatste argument meegeven aan een method.
* Een //raw proc// is het larvestadium van een functie. Dit is wel een object, namelijk een instance van de class ''{{{Proc}}}''. Wanneer een block aan een method wordt aangeboden, wordt het automatisch omgezet naar een raw proc, zodat het binnen die method kan worden aangeroepen. Je kunt zo'n proc ook zelf creëren d.m.v. {{pref hitt z pred{Proc.new { ... """}"""}}} ({{tt t{new}}} is een method en wordt hier aangeroepen met een block als argument ).
* Een //lambda// is het volwassen stadium van een functie, aan te maken via {{pref hitt z pred{lambda { ... """}"""}}} (ook de method {{tt t{lambda}}} ontvangt een block als argument). Een lambda is eveneens een instance van {{tt t{Proc}}}, maar dan een volledig afgewerkt exemplaar dat zich helemaal gedraagt als een functie à la Python. Alle {{tt t{Proc}}}-instances (raw of afgewerkt) kunnen worden aangeroepen met {{pref hitt z pred{//proc//''.call(''//args//'')''}}}, {{pref hitt z pred{//proc//''.yield(''//args//'')''}}} of {{pref hitt z pred{//proc//''[''//args//'']''}}}, waarbij {{tt t{call}}}, {{tt t{yield}}} en ''{{{[]}}}'' volkomen gelijkwaardige instance methods zijn. (Die {{tt t{yield}}} -- niet te verwarren met de {{tt t{yield}}} van het gelijknamige statement -- is pas in versie 1.9 toegevoegd. Naar mijn smaak houdt Ruby er wat al te veel synoniemen, en erger, homoniemen, op na.)
In een raw proc, en daarmee dus ook in een block, wordt het {{tt t{break}}}-statement opgevat als een instructie voor de //aanroeper// van de raw proc. Pas in een lambda is de context ervan beperkt tot die lambda zelf, zoals we elders van functies gewend zijn. Maar in bovenstaand geval breekt de {{tt t{break}}} dus de {{tt t{while}}}-lus in {{tt t{eachNumber}}} af tijdens de uitvoering van het {{tt t{yield}}}-statement. Ik had iets soortgelijks bij de dictionary kunnen toepassen: {{pref hitt z pred{{|k, v| if k == "B" then puts "#{k} #{v}"; @@background-color:#ffcccc;break@@; end """}"""}}} print alleen het sleutel/waarde-paar voor de sleutel {{tt t{"B"}}} en breekt het itereren vervolgens meteen af, zonder dat ik iets aan de ingebouwde {{tt t{each}}}-method van {{tt t{Hash}}} hoef te veranderen.

Methods en blocks vormen de spil van Ruby's uitdrukkingsmogelijkheden. [[Lambda's|Delivery by closure]] zie je weinig en raw procs hoogst zelden. Er zijn me geen ingebouwde {{tt t{Proc}}}-instances bekend, maar in enkele libraries heb ik ze wel gezien./%

%/
===
!!Python
In Python ligt het voor de hand {{tt t{eachNumber}}} als een functie te implementeren. De {{tt t{dict}}}-class bevat voor zo ver ik weet geen equivalent van Ruby's {{tt t{each}}}-method, dus die zullen we zelf wel moeten bouwen.
+++(~Each_Python)!!![Het volledige Python-script &darr;|show][Het volledige Python-script &uarr;|hide]
{{lf w80pct pre{
{{fgre{"""# Script: Integrated-provider-deliverer-pilot-a-la-Ruby.py
# Date  : 2023-03-24, Meindert Meindertsma
#
#   Role       Ruby term         Name in this script     Variant state
#   ---------  ----------------  ----------------------  -------------
#   provider   -                 eachNumber, dictionary  x
#   deliverer  iterator          eachNumber, each        x
#   pilot      iterator          eachNumber, each        x
#   ---------  ----------------  ----------------------  -------------"""}}}

class BreakIteration(StopIteration): pass
class ContinueIteration(StopIteration): pass


{{fgre{"""#-----====| NUMBERS |====-----#

#---- Provider/deliverer/pilot ----#"""}}}
def ''eachNumber''"""(procedure, increment = 1):
  value = 0
  while value < 4 * increment:
    value += increment
    try:
        procedure(value)
    except BreakIteration: break
    except ContinueIteration: continue
"""
{{fgre{"""#---- Deliver all even numbers ----#"""}}}
''eachNumber''(lambda n: print(n), 2)
"""
print('---')
"""
{{fgre{"""#---- Deliver just 3 numbers ----#"""}}}
"""def _(n):
    print(n)
    if n >= 3: raise BreakIteration    """{{fgre{"""# simulate break"""}}}
''eachNumber''(_)
"""
print('---')

"""
{{fgre{"""#-----====| DICTIONARY |====-----#

#---- Preparation ----#"""}}}
"""class RichDict(dict):
    def each(self, procedure):
        for k, v in self.items(): procedure(k, v)
"""
{{fgre{"""#---- Provider ----#"""}}}
''dictionary'' = RichDict({'A': 10, 'B': 11, 'C': 12})

{{fgre{"""#---- Deliver all key/value pairs ----#"""}}}
''dictionary.each''(lambda k, v: print(k, v))
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pre{
''Uitvoer''
"""
2
4
6
8
---
1
2
3
---
A 10
B 11
C 12"""
}}}{{clear block{Anders dan in Ruby kunnen classes die in Python zijn ingebouwd niet worden aangepast. Dan maar een //functie// {{tt t{each}}} bouwen is niet zo aantrekkelijk, omdat deze moet worden toegespitst op dictionaries en dus voor de duidelijkheid zoiets als {{tt t{eachElementOfDict}}} zou moeten gaan heten. Liever een subclass {{tt t{RichDict}}} aangelegd om daar een {{tt t{each}}}-//method// aan toe te voegen.}}}/%

%/
===
!!Lua
Lua kent geen methods, daar is het te primitief voor. Om een en ander na te bootsen moet er meer programmeerwerk worden verzet.
+++(~Each_Lua)!!![Het volledige Lua-script &darr;|show][Het volledige Lua-script &uarr;|hide]
{{lf w80pct pre4{
{{fgre{"""-- Script: Integrated-provider-deliverer-pilot-a-la-Ruby.lua
-- Date  : 2023-03-24, Meindert Meindertsma
--
--   Role       Ruby term         Name in this script     Variant state
--   ---------  ----------------  ----------------------  -------------
--   provider   -                 eachNumber, dictionary  x
--   deliverer  iterator          eachNumber, each        x
--   pilot      iterator          eachNumber, each        x
--   ---------  ----------------  ----------------------  -------------


------====| NUMBERS |====------

----- Provider/driverer/pilot -----"""}}}
function ''eachNumber'' (procedure, increment)
"""  increment = increment or 1
  local value = 0
  while value < 4 * increment do
    value = value + increment
    local OK, err = pcall(procedure, value)  """{{fgre{"""-- protected mode call"""}}}
"""    if not OK then
      if err.type == "BreakIteration" then break else error(err) end
    end
  end
end
"""
{{fgre{"""----- Deliver all even numbers -----"""}}}
''eachNumber''(function (n) print(n) end, 2)
"""
print "---"
"""
{{fgre{"""----- Deliver just 3 numbers -----"""}}}
''eachNumber''(function (n)
"""    print(n)
    if n >= 3 then error {type = "BreakIteration"} end  """{{fgre{"""-- simulate break"""}}}
"""  end
)

print "---"

"""
{{fgre{"""------====| DICTIONARY |====------

----- Preparation -----"""}}}
"""meta = {__index""" = {''each'' = function (self, procedure)
"""      for k,v in pairs(self) do procedure(k, v) end
    end
  }
}
"""
{{fgre{"""----- Provider -----"""}}}
''dictionary'' = {A = 10, B = 11, C = 12}
setmetatable(''dictionary'', meta)

{{fgre{"""----- Deliver all key/value pairs -----"""}}}
''dictionary:each''(function (k, v) print(k, v) end)
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pre4{
''Uitvoer''
"""
2
4
6
8
---
1
2
3
---
A       10
C       12
B       11"""
}}}{{clear block{Evenals bij Python zag ik me voor de keus gesteld: maak ik van {{tt t{each}}} een functie of probeer ik er iets method-achtigs van te maken? Ik heb voor het laatste gekozen en dat brengt de nodige meta&shy;programmering met zich mee. Wanneer ik de functie {{tt t{each}}} rechtstreeks in {{tt t{dictionary}}} had gedefinieerd, zou tijdens het itereren onderweg ook het sleutel/waarde-paar {{pref hitt4 z{each    function: 009AC158}}} of zoiets worden afgedrukt. Om dat te voorkomen moet een omweg worden bewandeld.

Om te beginnen: Lua kent slechts één collectietype, de ''{{sans{[[table|Simulaties van for...in...-statement##Het volledige Lua-script]]}}}''. Een table kan worden geassocieerd met andere tables, waarbij eerstgenoemde de rol van //metatable// krijgt. Die heb ik hierboven heel toepasselijk {{tt t{meta}}} genoemd. Deze metatable bevat in dit geval één //metamethod//, te weten {{tt t{"""__index"""}}}. Metamethods kunnen worden aangeroepen of anderszins gebruikt door een table waarmee de metatable geassocieerd is. Hierboven is {{tt t{"""__index"""}}} een table, van aanroepen is geen sprake. In deze gedaante is het effect, dat de table waarmee {{tt t{meta}}} geassocieerd is toegang heeft tot de sleutel/waarde-paren uit {{tt t{"""meta.__index"""}}}, althans voor zover de betreffende sleutels niet in de table zelf voorkomen. Dit begint sterk op een wat ruwe vorm van object&shy;oriëntatie te lijken, waarbij de metatable de rol van //class// speelt. Bij iteraties via {{tt t{pairs}}} of {{tt t{ipairs}}} doen de indirecte elementen zoals in dit geval {{tt t{each}}} nooit mee. Alleen als je zo'n indirect sleutel/waarde-paar expliciet bij de sleutel noemt, komt het tevoorschijn (dat is overigens te voorkomen door de {{tt t{rawget}}}-functie te gebruiken: {{pref hitt4 z{rawget(directory, "each")}}} levert {{tt t{nil}}} op).}}}/%
%/
<<eval [=[Vóór de associatie zou {{tt t{each}}} al kunnen worden toegepast met de aanroep {{pref hitt4 z{"""meta.__index.each"""(dictionary, $___)}}}. Na {{pref hitt4 z{setmetatable(dictionary, meta)}}} kan worden volstaan met {{pref hitt4 z{dictionary.each(dictionary, $___)}}}. Nog niet erg elegant. Vandaar dat Lua er een schepje //syntactische suiker// bij aanbiedt waarmee het tot de vorm {{pref hitt4 z{dictionary:each($___)}}} gekomen wat beter smaakt.]=]>>
===

----
|plain |k
|<html><a name="1">[1]</a></html>|<<tiddler Bibliografie##Thomas>> |
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.9.2//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press escape to close the listbox to resume typing.  When the listbox is not displayed, pressing //escape// clears the current input.
!!!Documentation
>see [[GotoPluginInfo]]
!!!Configuration
<<<
*Match titles only after {{twochar{<<option txtIncrementalSearchMin>>}}} or more characters are entered.<br>Use down-arrow to start matching with shorter input.  //Note: This option value is also set/used by [[SearchOptionsPlugin]]//.
*To set the maximum height of the listbox, you can create a tiddler tagged with <<tag systemConfig>>, containing:
//{{{
config.macros.gotoTiddler.listMaxSize=10;  // change this number
//}}}
<<<
!!!Revisions
<<<
2009.05.22 [1.9.2] use reverseLookup() for IncludePlugin
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!Code
***/
//{{{
version.extensions.GotoPlugin= {major: 1, minor: 9, revision: 2, date: new Date(2009,5,22)};

// automatically tweak shadow SideBarOptions to add <<gotoTiddler>> macro above <<search>>
config.shadowTiddlers.SideBarOptions=config.shadowTiddlers.SideBarOptions.replace(/<<search>>/,"{{button{goto}}}\n<<gotoTiddler>><<search>>");

if (config.options.txtIncrementalSearchMin===undefined) config.options.txtIncrementalSearchMin=3;

config.macros.gotoTiddler= { 
	listMaxSize: 10,
	listHeading: 'Found %0 matching title%1...',
	searchItem: "Search for '%0'...",
	handler:
	function(place,macroName,params,wikifier,paramString,tiddler) {
		var quiet	=params.contains("quiet");
		var showlist	=params.contains("showlist");
		var search	=params.contains("search");
		params = paramString.parseParams("anon",null,true,false,false);
		var instyle	=getParam(params,"inputstyle","");
		var liststyle	=getParam(params,"liststyle","");
		var filter	=getParam(params,"filter","");
		var html=this.html;
		var keyevent=window.event?"onkeydown":"onkeypress"; // IE event fixup for ESC handling
		html=html.replace(/%keyevent%/g,keyevent);
		html=html.replace(/%search%/g,search);
		html=html.replace(/%quiet%/g,quiet);
		html=html.replace(/%showlist%/g,showlist);
		html=html.replace(/%display%/g,showlist?'block':'none');
		html=html.replace(/%position%/g,showlist?'static':'absolute');
		html=html.replace(/%instyle%/g,instyle);
		html=html.replace(/%liststyle%/g,liststyle);
		html=html.replace(/%filter%/g,filter);
		if (config.browser.isIE) html=this.IEtableFixup.format([html]);
		var span=createTiddlyElement(place,'span');
		span.innerHTML=html; var form=span.getElementsByTagName("form")[0];
		if (showlist) this.fillList(form.list,'',filter,search,0);
	},
	html:  /* id attribute added to input element */
	'<form onsubmit="return false" style="display:inline;margin:0;padding:0">\
		<input id=gotoTiddler name=gotoTiddler type=text autocomplete="off" accesskey="G" style="%instyle%"\
			title="Enter title text... ENTER=goto, SHIFT-ENTER=search for text, DOWN=select from list"\
			onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
			%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list,%search%,%showlist%);"\
			onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,%quiet%,%search%,%showlist%);">\
		<select name=list style="display:%display%;position:%position%;%liststyle%"\
			onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
			onblur="this.style.display=%showlist%?\'block\':\'none\';"\
			%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler,%showlist%);"\
			onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this,%showlist%);">\
		</select><input name="filter" type="hidden" value="%filter%">\
	</form>',
	IEtableFixup:
	"<table style='width:100%;display:inline;padding:0;margin:0;border:0;'>\
		<tr style='padding:0;margin:0;border:0;'><td style='padding:0;margin:0;border:0;'>\
		%0</td></tr></table>",
	getItems:
	function(list,val,filter) {
		if (!list.cache || !list.cache.length || val.length<=config.options.txtIncrementalSearchMin) {
			// starting new search, fetch and cache list of tiddlers/shadows/tags
			list.cache=new Array();
			if (filter.length) {
				var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
				var tiddlers=store.sortTiddlers(fn.apply(store,[filter]),'title');
			} else 
				var tiddlers=store.reverseLookup('tags','excludeLists');
			for(var t=0; t<tiddlers.length; t++) list.cache.push(tiddlers[t].title);
			if (!filter.length) {
				for (var t in config.shadowTiddlers) list.cache.pushUnique(t);
				var tags=store.getTags();
				for(var t=0; t<tags.length; t++) list.cache.pushUnique(tags[t][0]);
			}
		}
		var found = [];
		var match=val.toLowerCase();
		for(var i=0; i<list.cache.length; i++)
			if (list.cache[i].toLowerCase().indexOf(match)!=-1) found.push(list.cache[i]);
		return found;
	},
	getItemSuffix:
	function(t) {
		if (store.tiddlerExists(t)) return "";  // tiddler
		if (store.isShadowTiddler(t)) return " (shadow)"; // shadow
		return " (tag)"; // tag 
	},
	fillList:
	function(list,val,filter,search,key) {
		if (list.style.display=="none") return; // not visible... do nothing!
		var indent='\xa0\xa0\xa0';
		var found = this.getItems(list,val,filter); // find matching items...
		found.sort(); // alpha by title
		while (list.length > 0) list.options[0]=null; // clear list
		var hdr=this.listHeading.format([found.length,found.length==1?"":"s"]);
		list.options[0]=new Option(hdr,"",false,false);
		for (var t=0; t<found.length; t++) list.options[list.length]=
			new Option(indent+found[t]+this.getItemSuffix(found[t]),found[t],false,false);
		if (search)
			list.options[list.length]=new Option(this.searchItem.format([val]),"*",false,false);
		list.size=(list.length<this.listMaxSize?list.length:this.listMaxSize); // resize list...
		list.selectedIndex=key==38?list.length-1:key==40?1:0;
	},
	keyProcessed:
	function(ev) { // utility function
		ev.cancelBubble=true; // IE4+
		try{event.keyCode=0;}catch(e){}; // IE5
		if (window.event) ev.returnValue=false; // IE6
		if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
		if (ev.stopPropagation) ev.stopPropagation(); // all
		return false;
	},
	inputEscKeyHandler:
	function(event,here,list,search,showlist) {
		if (event.keyCode==27) {
			if (showlist) { // clear input, reset list
				here.value=here.defaultValue;
				this.fillList(list,'',here.form.filter.value,search,0);
			}
			else if (list.style.display=="none") // clear input
				here.value=here.defaultValue;
			else list.style.display="none"; // hide list
			return this.keyProcessed(event);
		}
		return true; // key bubbles up
	},
	inputKeyHandler:
	function(event,here,quiet,search,showlist) {
		var key=event.keyCode;
		var list=here.form.list;
		var filter=here.form.filter;
		// non-printing chars bubble up, except for a few:
		if (key<48) switch(key) {
			// backspace=8, enter=13, space=32, up=38, down=40, delete=46
			case 8: case 13: case 32: case 38: case 40: case 46: break; default: return true;
		}
		// blank input... if down/enter... fall through (list all)... else, and hide or reset list
		if (!here.value.length && !(key==40 || key==13)) {
			if (showlist) this.fillList(here.form.list,'',here.form.filter.value,search,0);
			else list.style.display="none";
			return this.keyProcessed(event);
		}
		// hide list if quiet, or below input minimum (and not showlist)
		list.style.display=(!showlist&&(quiet||here.value.length<config.options.txtIncrementalSearchMin))?'none':'block';
		// non-blank input... enter=show/create tiddler, SHIFT-enter=search for text
		if (key==13 && here.value.length) return this.processItem(event.shiftKey?'*':here.value,here,list,showlist);
		// up or down key, or enter with blank input... shows and moves to list...
		if (key==38 || key==40 || key==13) { list.style.display="block"; list.focus(); }
		this.fillList(list,here.value,filter.value,search,key);
		return true; // key bubbles up
	},
	selectKeyHandler:
	function(event,list,editfield,showlist) {
		if (event.keyCode==27) // escape... hide list, move to edit field
			{ editfield.focus(); list.style.display=showlist?'block':'none'; return this.keyProcessed(event); }
		if (event.keyCode==13 && list.value.length) // enter... view selected item
			{ this.processItem(list.value,editfield,list,showlist); return this.keyProcessed(event); }
		return true; // key bubbles up
	},
	processItem:
	function(title,here,list,showlist) {
		if (!title.length) return;
		list.style.display=showlist?'block':'none';
		if (title=="*")	{ story.search(here.value); return false; } // do full-text search
		if (!showlist) here.value=title;
		story.displayTiddler(null,title); // show selected tiddler
		return false;
	}
}
//}}}
/***
|Name|GotoPluginInfo|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for GotoPlugin|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press escape to close the listbox to resume typing.  When the listbox is not displayed, pressing //escape// clears the current input.
!!!!!Usage/Examples
<<<
syntax: {{{<<gotoTiddler quiet search inputstyle:... liststyle:... filter:...>>}}}
All parameters are optional.
* ''quiet'' (//keyword//)<br>list will not be automatically display as each character is typed.  Use //down// or //enter// to view the list.
* ''showlist'' (//keyword//)<br>list will always be displayed, inline, directly below the input field.
* ''search'' (//keyword//)<br>adds an extra 'command item' to the list that can be used to invoke a full-text search using the entered value.  This can be especially useful when no matching tiddler titles have been found.
* ''inputstyle:'' and ''liststyle:''<br>are CSS declarations that modify the default input and listbox styles, respectively.  Note: the CSS styles must be surrounded by ({{{"..."}}} or {{{'...'}}}) or ({{{[[...]]}}}) (e.g., {{{liststyle:"border:1px dotted blue;color:green;..."}}}.
* ''filter:''<br>is a single tag value (or a boolean tag expression if MatchTagsPlugin is installed), and is used to limit the search to only those tiddlers matching the indicated tag or tag expression (e.g., {{{<<gotoTiddler filter:"faq or help">>}}})
{{{<<gotoTiddler>>}}}
<<gotoTiddler>>
{{{<<gotoTiddler search>>}}}
<<gotoTiddler search>>
{{{<<gotoTiddler showlist filter:"pluginInfo" liststyle:"height:10em;width:auto;">>}}}
<<gotoTiddler showlist filter:"pluginInfo" liststyle:"height:10em;width:auto;">>
<<<
!!!!!Configuration
<<<
*Match titles only after {{twochar{<<option txtIncrementalSearchMin>>}}} or more characters are entered.<br>Use down-arrow to start matching with shorter input.  //Note: This option value is also set/used by [[SearchOptionsPlugin]]//.
*To set the maximum height of the listbox, you can create a tiddler tagged with <<tag systemConfig>>, containing:
//{{{
config.macros.gotoTiddler.listMaxSize=10;  // change this number
//}}}
<<<
!!!!!Revisions
<<<
2009.05.22 1.9.2 use reverseLookup() for IncludePlugin
2009.04.12 1.9.1 support multiple instances with different filters by using per-element tiddler cache instead of shared static cache
2009.04.05 1.9.0 added 'showlist' parameter for inline display with listbox always visible.
2009.03.23 1.8.0 added txtIncrementalSearchMin (default=3).  Avoids fetching long lists.  Use down arrow to force search with short input.
2008.12.15 1.7.1 up arrow from input field now moves to end of droplist (search for input).  Also, shift+enter cam now be used to quickly invoke search for text.
2008.10.16 1.7.0 in macro handler(), changed to use //named// params instead of positional params, and added optional "filter:" param for tag filtering.  Removed 'insert' handling (now provided by [[QuickEditPlugin]]).
2008.10.02 1.6.1 for IE, wrap controls in a table.  Corrects placement of listbox so it is below input field.
2008.10.02 1.6.0 added 'search' param for optional "Search for:" item that invokes full text search (especially useful when no title matches are found)
2008.02.17 1.5.0 ENTER key always displays tiddler based on current input regardless of whether input matches any existing tiddler
2007.10.31 1.4.3 removed extra trailing comma on last property of config.macros.gotoTiddler object.  This fixes an error under InternetExplorer that was introduced 6 days ago... sure, I should have found it sooner, but... WHY DON'T PEOPLE TELL ME WHEN THINGS ARE BROKEN!!!!
2007.10.25 1.4.2 added onclick handler for input field, so that clicking in field hides the listbox.
2007.10.25 1.4.1 re-wrote getItems() to cache list of tiddlers/shadows/tags and use case-folded simple text match instead of regular expression to find matching tiddlers.  This *vastly* reduces processing overhead between keystrokes, especially for documents with many (>1000) tiddlers.  Also, removed local definition of replaceSelection(), now supported directly by the TW2.2+ core, as well as via backward-compatible plugin
2007.04.25 1.4.0 renamed macro from "goto" to "gotoTiddler".  This was necessary to avoid a fatal syntax error in Opera (and other browsers) that require strict adherence to ECMAScript 1.5 standards which defines the identifier "goto" as "reserved for FUTURE USE"... *sigh*
2007.04.21 1.3.2 in html definition, removed DIV around droplist (see 1.2.6 below).  It created more layout problems then it solved. :-(
2007.04.01 1.3.1 in processItem(), ensure that correct textarea field is found by checking for edit=="text" attribute
2007.03.30 1.3.0 tweak SideBarOptions shadow to automatically add {{{<<goto>>}}} when using default sidebar content
2007.03.30 1.2.6 in html definition, added DIV around droplist to fix IE problem where list appears next to input field instead of below it.  
2007.03.28 1.2.5 in processItem(), set focus to text area before setting selection (needed for IE to get correct selection 'range')
2007.03.28 1.2.4 added prompt for 'pretty text' when inserting a link into tiddler content
2007.03.28 1.2.3 added local copy of core replaceSelection() and modified for different replace logic
2007.03.27 1.2.2 in processItem(), use story.getTiddlerField() to retrieve textarea control
2007.03.26 1.2.1 in html, use either 'onkeydown' (IE) or 'onkeypress' (Moz) event to process <esc> key sooner, to prevent <esc> from 'bubbling up' to the tiddler (which will close the current editor).
2007.03.26 1.2.0 added support for optional "insert" keyword param.
2006.05.10 1.1.2 when filling listbox, set selection to 'heading' item... auto-select first tiddler title when down/enter moves focus into listbox
2006.05.08 1.1.1 added accesskey ("G") to input field html (also set when field gets focus).  Also, inputKeyHandler() skips non-printing/non-editing keys. 
2006.05.08 1.1.0 added heading to listbox for better feedback (also avoids problems with 1-line droplist)
2006.05.07 1.0.0 list matches against tiddlers/shadows/tags.  input field auto-completion... 1st enter=complete matching input (or show list)... 2nd enter=view tiddler.  "quiet" param controls when listbox appears.  handling for enter (13), escape(27), and down(40) keys.   Change 'ondblclick' to 'onclick' to avoid unintended triggering of tiddler editor).  Shadow titles inserted into list instead of appended to the end.
2006.05.05 0.0.0 started
<<<
[img[data/images/Simplified_Structure_of_the_Linux_Kernel.svg.png]]/%

%/
!!Objecttypen
In de Unix-wereld wordt een bestandssysteemobject //inode// genoemd. Linux kent de volgende typen: 

{{pref{{{tt{  @@bgcolor(#ee6): ''-'' @@ = //regular file//
  @@bgcolor(#ee6): ''b'' @@ = //block device (random accesible)//
  @@bgcolor(#ee6): ''c'' @@ = //character device (serial stream of input or output)//
  @@bgcolor(#ee6): ''d'' @@ = //directory//
  @@bgcolor(#ee6): ''l'' @@ = //symbolic link//
  @@bgcolor(#ee6): ''p'' @@ = //named pipe (aka FIFO)//
  @@bgcolor(#ee6): ''s'' @@ = //socket (aka Unix domain socket or inter-process communication socket)//
   &#x2570;&#x254C;&#x254C;&#x254C;&#x254C;&#x254C;&#x27A4; //(displayed by //''ls -l''//)//}}}}}}

Als gewone gebruiker heb je voornamelijk met bestanden, directories en symbolische links te maken. En zonder dat je er misschien erg in hebt ook met harde links. Een harde link is een entry in een directory die //rechtstreeks// verwijst naar een inode. Wanneer je een inode (bestand, directory enz.) aanmaakt, creëer je daarmee vanzelf een harde link ernaar in een directory. Met het ''{{{ln}}}''-commando kun je andere rechtstreekse verwijzingen naar een reeds bestaand bestand aanleggen (als nieuwe entry in een andere of in dezelfde directory, en al dan niet onder dezelfde naam). Het zelf vrijelijk aanleggen van harde links naar bestaande directories is voor gebruikers niet weggelegd. Pas bij verwijdering van de laatste harde link naar een inode verdwijnt die inode uit het bestandssysteem. Inhoud en [[attributen|Bestandsattributen in Linux]] (inodenummer, type, eigenaar, permissies, enz.) zijn eigenschappen van de inode zelf, niet van de entry die ernaar verwijst. De locatie in de directorystructuur en de naam van de entry zijn daarentegen geen eigenschappen van de inode. Overigens hoef je je in de regel niet om de inodenummers te bekommeren. In de praktijk refereer je alleen via een bestaande of nieuwe entrynaam naar de gewenste inode. Anderzijds is inspectie van het inodenummer (bijvoorbeeld via''{{{ ls -i}}}'') de enige manier om vast te stellen welke harde links naar dezelfde directory of file verwijzen. Het commando''{{{ ls -l }}}''laat zien met hoeveel harde links de inode verbonden is. Bij directories kan dat snel oplopen, omdat elke subdirectory via de automatische entry ''{{{..}}}'' weer terugverwijst naar zijn parent. Maar bij bestanden die een waarde groter dan {{{1}}} hebben, is er wel iets bijzonders aan de hand.

Een [[symbolische link|Symbolic links on Linux]], aan te maken met de opdracht''{{{ ln -s}}}'', is iets wezenlijk anders dan een harde link. Het is een inode die op zijn beurt verwijst naar de naam van een entry in een directory (in de vorm van een absoluut dan wel relatief zoekpad dat bestaat uit een aaneenschakeling van zulke entries). Het is dus een //indirecte// verwijzing, vergelijkbaar met (maar niet helemaal hetzelfde als) een shortcut in Windows. Zulke links zullen doodlopen, wanneer het genoemde pad niet bestaat doordat onderdelen ervan zijn hernoemd, verplaatst, verwijderd of zelfs nooit zijn aangemaakt.

In onderstaand schema zijn drie harde links en één symbolische link getekend naar inode {{{1002}}}, dat een tekstbestand bevat. Vanuit de directory in inode {{{1000}}} is dit bestand aanspreekbaar met{{{ D1/F11.txt}}},{{{ D2/F21.txt}}},{{{ S3.txt }}}en{{{ F4.txt}}}. De symbolische link{{{ S3.txt }}}naar het relatieve zoekpad{{{ D2/F21.txt }}}(en daarmee indirect naar inode {{{1002}}}) is gevoelig voor veranderingen in de omgeving. De drie harde links naar inode {{{1002}}} zijn dat niet, doordat ze geheel op zichzelf staan. Onderling zijn ze bovendien volkomen gelijkwaardig, want de volgorde waarin ze zijn aangelegd doet er niet toe.

[img[data/images/Unix-inodes.png]]

Om het schema een beetje overzichtelijk te maken, zijn de standaard directory-entries ''{{{.}}}'' (verwijst naar eigen inode) en ''{{{..}}}'' (verwijst naar de inode van de parent) niet ingetekend. Vanuit gebruikersperspectief is tijdens het werken in Linux eigenlijk alleen de boomstructuur van entries (inclusief markering van symbolische doorsteekjes) redelijk goed te waar te nemen. Dus (ook weer met weglating van ''{{{.}}}'' en ''{{{..}}}''):

{{pref{{{tt s low{
  //<starting-point>//''/''
    &#x251C;&#x2500;&#x2500;&#x2574;''D1/''
    &#x2502;     &#x251C;&#x2500;&#x2500;&#x2574;''F11.txt''
    &#x2502;     &#x2514;&#x2500;&#x2500;&#x2574;...
    &#x251C;&#x2500;&#x2500;&#x2574;''D2/''
    &#x2502;     &#x251C;&#x2500;&#x2500;&#x2574;''F21.txt''
    &#x2502;     &#x2514;&#x2500;&#x2500;&#x2574;...
    &#x251C;&#x2500;&#x2500;&#x2574;''S3.txt'' -> D2/F21.txt
    &#x251C;&#x2500;&#x2500;&#x2574;''F4.txt''
    &#x2514;&#x2500;&#x2500;&#x2574;...
}}}}}}
Reden om wat terughoudend te zijn met het aanleggen van extra harde links./%

%/
!!Permissies
Buiten de root-gebruiker kan alleen de eigenaar van een bestand of directory -- via het commando ''{{{chmod}}}'' -- toegangsrechten toekennen of intrekken. Voor hemzelf, voor leden van de groep waaronder de betrokken inode geschaard is, en voor gebruikers die noch eigenaar noch groepslid zijn. Er zijn 12 bits (oftewel vlaggen) in te stellen:

{{pref{{{tt{  User category:   ''ugt uuu ggg ooo''   //(//''u''// = user who owns it; //''g''// = member of its group; //''o''// = other; //''t''// = sticky)// 
  Bit position :   ~BA9 876 543 210   //(twelve bits)//
                   &mdash;&mdash;&mdash; &mdash;&mdash;&mdash; &mdash;&mdash;&mdash; &mdash;&mdash;&mdash;
  0001 / o=x   :   ... ... ... ..@@bgcolor(#ee6):__''x''__@@   @@bgcolor(#ee6): ''x'' @@ = //file executable / directory accessible (by others)//
  0002 / o=w   :   ... ... ... .@@bgcolor(#ee6):__''w''__@@.   @@bgcolor(#ee6): ''w'' @@ = //writable (by others)//
  0004 / o=r   :   ... ... ... @@bgcolor(#ee6):__''r''__@@..   @@bgcolor(#ee6): ''r'' @@ = //readable (by others)//
  0010 / g=x   :   ... ... ..@@bgcolor(#ee6):__''x''__@@ ...   @@bgcolor(#ee6): ''x'' @@ = //file executable / directory accessible (by group members)//
  0020 / g=w   :   ... ... .@@bgcolor(#ee6):__''w''__@@. ...   @@bgcolor(#ee6): ''w'' @@ = //writable (by group members)//
  0040 / g=r   :   ... ... @@bgcolor(#ee6):__''r''__@@.. ...   @@bgcolor(#ee6): ''r'' @@ = //readable (by group members)//
  0100 / u=x   :   ... ..@@bgcolor(#ee6):__''x''__@@ ... ...   @@bgcolor(#ee6): ''x'' @@ = //file executable / directory accessible (by owner)//
  0200 / u=w   :   ... .@@bgcolor(#ee6):__''w''__@@. ... ...   @@bgcolor(#ee6): ''w'' @@ = //writable (by owner)//
  0400 / u=r   :   ... @@bgcolor(#ee6):__''r''__@@.. ... ...   @@bgcolor(#ee6): ''r'' @@ = //readable (by owner)//
  1000 / o=t   :   ..''t'' ... ... ..@@bgcolor(#ee6):__''.''__@@   @@bgcolor(#ee6): ''T'' @@ = //sticky bit;// @@bgcolor(#ee6): ''t'' @@ = ''T'' + ''x'' 
  2000 / g=s   :   .''s''. ... ..@@bgcolor(#ee6):__''.''__@@ ...   @@bgcolor(#ee6): ''S'' @@ = //SGID;// @@bgcolor(#ee6): ''s'' @@ = ''S'' + ''x''
  4000 / u=s   :   ''s''.. ..@@bgcolor(#ee6):__''.''__@@ ... ...   @@bgcolor(#ee6): ''S'' @@ = //SUID;// @@bgcolor(#ee6): ''s'' @@ = ''S'' + ''x''
    &#x254E;                  @@color(#ee6):&#x2588;&#x2584;&#x2584;&#x2584;&#x2584;&#x2584;&#x2584;&#x2584;&#x2584;&#x2584;&#x2588;@@
    &#x2570;&#x254C;&#x254C;&#x27A4; //(octal value)//     &#x2570;&#x254C;&#x254C;&#x27A4; //(displayed by //''ls -l''//)//}}}}}}

Toekenning van het ''{{{w}}}''-bit stelt een bestand of directory open voor wijziging van de inhoud ervan. Achterwege laten van dit bit lijkt de inode daar in eerste instantie voor te behoeden, maar verhindert niet de hernoeming of verwijdering uit de directory waarin naar die inode verwezen wordt. Indirect is daarmee ook de inhoud vogelvrij: zet deze in een buffer, bewerk deze, verplaats of verwijder de oorspronkelijke inode, en sla de nieuwe inhoud op in een nieuw bestand of directory met de oude naam op de oude locatie. Deze inode is nu wel eigendom van de bewerker geworden. In bijvoorbeeld Vim gebeurt dit allemaal onder water. Om dit tegen te gaan, mag er geen ''{{{w}}}''-bit zijn gezet bij de directory waarin die inode voorkomt, of moet daar anders het sticky bit (''{{{t}}}'') zijn gezet. Samengevat: een inode kan zijn naam en aanwezigheid in een directory -- en zelfs zijn voortbestaan in het bestandssysteem! -- niet zelf beschermen, maar louter zijn inhoud en attributen voor de duur van zijn bestaan.

Omgekeerd verhindert weglating van het ''{{{w}}}''-bit bij een directory niet dat inhoud van onderliggende inodes wordt veranderd. Slechts het hernoemen en verwijderen van inodes is dan geblokkeerd, alsmede het toevoegen van nieuwe entries. Onderliggende inodes moeten in zo'n geval dus ook zichzelf beschermen door hun eigen ''{{{w}}}''-bits weg te laten. Alleen als de directory door ontbreken van het ''{{{x}}}''-bit is gebarricadeerd, kunnen onderliggende inodes er zonder eigen bewapening veilig schuilen./%

%/
;Set User ~ID-bit (SUID):
:{{_{Gezet bij programma &rArr; de uitvoering van het programma heeft dezelfde rechten als de eigenaar van het programma. //Niet lichtvaardig toepassen!//
In andere gevallen heeft dit bit voor Linux geen betekenis.}}}
;Set Group ~ID-bit (SGID):
:{{muliLine{Gezet bij programma &rArr; de uitvoering van het programma heeft dezelfde rechten als de groep van het programma. //Niet lichtvaardig toepassen!//
Gezet bij directory &rArr; nieuwe bestanden en subdirectories in de directory krijgen hetzelfde GID als de directory. Bij nieuwe subdirectories wordt bovendien ook het ~SGID-bit gezet (de andere bits van de bovenliggende directory worden echter niet overgenomen).}}}
;Sticky bit:
:{{_{Gezet bij directory &rArr; de inodes in de directory kunnen alleen worden hernoemd of verwijderd door de eigenaar van die inode, de eigenaar van de directory, of de root-gebruiker.
In andere gevallen heeft dit bit voor Linux geen betekenis.}}}/%

%/
Symbolische links zelf krijgen in Linux altijd het onveranderlijke kenmerk ''{{{lrwxrwxrwx}}}'' mee (in Mac OS volgen de automatisch toegekende rechten op zulke links wel het {{{umask}}}, en kunnen ze naderhand worden gewijzigd)./%

%/
!!User file-creation mask (umask)
Formule voor de automatische toekenning van rechten aan nieuwe inodes:''//{{{ permission }}}//{{{ = }}}//{{{mode}}}//{{{ and not }}}//{{{umask}}}//'', waarin //{{{mode}}}// = ''{{{666}}}'' voor bestanden en ''{{{777}}}'' voor directories, en //{{{umask}}}// = de waarde die het commando {{{umask}}} retourneert -- //{{{umask}}}// bepaalt dus welke permissiebits worden //uit//gezet. Per achttallig cijfer resulteert dit in:

{{pref{{{tt{  Umask digit  Permission on file  Permission on directory 
  &mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;  &mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;  &mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;
       ''0''             ''6'' = rw-             ''7'' = rwx
       ''1''             ''6'' = rw-             ''6'' = rw-
       ''2''             ''4'' = """r--"""             ''5'' = r-x
       ''3''             ''4'' = """r--"""             ''4'' = """r--"""
       ''4''             ''2'' = -w-             ''3'' = -wx
       ''5''             ''2'' = -w-             ''2'' = -w-
       ''6''             ''0'' = """---"""             ''1'' = """--x"""
       ''7''             ''0'' = """---"""             ''0'' = """---"""
}}}}}}
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Vervolg van [['Iterabiliteit' in Python]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''

In [['Iterabiliteit' in Python]] staat één scenario dat beschrijft wat er gebeurt als de {{tt t{iter}}}-functie geen enkel gehoor vindt, en zeven scenario's waarin de functie een {{tt t{"""__iter__"""}}}-method kan aanspreken. Er is nog een negende scenario mogelijk, namelijk dat {{tt t{iter}}} een {{tt t{"""__getitem__"""}}}-method aantreft voor het verrichten van het iteratiewerk./%

%/  
!!!Scenario 9: iteration by @@font-style:normal;{{tt{"""__getitem__"""}}}@@
[img[data/images/SC Python-iterator scenario 9.png]] [[Legenda|Structuurdiagrammen à la Constantine]]

Wanneer de door het {{tt t{for}}}-statement aangeroepen {{tt t{iter}}}-functie geen {{tt t{"""__iter__"""}}}-method in een object vindt maar wel een {{tt t{"""__getitem__"""}}}-method, wordt daar ook wel genoegen mee genomen als iteratie&shy;gereed&shy;schap. Het {{tt t{for}}}-mechanisme gaat dan met een zelf gegeneerde index aan de slag, te beginnen met de waarde {{tt t{0}}}. Het blijft de gevonden {{tt t{"""__getitem__"""}}} met die index als argument aanroepen, waarna het deze telkens met {{tt t{1}}} ophoogt. Dat gaat zo door totdat {{tt t{"""__getitem__"""}}} de exception ''{{tt{IndexError}}}'' afgeeft.

De boekhouding wordt in dit scenario dus door de pilot gedaan. Het enige wat de provider/deliverer-combinatie te doen staat, is leveren en "Ho!" roepen als het om wat voor reden dan ook welletjes is geweest./%

%/
+++(~SamenspelIterGetitem_PythonDoc)!!![Wat zegt de Python-documentatie erover? &darr;|show][Wat zegt de Python-documentatie erover? &uarr;|hide]
{{sans{
{{pre{
''iter(''//object//'')''
''iter(''//object//'','' //sentinel//'')''
}}}/%

%/Return an {{fblu{iterator}}} object. The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, //object// must be a collection object which supports the {{fblu{iterable}}} protocol (the {{tt t{"""__iter__()"""}}} method), or it must support the sequence protocol (the {{tt t{"""__getitem__()"""}}} method with integer arguments starting at {{tt t{0}}}). If it does not support either of those protocols, {{tt t fblu{TypeError}}} is raised. If the second argument, //sentinel//, is given, then object must be a callable object. The iterator created in this case will call //object// with no arguments for each call to its {{tt t fblu{"""__next__()"""}}} method; if the value returned is equal to sentinel, {{tt t fblu{StopIteration}}} will be raised, otherwise the value will be returned.

{{pre{
//object//.''"""__getitem__"""(''//self//'','' //key//'')''
}}}/%

%/Called to implement evaluation of {{hitt{//self//''[''//key//'']''}}}. For {{fblu{sequence}}} types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a {{fblu{sequence}}} type) is up to the {{tt t{"""__getitem__()"""}}} method. If //key// is of an inappropriate type, {{tt t fblu{TypeError}}} may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), {{tt t fblu{IndexError}}} should be raised. For {{fblu{mapping}}} types, if //key// is missing (not in the container), {{tt t fblu{KeyError}}} should be raised.
; Note
: {{tt t fblu{for}}} loops expect that an {{tt t fblu{IndexError}}} will be raised for illegal indexes to allow proper detection of the end of the sequence.
; Note
: When {{fblu{subscripting}}} a class, the special class method {{tt t fblu{"""__class_getitem__()"""}}} may be called instead of {{tt t{"""__getitem__()"""}}}. See {{fblu{{{tt t{"""__class_getitem__"""}}} versus {{tt t{"""__getitem__"""}}}}}} for more details.
}}}
===
Er zijn talloos veel manieren om met ''{{{od}}}'' ('__o__ctal __d__ump') een bestandsinhoud weer te geven. Van nature ben ik niet zo'n octale denker. Mijn favorieten zijn:/%
%/
*{{_{{{pref{{{high2{{{tt{''od -Ax -tx1z'' @@color(darkorange)://«file»//@@}}}}}}}}}
{{{
000000 49 6e 20 45 6e 67 6c 61 6e 64 20 6e 27 e9 63 6f  >In England n'.co<
000010 75 6e 64 65 72 65 6e 63 68 20 74 68 65 20 70 65  >underench the pe<
000020 6f 70 6c 65 3a 20 69 6e 74 20 6f 66 20 74 68 65  >ople: int of the<
000030 20 63 68 61 6e 67 65 72 20 74 68 65 20 70 72 6f  > changer the pro<
000040 76 69 73 69 6f 6e 20 69 74 20 6d 61 64 65 20 63  >vision it made c<
000050 6f 6e 66 69 61 6e 63 65 2e 0d 0a 4a 65 20 6a 75  >onfiance...Je ju<
000060 72 79 20 66 72 6f 6d 20 74 68 65 20 70 6f 69 6e  >ry from the poin<
000070 74 65 72 69 6f 72 20 69 6e 20 72 65 6c 69 63 74  >terior in relict<
000080 69 6f 6e 73 74 69 63 2c 20 70 72 6f 6f 66 20 6a  >ionstic, proof j<
000090 75 72 79 20 74 68 65 20 66 69 72 73 74 20 74 68  >ury the first th<
0000a0 61 74 20 66 6f 72 20 68 61 64 20 61 6e 64 20 61  >at for had and a<
0000b0 20 63 72 65 63 65 73 20 72 65 73 65 20 74 68 61  > creces rese tha<
0000c0 74 20 77 69 74 6e 65 73 73 65 6d 62 6c 79 20 62  >t witnessembly b<
0000d0 65 63 61 6d 65 20 63 61 75 73 65 20 6f 66 20 74  >ecame cause of t<
0000e0 68 61 74 20 77 61 73 20 62 65 69 6e 20 77 68 65  >hat was bein whe<
0000f0 72 65 20 77 69 74 68 20 74 68 65 20 73 65 65 6d  >re with the seem<
000100 73 65 6c 6c 65 64 20 66 72 6f 6d 20 6f 6e 65 20  >selled from one <
000110 68 65 20 6d 61 72 6b 73 20 61 20 73 6f 20 74 68  >he marks a so th<
000120 61 74 20 6d 61 64 65 20 6c 61 77 73 20 6f 66 20  >at made laws of <
000130 74 72 69 61 6c 20 69 6e 20 63 6f 75 6e 74 65 64  >trial in counted<
000140 20 77 68 69 63 68 20 67 61 76 65 20 6e 6f 74 65  > which gave note<
000150 20 61 6e 64 20 74 68 65 20 74 75 72 65 20 77 68  > and the ture wh<
000160 69 6c 6f 73 65 64 20 73 6f 63 69 61 6c 69 74 79  >ilosed sociality<
000170 20 63 61 75 73 65 64 20 74 68 65 20 31 34 74 68  > caused the 14th<
000180 2c 20 31 37 39 31 2e 0d 0a                       >, 1791...<
000189 
}}}
}}}
*{{_{{{pref{{{high2{{{tt{''od -Ax -tx1c -w''@@color(darkorange)://[//@@''32''@@color(darkorange)://]//@@ @@color(darkorange)://«file»//@@}}}}}}}}}
{{{
000000  49  6e  20  45  6e  67  6c  61  6e  64  20  6e  27  e9  63  6f  75  6e  64  65  72  65  6e  63  68  20  74  68  65  20  70  65
         I   n       E   n   g   l   a   n   d       n   ' 351   c   o   u   n   d   e   r   e   n   c   h       t   h   e       p   e
000020  6f  70  6c  65  3a  20  69  6e  74  20  6f  66  20  74  68  65  20  63  68  61  6e  67  65  72  20  74  68  65  20  70  72  6f
         o   p   l   e   :       i   n   t       o   f       t   h   e       c   h   a   n   g   e   r       t   h   e       p   r   o
000040  76  69  73  69  6f  6e  20  69  74  20  6d  61  64  65  20  63  6f  6e  66  69  61  6e  63  65  2e  0d  0a  4a  65  20  6a  75
         v   i   s   i   o   n       i   t       m   a   d   e       c   o   n   f   i   a   n   c   e   .  \r  \n   J   e       j   u
000060  72  79  20  66  72  6f  6d  20  74  68  65  20  70  6f  69  6e  74  65  72  69  6f  72  20  69  6e  20  72  65  6c  69  63  74
         r   y       f   r   o   m       t   h   e       p   o   i   n   t   e   r   i   o   r       i   n       r   e   l   i   c   t
000080  69  6f  6e  73  74  69  63  2c  20  70  72  6f  6f  66  20  6a  75  72  79  20  74  68  65  20  66  69  72  73  74  20  74  68
         i   o   n   s   t   i   c   ,       p   r   o   o   f       j   u   r   y       t   h   e       f   i   r   s   t       t   h
0000a0  61  74  20  66  6f  72  20  68  61  64  20  61  6e  64  20  61  20  63  72  65  63  65  73  20  72  65  73  65  20  74  68  61
         a   t       f   o   r       h   a   d       a   n   d       a       c   r   e   c   e   s       r   e   s   e       t   h   a
0000c0  74  20  77  69  74  6e  65  73  73  65  6d  62  6c  79  20  62  65  63  61  6d  65  20  63  61  75  73  65  20  6f  66  20  74
         t       w   i   t   n   e   s   s   e   m   b   l   y       b   e   c   a   m   e       c   a   u   s   e       o   f       t
0000e0  68  61  74  20  77  61  73  20  62  65  69  6e  20  77  68  65  72  65  20  77  69  74  68  20  74  68  65  20  73  65  65  6d
         h   a   t       w   a   s       b   e   i   n       w   h   e   r   e       w   i   t   h       t   h   e       s   e   e   m
000100  73  65  6c  6c  65  64  20  66  72  6f  6d  20  6f  6e  65  20  68  65  20  6d  61  72  6b  73  20  61  20  73  6f  20  74  68
         s   e   l   l   e   d       f   r   o   m       o   n   e       h   e       m   a   r   k   s       a       s   o       t   h
000120  61  74  20  6d  61  64  65  20  6c  61  77  73  20  6f  66  20  74  72  69  61  6c  20  69  6e  20  63  6f  75  6e  74  65  64
         a   t       m   a   d   e       l   a   w   s       o   f       t   r   i   a   l       i   n       c   o   u   n   t   e   d
000140  20  77  68  69  63  68  20  67  61  76  65  20  6e  6f  74  65  20  61  6e  64  20  74  68  65  20  74  75  72  65  20  77  68
             w   h   i   c   h       g   a   v   e       n   o   t   e       a   n   d       t   h   e       t   u   r   e       w   h
000160  69  6c  6f  73  65  64  20  73  6f  63  69  61  6c  69  74  79  20  63  61  75  73  65  64  20  74  68  65  20  31  34  74  68
         i   l   o   s   e   d       s   o   c   i   a   l   i   t   y       c   a   u   s   e   d       t   h   e       1   4   t   h
000180  2c  20  31  37  39  31  2e  0d  0a
         ,       1   7   9   1   .  \r  \n
000189
}}}
}}}
In de linker kantlijn staan dankzij de optie ''{{{-Ax}}}'' hexadecimale offsetnummers (de telling begint bij {{{0}}}). Het laatste getal (linksonder) is de bestandsgrootte. Met de optie ''{{{-Ad}}}'' zijn decimale offsetnummers en bestandsomvang te verkrijgen.

De specificatie ''{{{x1}}}'' in de ''{{{-t}}}''-optie bestelt hexadecimale weergave van de afzonderlijke bytes. De toevoeging ''{{{z}}}'' geeft aan dat je de afdrukbare tekens in de rechter kantlijn zichtbaar gemaakt wilt hebben. De specificatie ''{{{c}}}'' bestelt weergave van het ~ASCII-teken, backslash-escape of octale code (zie de ''é'' op offset {{{13}}} en de CR+~LF-afsluiting aan het eind).

De inhoud van deze op Windows en in Latin-1 (codepage 1252) gecodeerde @@color(darkorange)://«file»//@@ was overigens:
<<<
@@color(darkorange)://1e regel:&nbsp;//@@ In England n'écounderench the people: int of the changer the provision it made confiance.@@color(darkorange):&#x21B5;@@
@@color(darkorange)://2e regel:&nbsp;//@@ Je jury from the pointerior in relictionstic, proof jury the first that for had and a creces rese that witnessembly became cause of that was bein where with the seemselled from one he marks a so that made laws of trial in counted which gave note and the ture whilosed sociality caused the 14th, 1791.@@color(darkorange):&#x21B5;@@
<<<
/%
!info
|Name|HideTiddlerTags|
|Source|http://www.TiddlyTools.com/#HideTiddlerTags|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|hide a tiddler's 'tagged' and 'tagging' displays (if any)|
Usage:
<<<
{{{
<<tiddler HideTiddlerTags>>
<<tiddler HideTiddlerTags with: TiddlerTitle>>
}}}
<<<
!end
!show
<<tiddler {{
	var title="$1";
	if (title=='$'+'1') {
		var here=story.findContainingTiddler(place);
		if (here) title=here.getAttribute('tiddler');
	}
	var t=story.getTiddler(title); if (t) {
		var e=t.getElementsByTagName('*');
		for (var i=0; i<e.length; i++)
			if (hasClass(e[i],'tagging')||hasClass(e[i],'tagged'))
				e[i].style.display='none';
	}
'';}}>>
!end
%/<<tiddler {{
	var src='HideTiddlerTags';
	src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with: [[$1]]>>
*''{{{SYSTABLESPACE}}}'' -- Information about every ~DB2 table space
**''{{{SYSTABLES}}}'' -- Information about every ~DB2 table
***''{{{SYSTABSTATS}}}'' -- Partitioned table space statistics by partition
***''{{{SYSTRIGGERS}}}'' -- Information about every trigger defined to the ~DB2 subsystem
***''{{{SYSCOLUMNS}}}'' -- Information about every column of every ~DB2 table or view
****''{{{SYSCOLDIST}}}'' -- Cardinality, frequent value, and non-padded frequent value distribution sttistics for the first key column of an index key
****''{{{SYSCOLDISTSTATS}}}'' -- The non-uniform distribution statistics for the ten most frequently occurring values for the first key column in a partitioned index
****''{{{SYSCOLSTATS}}}'' -- The partition statistics for selected columns
****''{{{SYSFIELDS}}}'' -- Information on field procedures implemented for ~DB2 tables
***''{{{SYSRELS}}}'' -- The referential integrity information for every relationship defined in ~DB2
****''{{{SYSLINKS}}}'' -- Information about the links between ~DB2 Catalog tables
****''{{{SYSFOREIGNKEYS}}}'' -- Information about every column participating in foreign keys
***''{{{SYSTABCONST}}}'' -- Information about every unique constraint (primary key or unique key) created in ~DB2 V7 or later
****''{{{SYSKEYCOLUSE}}}'' -- Columns that participate in unique constraints (primary key or unique key) from the {{{SYSTABCONST table}}}
***''{{{SYSCHECKS}}}'' -- {{{CHECK}}} constraint specifications
****''{{{SYSCHECKS2}}}'' -- Information about {{{CHECK}}} constraints on ~DB2 Catalog tables created for V7 or later
****''{{{SYSCHECKDEP}}}'' -- Column references for {{{CHECK}}} constraints
***''{{{SYSINDEXES}}}'' -- Information about every ~DB2 index
****''{{{SYSINDEXPART}}}'' -- Information about the physical structure and storage of every ~DB2 index
****''{{{SYSKEYS}}}'' -- Information about every column of every ~DB2 index
****''{{{SYSINDEXSTATS}}}'' -- Partitioned index statistics by partition
***''{{{SYSSYNONYMS}}}'' -- Information about every ~DB2 synonym
***''{{{SYSTABAUTH}}}'' -- Table privileges held by ~DB2 users 
****''{{{SYSCOLAUTH}}}'' -- The {{{UPDATE}}} privileges held by ~DB2 users on table or view columns
***''{{{SYSCONSTDEP}}}'' -- Information regarding columns that are dependent on {{{CHECK}}} constraints and user-defined defaults
**''{{{SYSTABLEPART}}}'' -- Information about the physical structure and storage of every ~DB2 table space
----
*''{{{SYSVTREE}}}'' -- The first 4000 bytes of the internal representation of the view; the remaining portion of longer or complex views is stored in {{{SYSVLTREE}}}
**''{{{SYSVLTREE}}}'' -- The first 4000 bytes of the internal representation of longer or complex views
**''{{{SYSVIEWS}}}'' -- The SQL{{{ CREATE VIEW }}}statement for every ~DB2 view
**''{{{SYSVIEWDEP}}}'' -- A cross-reference of ~DB2 objects required by ~DB2 views
----
*''{{{SYSSTOGROUP}}}'' -- Information about every ~DB2 storage group
**''{{{SYSVOLUMES}}}'' -- A cross-freference of DASD volumes assigned to ~DB2 storage groups
----
*''{{{SYSDATABASE}}}'' -- Information about every ~DB2 database
**''{{{SYSDBAUTH}}}'' -- Database privileges held by ~DB2 users
----
*''{{{SYSSEQUENCES}}}'' -- Information about identity columns and {{{SEQUENCE}}} objects
**''{{{SYSSEQUENCESDEP}}}'' -- Records the dependencies of identity columns on tables
<<tiddler HideTiddlerTags>><html><img src="core/EenJaarOfWat-groen-blokje.png" style="position:relative;top:0.4em;" width="26"></html>&#x2006; [[ALGOL 60]], de [[Backus-Naur Form]], [[stroomschema's]] en [[Nassi-Shneidermandiagrammen]] waren een jaar of wat geleden als een aan het vak Numerieke Analyse gekoppeld bijkomstig&shy;heidje op mijn toenmalige leerweg gestrooid. Een jaar later volgde een tweede confrontatie. Gesteld voor de opgave via een zelf te schrijven Algol-programma een mechanica&shy;probleem op te lossen, bruiste ik onophoudelijk van steeds nieuwe ideeën voor een mooie opmaak en aankleding van de programma&shy;uitvoer. In die mate, dat ik er 's nachts wakker van lag. Na afloop van het desbetreffende practicum moest ik mezelf daar maar liever tegen beschermen, vond ik. Ik zou mij dus voortaan verre proberen te houden van automatiserings&shy;werkzaamheden. Alleen voor zover het Nassi-Shneider­man&shy;diagrammen aangaat, is dat ook aardig gelukt.

<html><img src="core/EenJaarOfWat-groen-blokje.png" style="position:relative;top:0.4em;" width="26"></html>&#x2006; Welkom op deze webstek. Van het aandachts&shy;gebied dat hier bestreken wordt, beginnen de contouren zich waarschijnlijk nu al een beetje af te tekenen. De context van mijn initiatief verdient misschien nog wel enige toelichting. Sinds ik me op de valreep van de vorige eeuw {{z{HTML}}} en dergelijke heb eigen gemaakt, houd ik mijn mede-IT'ers -- en mijzelf&#x200a;! -- via het toevallig aanwezige intranet op de hoogte van opgediepte wetens&shy;waardig&shy;heden die ter plaatse niet in handzaam formaat gedocumenteerd zijn. Nu de afstand tot mij bekende IT-geïnter&shy;esseerden wat groter is geworden, lijkt deze het gemakkelijkst te overbruggen door zulke notities dan maar in een publiek toegankelijk medium vast te leggen. Zodoende. En in de hoop dat nog een jaar of wat vol te houden.
/%

%/+++(~WelkomBediening)!!!![Navigatie binnen de site en naar buiten &darr;|toon instructies][Navigatie binnen de site en naar buiten &uarr;|verberg instructies]
<html><img src="core/EenJaarOfWat-groen-blokje.png" style="position:relative;top:0.4em;" width="26"></html>&#x2006; Deze webstek (Hollands: website) is uitgevoerd als één nogal uit de kluiten gewassen {{z{HTML}}}-pagina van het type [[TiddlyWiki]]. Afzonderlijke artikelen worden [[tiddlers|Tiddler]] genoemd en zijn vergelijkbaar met briefjes op een prikbord. De tiddlers zijn onderling verbonden door middel van hyperlinks. Bovendien zijn ze toegankelijk via het hoofdmenu{{ref{&#x200a;[[[1]|##1]]}}} in het linker zijpaneel, via hun [[tags|Tags]] (trefwoorden), en via de registers in het rechter zijpaneel. Beide panelen zijn weg te klappen en terug te halen met de pijltjes&shy;knoppen {{hi2 sans fwhi{►}}} en {{hi2 sans fwhi{◄}}} bovenaan tegen de linker en rechter vensterrand. Je kunt ook tegen de stroom van hyperlinks in navigeren en tiddler-hoppen. Iedere tiddler heeft namelijk rechtsboven een eigen menuutje: onder 'more' > 'references' vind je de tiddlers die naar de huidige verwijzen, terwijl 'more' > 'jump' je de gelegenheid biedt naar één van de andere open tiddlers te springen. Eerder in dezelfde sessie bezochte tiddlers zijn terug te halen via het kruimelspoor. Dit kan boven in het scherm zichtbaar zijn, en zo niet, dan is het altijd nog bereikbaar via het hoofdmenu. Ten slotte kun je met de zoekfuncties 'search' en 'more' > 'goto tiddler' (te vinden boven de registers in het rechter paneel) zoeken naar tekstfragmenten en tiddlertitels.

<html><img src="core/EenJaarOfWat-groen-blokje.png" style="position:relative;top:0.4em;" width="26"></html>&#x2006; De knop <html><img src="core/town-a0.png" style="position:relative;top:0.3em;" width="20"></html> rechts boven de titel van deze site voert naar buiten, en wel naar het voorportaal [[Le Dépôt|../index.html]], dat ook mijn e-mailadres bevat. Deze knop is de enige hyperlink die de huidige site verruilt voor een andere webpagina, tenzij je tijdens het klikken de control-, command- en/of shift-toets ingedrukt houdt (afhankelijk van je browser en besturingssysteem). De overige naar buiten gerichte hyperlinks, herkenbaar aan hun onderstreping, openen de bestemming in een nieuw tabblad van je browser. Zoals de link 'Le Dépôt' in deze alinea. Tot zo ver de uitleg in dit korte bestek.

----
|plain |k
| <html><a name="1">[1]</a></html>|Het hoofdmenu ontsluit niet //alle// tiddlers. Zeker in het begin zal de steun die het te bieden heeft erg mager zijn. Geef de menustructuur maar even de tijd om verder uit te groeien. |
~DB2 is een tamelijk complex geheel van logische en fysieke componenten. Aan de hand van [[[1]|##1]] en [[DB2 for z/OS|http://www-01.ibm.com/support/knowledgecenter/SSEPEK/db2z_prodhome.html?lang=nl]] heb ik geprobeerd de belangrijkste componenten en hun onderlinge samenhang in kaart te brengen. In onderstaand klassendiagram zijn alleen de groene blokjes direct van belang voor de gegevensopvrager, terwijl de grijze laten zien wat er onder de motorkap nog meer bij een ~DB2-database meespeelt.

&nbsp; &nbsp;[img[DB2-structuur|data/images/CD DB2.png]]

Om het diagram nog een beetje overzichtelijk te houden, heb ik de indexspace niet ingetekend. De constructie hiervan lijkt sterk op die van de tablespace: (1) een indexspace behoort bij één database, (2) bevat één index, en (3) kan eventueel gepartioneerd zijn, waarbij elke partitie een deel van dezelfde index bevat. De bij de klassen {{{PartitionedTS}}} en {{{Table}}} in formele OCL uitgeschreven constraints stellen simpelweg: "Iedere partitioned tablespace bevat niet meer dan één tabel" resp. "Iedere tabel bevindt zich in één tablespace". Ook voor indexen geldt dat iedere index in één indexspace zit. Op ~AV2 hebben we één subsystem, ''{{{DB2}}}'' geheten.

De verhouding database&ndash;schema&ndash;table is niet voor iedereen duidelijk, vooral als het op qualifying aankomt. Coleman heeft hier in zijn [[DB2tutor|http://ibmsystemsmag.com/Blogs/db2utor/Archive/object-creator-schema-qualifier-and-owner/]]-blog een begrijpelijk exposé over opgesteld. Ook als je naar het datamodel van de [[DB2-catalog|Hiërarchieën in de DB2-catalog]] kijkt, wordt het allemaal wel inzichtelijk. Hieronder heb ik de belangrijkste componenten en hun onderlinge samenhang in beeld gebracht. De tekentechniek die ik daarbij heb toegepast, is aan de [[functionele datamodellering volgens Shipman|Voorbij de functionele datamodellering]] ontleend. De blauwe blokjes stellen tabellen in het schema {{{SYSIBM}}} voor en de omcirkelingen geven primaire sleutels aan.

&nbsp; &nbsp;[img[Metatabellen|data/images/DM DB2-Catalog.png]]

Gezien dit diagram is het niet zo vreemd meer dat individuele tablespaces plegen te worden benoemd met''// {{{«databaseName»}}}//{{{.}}}//{{{«tablespaceName»}}}//'', en tabellen met''// {{{«schemaName»}}}//{{{.}}}//{{{«tableName»}}}//''. Maar wat //is// een schema nu eigenlijk voor iets? Zie het maar als een extra abstractieniveau, een logische collectie of -- in programmeurstermen gesproken -- een namespace. In het algemeen is de keuze voor het schema waarin een object bij zijn definitie moet worden ondergebracht niet gebonden aan het schema van het object waarnaar eerstgenoemd object verwijst. Verder heb ik vastgesteld dat de tabellen in schema {{{SYSIBM}}} niet allemaal tot de database {{{DSNDB06}}} behoren, en dat niet alle tabellen van {{{DSNDB06}}} in {{{SYSIBM}}} zijn ondergebracht. Wat is nu werkelijk de catalog, {{{DSNDB06}}} of {{{SYSIBM}}}? Over [[versie 10|http://www-01.ibm.com/support/knowledgecenter/SSEPEK_10.0.0/com.ibm.db2z10.doc.sqlref/src/tpc/db2z_catalogtablesintro.dita?cp=SSEPEK_10.0.0%2F10-0]] stelt IBM: //~DB2® for z/OS® maintains a set of tables (in database ~DSNDB06) called the ~DB2 catalog. (...) All catalog tables are qualified by SYSIBM. Do not use this qualifier for user-defined tables.// Over [[versie 11|http://www-01.ibm.com/support/knowledgecenter/SSEPEK_11.0.0/com.ibm.db2z11.doc.intro/src/tpc/db2z_catalog.dita]] is IBM nog wat uitgesprokener: //The system database ~DSNDB06 contains the ~DB2 catalog.//

Er vielen me nog meer dingen op toen ik zo in de catalog rondkeek. Zo is er geen eigen tabel voor het fenomeen //schema// in de catalog aanwezig (de tabel {{{SYSIBM.SYSSCHEMAAUTH}}} heeft geen primaire sleutel en lijkt me daarmee niet wat ik zocht). Dat verbaast me. Wordt het dan niet in de catalog opgetekend wanneer er met {{hitt z{''CREATE SCHEMA //«schemaName»//''}}} een nieuw schema wordt aangelegd? In [[[1]|##1]] wordt inderdaad uitdrukkelijk gesteld: //A ~DB2 schema is not really a ~DB2 object. You cannot explicitly CREATE or DROP a schema. The schema is implicitly //created// when the first ~DB2 object is created using that schema name.// Wellicht gold dat voor versie 8 en ouder, en niet meer voor de nieuwere ~DB2-versies. Wij werken nog met versie 10 [[[2]|##2]], terwijl IBM bij versie 11 is (stand oktober 2015).

Een andere opvallende ontdekking is het ontbreken van een aparte catalogtabel voor de indexspace. Dat is echter toch niet zo raar, als je bedenkt dat index en indexspace in een één-op-één verhouding tot elkaar staan [[[3]|##3]]. Eén tabel voor beide is dus voldoende.

Alle ~DB2-componenten moeten uiteindelijk ergens in de bestandsstructuur van z/OS worden ondergebracht. Onderstaand klassendiagram geeft aan hoe dat georganiseerd is voor de tablespaces. Ook hier heb ik omwille van de overzichtelijkheid de indexen c.q. indexspaces weggelaten.

[img[Fysieke DB2-structuur|data/images/CD DB2 physical.png]]

De afgebeelde constraints luiden in mensentaal (met tussen haakjes een aanvulling voor indexen): "Iedere simple of segmented tablespace (of non-partitioned index) is ondergebracht in één storagegroup" resp. "Ieder ~VSAM-bestand bevat materiaal van één tablespace (of één index)". Hiermee treedt ook nog een extra verschil tussen segmented en partitioned tablespaces aan de dag: een partitioned tablespace mag wèl worden verdeeld over verscheidene storagegroups.

----
|plain |k
|<html><a name="1">[1]</a></html>|<<tiddler Bibliografie##Mullins>> |
|<html><a name="2">[2]</a></html>|Opgevraagd met {{hitt z{''{{{SELECT GETVARIABLE('SYSIBM.VERSION') FROM SYSIBM.SYSDUMMY1;}}}''}}}. |
|<html><a name="3">[3]</a></html>|De index op de combinatie {{{dbname}}} + {{{indexspace}}} legt geen uniciteitsbeperking op. Maar in de praktijk is die er wel. |
Als ik me goed herinner, heb ik mijn eerste kennismaking met Lisp te danken aan een enigszins ontmoedigend getiteld boek van Bob Walraet.{{ref{[[[1]|##1]]}}} Vervolgens heb ik het bestaan van deze taal jarenlang genegeerd, totdat ik bij mijn pogingen Rebol te doorgronden op het idee kwam ook de mechanismen van Lisp nog eens goed te bekijken. Er zijn namelijk veel overeenkomsten. Het fenomeen //block// in Rebol doet denken aan de gegevensstructuur //list// in Lisp ('&#x200b;''{{sans z{LIS}}}''t ''{{sans z{P}}}''rocessing') en in beide talen is het precieze moment waarop een uitdrukking wordt geëvalueerd niet meteen doorgrondelijk. Naast de oppervlakkige gelijkenis (Lisp moet zeker een van de inspiratiebronnen voor Rebol zijn geweest) zijn er niettemin veel fundamentele verschillen. Dat blijkt echter helemaal geen bezwaar. Naast de overeenkomsten zijn het juist de contrasten die tot een beter begrip van beide talen leiden.

Er bestaan vele Lisp-dialecten. Om autodidactische redenen heb ik voor Scheme gekozen.{{ref{[[[2]|##2]]}}} Net even strakker, consistenter, minimalistischer. +++(~SchemeIntro_Voorbeelden)[Enkele voorbeelden: &darr;|show][Enkele voorbeelden: &uarr;|hide]
* De Lisp-uitdrukkingen ''{{hitt pblu z{nil}}}'' en ''{{hitt pblu z{()}}}'' stellen beide een lege //list// voor. Scheme ondersteunt alleen de haakjesnotatie, aangezien dat de meest logische vorm voor een lijst is. Ik ervaar ''{{hitt pblu z{nil}}}'', dat in Lisp wordt geprefereerd, wel als leesbaarder.
* {{_{Functies worden in Lisp op een andere manier gedefinieerd dan andere waarden.
* <<eval [=[{{pref hitt pblu z{''(defun'' //functionName// ''(''//parameterName// $___$0'')'' //body//$___'')''}}}]=] f3m>>
* <<eval [=[{{pref hitt pblu z{''(defvar'' //varName// //value//'')''}}})]=] f3m>>
Niet alleen de formulering verschilt, er is ook echt sprake van verschillende //namespaces//. In Scheme daarentegen is er slechts één gemeenschappelijke namespace voor beide en is de syntax geüniformeerd. Bovendien wordt de ook in Lisp bestaande {{tt t{lambda}}}-expressie in de functiedefinitie hergebruikt:
* <<eval [=[{{pref hitt pblu z{''(define'' //functionName// ''(lambda (''//parameterName// $___$0'')'' //body//$___''))''}}}]=] f3m>>
* <<eval [=[{{pref hitt pblu z{''(define'' //varName// //value//'')''}}})]=] f3m>>
Desondanks is er toch een alternatieve vorm <<eval [=[{{pref hitt pblu z{''(define (''//functionName// //parameterName// $___$0'')'' //body//$___'')''}}}]=] f3m>> beschikbaar gesteld. Dit wordt wel ietwat smalend de 'defun syntax' voor {{tt t{define}}} genoemd. Ik smaal niet mee, maar er zijn genoeg auteurs die deze notatie mijden.}}}
* {{_{In Lisp wordt van //functions// gesproken, terwijl Scheme het bij //procedures// houdt. Dit onderscheid heeft niets te maken met hoe er in [[ALGOL 60]] en Pascal tegenaan wordt gekeken (//procedure// heeft geen returnwaarde en //function// wel). De makers van Scheme (Guy Steel en Gerald Jay Sussman) zagen het woord //procedure// als een verbijzondering van //function//, in de zin dat een proceduredefinitie beschrijft welke handelingen moeten worden verricht om tot een bepaald resultaat te komen, terwijl een functiedefinitie ook kan volstaan met een specificatie van de eisen waaraan het resultaat moet voldoen. Vergelijk deze in pseudo-Python geschreven definities van de functie ^^10^^log //x//:
* {{pre{
{{fgre{//# Definition by declaration//}}}
def log10(x):"""
    let 10 ** y == x
    return y"""
}}}
* {{pre{
{{fgre{//# Definition by procedure//}}}
def log10(x):"""
    return log(x) / log(10)"""
}}}
(De laatste definitie doet een beroep op de natuurlijke logaritme &ell;n //x//, maar dat doet niets af aan het procedurele karakter ervan.)
}}}
* Scheme was het eerste Lisp-dialect met //lexicale scopes//. Tegenwoordig bestaan er nauwelijks meer levende Lisp-dialecten die //dynamische scopes// toepassen, met Emacs Lisp als notoire uitzondering.
* De Scheme-macro's zijn [[hygiënisch|https://en.wikipedia.org/wiki/Hygienic_macro]].{{ref{[[[3]|##3]]}}} Of dat hinderlijke beperkingen oplegt, is me bij het schrijven van deze zin nog niet duideljik. Eerst [[The Adventures of a Pythonista in Schemeland|http://www.phyast.pitt.edu/~micheles/scheme/TheAdventuresofaPythonistainSchemeland.pdf]] maar eens doornemen.{{ref{[[[4]|##4]]}}}

===
 Bovendien is er dat tovenaarsboek vol Scheme-spreuken waarvan een mede-auteur tevens een van de uitvinders van Scheme is.{{ref{[[[5]|##5]]}}} Dan resteert nog wel de vraag: welke Scheme? [[Chez Scheme|https://scheme.com/]], [[Chicken|http://code.call-cc.org/]] en [[Racket|https://racket-lang.org/]] leken me de meest levenskrachtige implementaties. Van die drie is eerstgenoemde de eenvoudigste. Daar komt nog bij, dat degene die Chez Scheme gebouwd heeft ook een nogal degelijk Scheme-boek heeft geschreven,{{ref{[[[6]|##6]]}}} waar de gebruikershandleiding dan weer naadloos op aansluit.{{ref{[[[7]|##7]]}}} Het is daarom Chez Scheme geworden.

Voor het geval ik de Lisp-wereld nog eens aan de kant schuif om de kennis ervan na jaren dan toch weer snel te willen oprakelen, heb ik hier de essenties van enkele Scheme-constructies geschetst, voorafgegaan door een uitleg van de grafische en tekstuele talen waarin ik dat doe:
* [[Naast Scheme]]
* [[In de spelonken van Scheme]]
* [[In de kelders van Scheme]]
* [[Aan de oppervlakte van Scheme]]

----
|plain |k
|<html><a name="1">[1]</a></html>|<<tiddler Bibliografie##Walraet>> |
|<html><a name="2">[2]</a></html>|<<tiddler Bibliografie##RnRS>> |
|<html><a name="3">[3]</a></html>|<<tiddler Bibliografie##Clinger>> |
|<html><a name="4">[4]</a></html>|<<tiddler Bibliografie##Simionato>> |
|<html><a name="5">[5]</a></html>|<<tiddler Bibliografie##A&S>> |
|<html><a name="6">[6]</a></html>|<<tiddler Bibliografie##Dybvig>> Bestrijkt [[R6RS|Revised Report on the algorithmic language Scheme]]. |
|<html><a name="7">[7]</a></html>|<<tiddler Bibliografie##CSUG>> Bestrijkt [[R6RS|Revised Report on the algorithmic language Scheme]]. |
<<tiddler [[{}::togglesliders]]>> Ter opfrissing van het geheugen hieronder een exposé van acht normaalvormen waaraan een relatie zoal zou kunnen voldoen. De eerste heeft betrekking op de interne structuur van attributen. De tweede, derde en ~Boyce-Codd normaalvormen hebben betrekking op afhankelijkheden tussen primaire en niet-primaire attributen. De vierde en vijfde normaalvormen gaan over afhankelijkheden tussen primaire attributen onderling. De zesde en domein/sleutel normaalvorm besluiten de reeks. Afhankelijkheden zoals hier behandeld kunnen [[grafisch|Afhankelijkheidsdiagrammen]] worden verbeeld. Dat is de vorm die ik hieronder voor de presentatie van normaliseringsrecepten heb gekozen./%
%/
++++(1NV)!![1NV &ndash; Eerste normaalvorm &darr;|toon 1NV][1NV &ndash; Eerste normaalvorm &uarr;|verberg 1NV]
De populaties van alle attributen bestaan alleen uit atomaire waarden.

[img[From 0NF to 1NF|data/images/DD 1NF.png]] 
===/%

%/++++(2NV)!![2NV &ndash; Tweede normaalvorm &darr;|toon 2NV][2NV &ndash; Tweede normaalvorm &uarr;|verberg 2NV]
De relatie voldoet aan de 1NV. Elk niet-primair attribuut is volledig functioneel afhankelijk van de primaire sleutel.
*//Een attribuut dat tot één van de kandidaatsleutels behoort, wordt een __primair attribuut__ genoemd.//
*//Een __kandidaatsleutel__ is een attribuut of combinatie van attributen welke voldoet aan de uniciteits- en de minimaliteitsregel. De minimaliteitsregel houdt in dat het niet mogelijk is één van de attributen uit de combinatie te verwijderen zonder de uniciteitsregel te schenden.// 
*//Attribuut //Y// is __functioneel afhankelijk__ van attribuut //X// als bij elke verschillende waarde van //X// slechts één waarde van //Y// hoort.//
*//Attribuut //Y// is __volledig afhankelijk__ van de attributenverzameling //X// indien //Y// niet functioneel afhankelijk is van welke willekeurige deelverzameling attributen van //X// (uitgezonderd //X// zelf) dan ook//.
[img[From 1NF to 2NF|data/images/DD 2NF.png]] 
===/%

%/++++(3NV)!![3NV &ndash; Derde normaalvorm &darr;|toon 3NV][3NV &ndash; Derde normaalvorm &uarr;|verberg 3NV]
De relatie voldoet aan de 2NV. Elk niet-primair attribuut is niet-transitief afhankelijk van de primaire sleutel.
*//Attribuut //Y// is __transitief afhankelijk__ van de verzameling attributen //X// indien://
**Y// functioneel afhankelijk is van attribuut //Z// en//
**Z// functioneel afhankelijk is van //X// en//
**Z// niet functioneel afhankelijk is van //Y// en//
**X// niet functioneel afhankelijk is van //Z.
[img[From 2NF to 3NF|data/images/DD 3NF.png]]
===/%

%/++++(BCNV)!![BCNV &ndash; Boyce-Codd normaalvorm &darr;|toon BCNV][BCNV &ndash; Boyce-Codd normaalvorm &uarr;|verberg BCNV]
De relatie voldoet aan de 1NV. Elke determinant is een kandidaatsleutel.
*//De BCNV heeft geen betrekking op redundanties in relaties, maar op update-anomalieën.//
*//De verzameling attributen //X// is een __determinant__ indien een ander attribuut //Y// volledig functioneel afhankelijk van //X// is.///%
%/
Een relatie voldoet aan de BCNV indien zij geen ~Boyce-Codd afhankelijkheden bevat.
*//Attribuut //Y// is __~Boyce-Codd afhankelijk__ van de attributenverzameling //X// indien //X// functioneel afhankelijk is van een verzameling attributen waartoe //Y// behoort.///%
%/
Het meest vertrouwde voorbeeld van een relatie die wel in de 3NV maar niet in de BCNV staat, is {{{ADRES}}} met de attributen {{{Straat}}}, {{{Huisnr}}}, {{{Postcode}}} en {{{Plaats}}}. Kandidaatsleutels (accolades geven meerwaardige feiten aan):
*<html><code>{Straat, Huisnr, Plaats}</code></html>
*<html><code>{Postcode, Huisnr}</code></html>
Functionele afhankelijkheden (de pijl wijst naar de functioneel afhankelijke  oftewel gedetermineerde elementen):
*<html><code>{Straat, Huisnr, Plaats}</coe></html> &rarr; {{{Postcode}}}
*{{{Postcode}}} &rarr; {{{Straat}}}
*{{{Postcode}}} &rarr; {{{Plaats}}}
{{{Postcode}}} alleen is wel een determinant maar geen kandidaatsleutel. {{{Straat}}} en {{{Plaats}}} zijn elk ~Boyce-Codd afhankelijk van {{{Postcode}}}.

[img[From 3NF to BCNF|data/images/DD BCNF.png]]
Bovenstaande relatie R heeft twee kandidaatsleutels. Welke van deze twee aanvankelijk als primaire sleutel was gekozen, heeft geen invloed op het standaardrecept voor verdere normalisatie vanuit 3NV: splits de ~Boyce-Codd afhankelijkheid af tot een afzonderlijke relatie (R2), en verwijder de gedetermineerde in deze afhankelijkheid uit de oorspronkelijke relatie (R1). Deze oplossing is boven de streep getekend. Maar wat te denken van het alternatieve recept onder de streep: verwijder juist de ~Boyce-Codd //determinant// (R1'). In beide gevallen gaat de functionele afhankelijkheid {Y,&nbsp;Z} &rarr; X verloren. Maar het standaardrecept laat bovendien {Y,&nbsp;Z} &rarr; A vallen! Anderzijds is een voordeel van het standaardrecept, dat het -- iets anders geformuleerd -- ook al werkt vanuit 1NV: breng de functionele afhankelijkheden van determinanten die geen kandidaatsleutel zijn onder in een aparte relatie en verwijder de betrokken gedetermineerde uit de oorspronkelijke relatie.

Het verlies van afhankelijkheden zou je kunnen compenseren met een extra relatie R3 of R3', maar dan haal je het oorspronkelijke probleem weer terug, zij het nu op databaseniveau. Een dilemma.

Denk, om de hierboven getekende recepten wat sprekender te maken, eens aan X = {{{Postcode}}}, Y = <html><code>{Plaats, Straat}</code></html>, Z = {{{Huisnr}}} en A = {{{Waarde}}}. Beide recepten laten de afhankelijkheid {{{{Plaats}}},&nbsp;{{{Straat}}},&nbsp;{{{Huisnr}}}} &rarr; {{{Postcode}}} vallen, en het standaardrecept ook nog eens de alternatieve toegang tot het attribuut {{{Waarde}}} in de vorm van {{{{Plaats}}},&nbsp;{{{Straat}}},&nbsp;{{{Huisnr}}}} &rarr; {{{Waarde}}}.
===/%

%/++++(4NV)!![4NV &ndash; Vierde normaalvorm &darr;|toon 4NV][4NV &ndash; Vierde normaalvorm &uarr;|verberg 4NV]
De relatie voldoet aan de BCNV. Er komt bovendien geen niet-triviale meerwaardige afhankelijkheid in de relatie voor.
*//De attributenverzamelingen //X//, //Y// en //Z// vormen  __meerwaardige afhankelijkheid__ indien //X// en //Y// enerzijds en //X// en //Z// anderzijds twee onderling onafhankelijke meerwaardige feiten vormen. (Een relatie kan alleen een meerwaardige afhankelijkheid bevatten indien er ten minste twee meerwaardige feiten met ten minste één overlappend attribuut in voorkomen. De primaire sleutel moet dus ook uit minimaal drie attributen bestaan.)//
*//De attributenverzamelingen //X// en //Y// vormen een __meerwaardig feit__ indien://
**//bij elke waarde van //X// één of meer waarden van //Y// kunnen horen en//
**//bij elke waarde van //Y// één of meer waarden van //X// kunnen horen.//
*//Functionele afhankelijkheid wordt in dit verband niet als een speciaal geval van meerwaardig feit beschouwd. Beide begrippen sluiten elkaar hier dus even uit. [[Elders|Afhankelijkheidsdiagrammen]] wordt nader op het begrip //niet-triviaal// ingegaan.///%
%/
Deze normaalvorm heeft betrekking op afhankelijkheden tussen primaire attributen onderling. Relaties met een primaire sleutel bestaande uit één of twee attributen voldoen per definitie aan de 4NV, want voor een meerwaardige afhankelijkheid is een primaire sleutel van minstens drie attributen nodig.

[img[From BCNF to 4NF|data/images/DD 4NF.png]]
===/%

%/++++(5NV)!![5NV (PJNV) &ndash; Vijfde normaalvorm (project-join normaalvorm) &darr;|toon 5NV][5NV (PJNV) &ndash; Vijfde normaalvorm (project-join normaalvorm) &uarr;|verberg 5NV]
De relatie voldoet aan de 4NV, en het is onmogelijk haar te vervangen door twee of meer van haar projecties op basis van gedeelten van de kandidaatsleutel(s) zonder dat hierbij informatie verloren gaat.
*//Verliesvrije decompositie houdt in dat een join van de resulterende relaties weer de oorspronkelijke relatie oplevert.//
[img[From 4NF to 5NF|data/images/DD 5NF (PJNF).png]] 
===/%

%/++++(6NV)!![6NV &ndash; Zesde normaalvorm &darr;|toon 6NV][6NV &ndash; Zesde normaalvorm &uarr;|verberg 6NV]
De relatie kent geen niet-triviale joinafhankelijkheden. Evenals bij 5NV is verliesvrije decompositie weer een vereiste, maar deze keer worden de projecties worden gebaseerd op echte subsets van //alle// attributen.

[img[To 6NF|data/images/DD 6NF.png]]
===/%

%/++++(DSNV)!![DSNV (DKNF) &ndash; Domein/sleutel normaalvorm &darr;|toon DSNV][DSNV (DKNF) &ndash; Domein/sleutel normaalvorm &uarr;|verberg DSNV]
Anders dan voorgaande normaalvormen is de //domain-key normal form// niet gebaseerd op  de traditionele afhankelijkheden (functioneel, meerwaardig, join), maar doet deze een beroep op meer primitieve begrippen. Een relatie staat in de DKNF indien iedere beperking erop een logische consequentie is van de definitie van //sleutels// en //domeinen//. Gemakkelijker gezegd dan gedaan. Dikwijls heb je te maken met tamelijk goed verborgen en/of complexe bedrijfsregels. Hieronder een paar gevallen waar de voorgaande normaalvormen geen soelaas bieden, maar de redding nabij is.

In R1 zijn niet alle combinaties van Y en Z toegestaan, en R2 defineert wat geldige combinaties zijn. Vervang de gecombineerde primaire sleutel {Y,&nbsp;Z} dan door een enkelvoudige sleutel:

[img[To DKNF (1)|data/images/DD DKNF (1).png]]

De beperkingen hebben betrekking op onderdelen van een attribuut. Splits het desbetreffende attribuut dan uit in de relevante onderdelen en pas vervolgens de gebruikelijke normaliseringen toe:

[img[To DKNF (2)|data/images/DD DKNF (2).png]]

Voor de aardigheid heb ik ook het bij BCNV geponeerde postcodeprobleem nog eens +++(PostcodeRegioWijkSectie)[onder handen genomen. &darr;|toon postcodeprobleem][onder handen genomen: &uarr;|verberg postcodeprobleem] De rode pijlen in R zijn ~Boyce-Codd afhankelijkheden. De afhankelijkheden op hoog niveau zijn met "H" gemerkt, en die op dieper niveau met "L". Afhankelijk van de procedure die ik volg, verkrijg ik vier oplossingen:
#Hierbij heb ik het //standaardrecept// voor BCNV //top-down// toegepast. Het resultaat komt zoals verwacht sterk overeen met de eerste oplossing die ik bij BCNV had gegeven. De uitsplitsing komt er pas als detailwerk achteraan. Verliezen: het is niet mogelijk via {{{{Plaats}}},&nbsp;{{{Straat}}},&nbsp;{{{Huisnr}}}} de {{{Postcode}}} of de {{{Waarde}}} te achterhalen.
#Hierbij heb ik het //alternatieve recept top-down// toegepast. Ook is de uitsplitsing een operatie achteraf en is de overeenkomst met de eerder gegeven tweede ~BCNV-oplossing groot. Anders dan bij procedure 1 geeft de combinatie {{{{Plaats}}},&nbsp;{{{Straat}}},&nbsp;{{{Huisnr}}}} nog steeds toegang tot de {{{Waarde}}}. Daarom heeft deze aanpak mijn voorkeur boven de andere drie.
#Hierbij heb ik het //standaardrecept bottom-up// toegepast. R1"""''""" lijkt wat op R1' bij procedure 2. Anders dan bij 2 is de afhankelijkheid {{{{Plaats}}},&nbsp;{{{Straat}}},&nbsp;{{{Huisnr}}}} &rarr; {{{Postcode}}} behouden gebleven, maar zijn {{{Postcode}}} &rarr; {{{{Plaats}}},&nbsp;{{{Straat}}}} en {{{{Postcode}}},&nbsp;{{{Huisnr}}}} &rarr; {{{Waarde}}} teloor gegaan. Slechte ruil.
#Hierbij heb ik het //alternatieve recept bottom-up// toegepast. Het resultaat lijkt op dat van procedure 1, maar het gebrek aan coherentie leidt ertoe dat er ten opzichte van 1 nòg een afhankelijkheid is verdwenen, namelijk {{{Postcode}}} &rarr; {{{{Plaats}}},&nbsp;{{{Straat}}}}. Dit is dus de minst bruikbare oplossing.
[img[To DKNF (3)|data/images/DD DKNF (3).png]]
===
===
Er zijn nogal wat hoekmaten in omloop, terwijl zich in vergeten hoekjes ook nog enkele ophouden. Zie voor een eerste overzicht hiervan en hulpmiddelen om ze onderling te converteren:
* https://en.wikipedia.org/wiki/Angular_unit
* https://en.wikipedia.org/wiki/Angle#Measurement
* https://www.translatorscafe.com/unit-converter/sk-SK/angle/13-12/right%20angle-quadrant/
* https://www.translatorscafe.com/unit-converter/sk-SK/angle/2-1/radian-degree/?value=1
Laat ons vervolgens eens -- onderwijl enige achtergronden en verbanden schetsend -- een flinke greep uit het assortiment doen:

{{z{
|col1 thick1 |k
| !{{n{(1)}}}<br>Draaiing | !{{n{(2)}}}<br>Diame-<br>treet |>| !{{n{(3)}}}<br>Radiaal | !{{n{(4)}}}<br>Kwa-<br>drant | !{{n{(5)}}}<br>Sex-<br>tant | !{{n{(6)}}}<br>Oc-<br>tant | !{{n{(7)}}}<br>Klok-<br>pos. | !{{n{(8)}}}<br>Astron.<br>uur | !{{n{(9)}}}<br>Wind-<br>streek | !{{n{(10)}}}<br>Hexa-<br>contade | !{{n{(11)}}}<br>Zam | !{{n{(12)}}}<br>Binaire<br>graad | !{{n{(13)}}}<br>Graad | !{{n{(14)}}}<br>Gon |>|>| !{{n{(15)}}}<br>Mil | !{{n{(16)}}}<br>Kral.<br>kerf |
|~|~|                                                          !{{h3 stix{&tau;}}}   | !{{h3 stix{&pi;}}}   |~|~|~|~|~|~|~|~|~|~|~|!Sovjet|!Zweeds|!NAVO|~|
|Slag                     |             {{stix{&pi;}}}|             {{stix{&tau;}}}|           2 {{stix{&pi;}}}|          4|           6|         8|                12/%|
                        %/|       24^^h^^|         32|        60|        224|      {{f4{(256)}}}|         360&deg;|         400|     6.000|       6.300/%|
                        %/|          6.400| 960|
|Halve slag               |    &frac12; {{stix{&pi;}}}|    &frac12; {{stix{&tau;}}}|             {{stix{&pi;}}}|          2|           3|         4|                 6/%|
                        %/|       12^^h^^|         16|        30|        112|                128|         180&deg;|         200|     3.000|       3.150/%|
                        %/|          3.200| 480|
|Eenderde slag            |    &frac13; {{stix{&pi;}}}|    &frac13; {{stix{&tau;}}}|  2&#x2044;3 {{stix{&pi;}}}|  1&frac13;|           2| 2&frac23;|                4/%|
                        %/|        8^^h^^| 10&frac23;|        20| 74&frac23;| {{f4{&#x2248;85}}}|         120&deg;| 133&frac13;|     2.000|       2.100/%|
                        %/|  2.100&frac13;| 320|
|Kwartslag                |    &frac14; {{stix{&pi;}}}|    &frac14; {{stix{&tau;}}}|    &frac12; {{stix{&pi;}}}|          1|     1&half;|         2|                 3/%|
                        %/|        6^^h^^|          8|        15|         56|                 64|          90&deg;|         100|     1.500|       1.575/%|
                        %/|          1.600| 240|
|Eenvijfde slag           |    &frac15; {{stix{&pi;}}}|    &frac15; {{stix{&tau;}}}|    &frac25; {{stix{&pi;}}}|   &frac45;|   1&frac15;| 1&frac35;| {{f4{2&frac25;}}}/%|
                        %/| 4^^h^^48^^m^^|  6&frac25;|        12| 44&frac45;| {{f4{&#x2248;51}}}|          72&deg;|          80|     1.200|       1.260/%|
                        %/|          1.280| 192|
|Eenzesde slag            |    &frac16; {{stix{&pi;}}}|    &frac16; {{stix{&tau;}}}|    &frac13; {{stix{&pi;}}}| 2&#x2044;3|           1| 1&frac13;|                 2/%|
                        %/|        4^^h^^|  5&frac13;|        10| 37&frac13;| {{f4{&#x2248;43}}}|          60&deg;|  66&frac23;|     1.000|       1.050/%|
                        %/|  1.066&frac23;| 160|
|Eenachtste slag          |    &frac18; {{stix{&pi;}}}|    &frac18; {{stix{&tau;}}}|    &frac14; {{stix{&pi;}}}|   &frac12;|    &frac34;|         1| {{f4{1&frac12;}}}/%|
                        %/|        3^^h^^|          4|   7&half;|         28|                 32|          45&deg;|          50|       750| 787&frac12;/%|
                        %/|            800| 120|
|Eentwaalfde slag         | 1&#x2044;12 {{stix{&pi;}}}| 1&#x2044;12 {{stix{&tau;}}}|    &frac16; {{stix{&pi;}}}|   &frac13;|    &frac12;|  &frac23;|                 1/%|
                        %/|        2^^h^^|  2&frac23;|         5| 18&frac23;| {{f4{&#x2248;21}}}|          30&deg;|  33&frac13;|       500|         525/%|
                        %/|    533&frac13;|  80|
|Eenzestiende slag        | 1&#x2044;16 {{stix{&pi;}}}| 1&#x2044;16 {{stix{&tau;}}}|    &frac18; {{stix{&pi;}}}|   &frac14;|    &frac38;|  &frac12;|  {{f4{&frac34;}}}/%|
                        %/| 1^^h^^30^^m^^|          2| 3&frac34;|         14|                 16| 22&deg;30&prime;|          25|       375| 393&frac34;/%|
                        %/|            400|  60|
|Eenvierentwintigste slag | 1&#x2044;24 {{stix{&pi;}}}| 1&#x2044;24 {{stix{&tau;}}}| 1&#x2044;12 {{stix{&pi;}}}|   &frac16;|    &frac14;|  &frac13;|  {{f4{&frac12;}}}/%|
                        %/|        1^^h^^|  1&frac13;|   2&half;|  9&frac13;| {{f4{&#x2248;11}}}|          15&deg;|  16&frac23;|       250| 262&frac12;/%|
                        %/|    266&frac23;|  40|
|Eentweeëndertigste slag  | 1&#x2044;32 {{stix{&pi;}}}| 1&#x2044;32 {{stix{&tau;}}}| 1&#x2044;16 {{stix{&pi;}}}|   &frac18;| 3&#x2044;16|  &frac14;|  {{f4{&frac38;}}}/%|
                        %/| 0^^h^^45^^m^^|          1| 1&frac78;|          7|                  8| 11&deg;15&prime;|  12&frac12;| 187&half;| 196&frac78;/%|
                        %/|      200|  30|
}}}
{{lf{(1)}}}{{block mlbem{De vooral dankzij Fred Hoyle ingeburgerde Engelse term voor een ''volledige omwenteling'' bij hoekmetingen is [[turn|https://en.wikipedia.org/wiki/Turn_(angle)]]. In het Nederlands zou ''toer'' een mooie vertaling zijn: dezelfde etymologische herkomst (Grieks {{stix widenq{&tau;&omicron;&rho;&nu;&omicron;&sigmaf;}}}) en daarmee dezelfde {{stix{[[steunbetuiging aan τ (tau)|π, de halve waarheid]]}}}. Wordt de radiaal (3) ons reeds als een natuurlijke eenheid van hoekmeting voorgehouden, dan is de toer toch zeker de àllernatuurlijkste eenheid.}}}/%
%/
{{lf{(2)}}}{{block mlbem{Eén ''diametreet'' (Engels: //diametrete//) is de grootte van een hoek die, als middelpuntshoek van een cirkel beschouwd, op een boog staat waarvan de lengte gelijk is aan de diameter van die cirkel. Voor zover ik weet wordt deze maat nergens gebruikt en is zelfs de naam ervan volkomen onbekend. Dat onderstreept nog eens te meer dat de {{stix{[[definitie van π (pi)|π, de halve waarheid]]}}} achteraf gezien een verkeerde keuze is geweest.}}}/%
%/
{{lf{(3)}}}{{block mlbem{Eén ''[[radiaal|https://nl.wikipedia.org/wiki/Radiaal_(wiskunde)]]'' (Engels: [[radian|https://en.wikipedia.org/wiki/Radian]]) is de grootte van een hoek die, als middelpuntshoek van een cirkel beschouwd, op een boog staat waarvan de lengte gelijk is aan de straal van die cirkel. In graden (13) uitgedukt: 1 rad &#x2248; 57&deg;17&prime;45&Prime;. Er passen 6,28318.^^{{z{&nbsp;}}}^^.^^{{z{&nbsp;}}}^^. radialen in één toer. Dat is geen natuurlijk getal, het is zelfs geen rationaal getal. Zo kun je natuurlijk nooit een rondom sluitende onderverdeling van bijvoorbeeld een kompasroos maken. Zie (15) voor de sjoemeltrucjes die daarvoor bedacht zijn. Wie niet wil sjoemelen, kan het aantal radialen in een toer uitdrukken met het getal ''{{stix{&tau;}}}'', wat in feite niets anders is dan een andere notatie van 6,28318.^^{{z{&nbsp;}}}^^.^^{{z{&nbsp;}}}^^., maar met de pretentie van volkomen exactheid, want gedefinieerd als de omtrek van een cirkel gedeeld door zijn straal. En wie wat conservatiever is, kan desgewenst van ''2{{stix{&pi;}}}'' radialen spreken.

De eerste notie van hoekmeting in booglengte lijkt rond 1400 bij al-K&#x0101;sh&#x012b; te vinden te zijn. Hij verdeelde de radiaal in 60 //diameterdelen// (Engels: //diameter parts//), die op hun beurt ook weer in zestigen werden verdeeld. Een diameterdeel is net iets minder dan een booggraad volgens (13), namelijk bijna 57&prime;17&Prime;45&#x2034; (eh, nee, zo zeggen we dat tegenwoordig niet meer, beter is nu 57&prime;17,75&Prime;).}}}/%
%/
{{lf{(4)}}}{{block mlbem{''Kwadrant'' (Engels: //quadrant//) is een veelgebruikte term, al kom je deze in hoekmeting niet veel tegen. [[Duitsland en Zwitserland|https://de.wikipedia.org/wiki/Vollwinkel]] hebben er desalniettemin een symbool voor vastgelegd: 4^^&#x221f;^^&nbsp;=&nbsp;1&nbsp;Vollwinkel. Euclides rekende er in elk geval echt mee.}}}/%
%/
{{lf{(5)}}}{{block mlbem{De Babyloniërs verdeelden de toer in eerste instantie in zes ''sextanten'', misschien omdat je zo mooi zes gelijkzijdige (dus volmaakte!) driehoeken in een cirkel kunt stouwen. Tengevolge van het sexagesimale getallenstelsel waarmee ze werkten (handig: deelbaar door 2, 3, 4, 5, 6, 10, 12, 15, 20 en 30), pasten er 60&deg; in een sextant, 60&prime; in een graad, 60&Prime; in een minuut, 60&#x2034; in een seconde, 60&#x2057; in een terts, enzovoort. Zie verder (13).}}}/%
%/
{{lf{(6)}}}{{block mlbem{Toepassingen van ''octanten'' als hoekmaat zijn me niet bekend.}}}/%
%/
{{lf{(7)}}}{{block mlbem{''[[Klokposities|https://nl.wikipedia.org/wiki/Richting#Luchtvaart]]'' (Engels: [[clock positions|https://en.wikipedia.org/wiki/Clock_position]] of //clock bearing//) zijn een praktisch hulpmiddel om vanuit je eigen oriëntatie globaal de positie van een ander object te verwoorden. Denk je een horizontale wijzerplaat in met de ''12'' wijzend in de richting waarin je opgesteld staat of waarin je voer/vaar/vliegtuig zich beweegt. Zeg "Walvis op 11 uur!" als je schuin vooruit (meer naar voren dan opzij) aan bakboordzijde een walvis hebt gespot. Werk altijd met hele uren, want dat is bij alle haast al moeilijk genoeg. Er kunnen dus maar 12 richtingen worden aangegeven. Mijn laatste toepassing was bij een beschrijving in 2021 van de zolder van mijn studentensociëteit.

Een andere verdeling van de cirkel in twaalven is die van ''tekens'' (Engels: //signs//). Jawel, die van de dierenriem. Populair onder astrologen.}}}/%
%/
{{lf{(8)}}}{{block mlbem{Dan geven we de astronomen hier ook maar een plek. In het equatoriale coördinatenstelsel wordt de [[rechte klimming|https://nl.wikipedia.org/wiki/Rechte_klimming]] (Engels: [[right ascension|https://en.wikipedia.org/wiki/Right_ascension]], afgekort //RA//) ''{{stix{&alpha;}}}'' van een hemelobject meestal aangegeven in ''astronomische uren'' (Engels //hours//), minuten en seconden (bijvoorbeeld 12^^h^^34^^m^^56,7^^s^^ of 12:34:56,7). Deze coördinaat ligt op de hemelevenaar, begint bij het lentepunt op de snijlijn van de hemelevenaar en de ecliptica, en telt van daaraf naar het oosten. De hemelevenaar is het vlak waarin de evenaar van de aarde zich bevindt, en de ecliptica het vlak waarin de zon om de aarde lijkt te draaien. Gezien vanuit de rondtollende aarde lijkt het uitspansel elk uur 15&deg; te zijn gedraaid. Vanuit dergelijke observaties was het praktischer om de draaiing in tijdseenheden aan te geven. Zodoende wordt de coördinaat in de hemelevenaar die de positie aangeeft ten opzichte van het zuiden van de nulmeridiaan of meridiaan waar de waarnemer zich op bevindt de [[uurhoek|https://nl.wikipedia.org/wiki/Uurhoek]] genoemd: [[Greenwich Hour Angle (GHA) resp. Local Hour Angle (LHA)|https://en.wikipedia.org/wiki/Hour_angle]]. Meridianen draaien met de aarde mee, dus de uurhoek van een hemelobject verandert (letterlijk) met het uur. Om een absolute maat voor sterposities te krijgen is het lentepunt (Engels: //vernal equinox//) als referentiepunt gekozen, want dat ligt (nagenoeg) vast ten opzichte van het hemelgewelf (volgens mijn aantekeningen ten behoeve van mijn bijdrage aan een dispuutskalender voor 1979 verschuift het jaarlijks 3,35 seconden, dus we zijn sindsdien 2&prime;20&Prime; verder). De rechte klimming telt de uren oostwaarts, de tegenhanger, de siderische uurhoek (SHA) telt ze westwaarts. Samen omspannen ze dus altijd 24 uur. De gewoonte om van uren te spreken is doet nog steeds opgeld, al worden booggraden eveneens toegepast. Opletten dus bij gebruik van minuten en seconden, aangezien een tijdminuut overeenkomt met 15 boogminuten.

Haaks op de rechte klimming staat de andere equatoriale coördinaat, de [[declinatie|https://nl.wikipedia.org/wiki/Declinatie_(astronomie)]] (Engels: [[declination|https://en.wikipedia.org/wiki/Declination]]) ''{{stix{&delta;}}}''. Die wordt wel altijd in booggraden, boogminuten en boogseconden uitgedrukt (of in booggraden met decimale fracties).

|bare |k
| [img[rechte klimming en declinatie|data/images/Rechte klimming en declinatie.png]] |vertical-align:middle;padding-left:4em;[img[uurhoeken|data/images/Uurhoeken.gif]] |
}}}/%
%/
{{lf{(9)}}}{{block mlbem{Traditioneel bevatte de kompasroos 32 ''[[windstreken|https://nl.wikipedia.org/wiki/Windstreek]]'' (Engels: //points//), met [[namen|https://upload.wikimedia.org/wikipedia/commons/6/6f/1650_Jansson_Wind_Rose%2C_Anemographic_Chart%2C_or_Map_of_the_Winds_-_Geographicus_-_Anemographica-jannson-1650.jpg]] en al. De huis-tuin-en-keuken-en-ook-nog-trektocht-kompassen gaan niet zo ver. Zowel mijn mechanische als mijn elektronische houden het bij noord/oost/zuid/west en de klassieke gradenverdeling. Maar ik heb ook afbeeldingen gezien van een onderverdeling volgens de NAVO-variant van (15).

In het oude Arabië werd de cirkel met de ''akhnam'' eveneens in tweeëndertigen gedeeld.}}}/%
%/
{{lf{(10)}}}{{block mlbem{Erathosthenes, die de omtrek van de aarde heeft uitgerekend, verdeelde de cirkel in 60 ''hexacontaden''. Onder invloed van het Babylonische sexagesimale getallenstelsel?}}}/%
%/
{{lf{(11)}}}{{block mlbem{Er gaan zeven ''zam'' in een //akhnam// (9). Ik weet niet hoe de Arabieren toen aan die onderverdeling in zevenen kwamen. Omdat 36&nbsp;zam &#x2248; 1,0098&nbsp;rad wellicht? Of vanwege de zeven dagen in de week? Ik begrijp wel waarom dit stelsel uiteindelijk geen succes is geworden.}}}/%
%/
{{lf{(12)}}}{{block mlbem{Hadden ze voor een opslitsing in acht delen gekozen, dan waren ze de zuiver ''binaire gradenverdeling'' (Engels: //binary degrees// of //binary radians//, afgekort tot //brad//) van de akhnams trouw gebleven. Dat is weer helemaal actueel. De 8-bits (oftewel 1-byte) representatie volgens kolom (12) in de tabel bestrijkt het interval [0,&nbsp;256), maar er zijn ook andere 2^^{{z{//n//}}}^^-bits representaties mogelijk, bijvoorbeeld 16 bits om het interval [0,&nbsp;65536) te ondersteunen.}}}/%
%/
{{lf{(13)}}}{{block mlbem{De klassieke verdeling van een toer in 360 ''[[booggraden|https://nl.wikipedia.org/wiki/Booggraad]]'' (Engels: //[[degrees|https://en.wikipedia.org/wiki/Degree_(angle)]]//) hebben we via via van de Babyloniërs overgenomen. Deze onderverdeling is onafhankelijk van de Babyloniërs ook elders ontstaan. Er is naast de verklaring gegeven bij (5) nog een andere mogelijk, namelijk dat er een verband is met de 360 dagen van het jaar. Natuurlijk, natuurlijk, een jaar heeft nog een paar dagen meer, maar als je die tot sacrale dagen bestempelt en dus niet meetelt, past het precies. Naast de onderverdeling in boogminuten en boogseconden worden ook vaak decimale fracties van graden gehanteerd. Delen van seconden worden tegenwoordig altijd als decimale fractie weergegeven.}}}/%
%/
{{lf{(14)}}}{{block mlbem{De ''[[gon|https://nl.wikipedia.org/wiki/Gon_(hoek)]]'', sinds circa 1980 zo genoemd om aan alle naamsverwarring een eind te maken, is een uitvloeisel van de Franse revolutie, en nauw verbonden met de meter. Anders dan de meter is de gon nooit echt in zwang gekomen. Alleen onder landmeters en dergelijk volk is deze eenheid gewild. Andere, oudere benamingen zijn //grad//, //grade// en [[gradian|https://en.wikipedia.org/wiki/Gradian]]. Gebruikte symbolen waren //gr//, //grd// en //^^{{z{g}}}^^//. Oorspronkelijk was de cirkel verdeeld in vier kwadranten (4) van elk 100 van dit soort graden, was elke graad weer onderverdeeld in 100 centigraden (//cgr//), en elke centigraad in 100 myriograden (//mogr//). Tegenwoordig werkt men met gons (//gon//), centigons (//cgon//) en milligons (//mgon//). Als er al mee gewerkt wordt.}}}/%
%/
{{lf{(15)}}}{{block mlbem{De ''[[artilleriepromille|https://nl.wikipedia.org/wiki/Mil_(hoekmaat)]]'' (Engels: [[milliradian|https://en.wikipedia.org/wiki/Milliradian]]) of kortweg ''mil'' is een artillerieuitvoering van de milliradiaal (mrad c.q. 1&#x2044;1000 rad). Waarom vindt de artillerie deze hoekmaat zo ideaal? Omdat het zo lekker rekent. Stel dat je doel zich op 1 kilometer bevindt en het eerste schot slaat 5 meter rechts ervan in. Dan draai je het geschut 5 mil naar links, schiet... en raak! Wanneer je de omvang van het doel kent, kun je via een vizier met milverdeling de afstand bepalen, en omgekeerd kun je, als je de afstand kent, de omvang van het doel bepalen. Nadeel is, dat er geen geheel aantal milliradialen in een cirkel passen. Daarom zijn de artilleristen een beetje gaan trekken of duwen tot het wel paste:
* De Russen hebben hun mil onder de noemer [[тысячная|https://ru.wikipedia.org/wiki/%D0%A2%D1%8B%D1%81%D1%8F%D1%87%D0%BD%D0%B0%D1%8F_(%D1%83%D0%B3%D0%BE%D0%BB)]] zodanig opgerekt dat er nog maar 6.000 van in een omwenteling passen en 100&nbsp;mil&nbsp;=&nbsp;6&deg;. De afwijking van de 'echte mil' bedraagt daarmee ruim 4,7%. Finland heeft deze maat destijds overgenomen (evenals natuurlijk de Warschaupactlanden), maar gaat over naar de NAVO-mil.
* De Zweden gingen met hun mil (Zweeds: [[streck|https://sv.wikipedia.org/wiki/Streck_(vinkelenhet)]]) veel nauwkeuriger te werk, en drukten de maat zodanig in dat er 6.300 van in een toer passen. De afwijking bedraagt hier slechts 0,26%. De tabel laat zien dat hier wel een prijs voor moet worden betaald. Ook Zweden is overgestapt op de NAVO-mil.
* De NAVO heeft een middenweg bewandeld: met 6.400 mil in een toer is de afwijking bijna 1,9%, maar het groeperen in halven, kwarten, achtsten enz. levert tenminste niet zulke bizarre getallen op als bij de Zweden. Een verdeling in derden, zesden, twaalfden en dergelijke geeft daarentegen nog steeds ongemakkelijke hoeveelheden.
}}}/%

%/{{lf{(16)}}}{{block mlbem{Zelf zat ik me bij het inventariseren van al die hoekmaten af te vragen: waarom niet een eenheid gekozen die deling van een toer door 2, 3, 4, 5, 6, 8, 10, 12, 15, 16, 20, 24, 30, 32, 40, 48, 60, 64, 80, 96, 120, 160, 192, 240, 320 en 480 faciliteert? Bijvoorbeeld de Kralingse ''kerf'' (Engels: //notch//) = (&frac38;)&deg; = 22&prime;30&Prime;, of anders de Kralingse ''kras'' (Engels: //nick//) = 1&nbsp;decikerf = &frac23;&nbsp;NAVO-mil. Het is maar een idee.}}}
TiddlyWiki, MainMenu, NonExistent -- //Wikiword// (in deze wiki is gepoogd zulke impliciete hyperlinks te vermijden en uitsluitend expliciete, d.w.z. geforceerde hyperlinks te creëren)
~TiddlyWiki, ~MainMenu, ~NonExistent -- //Forced non-wikiword//
[[TiddlyWiki]], [[MainMenu]], [[NonExistent]] -- //Forced wikiword//
''{{up1px sans{<<showPopup tiddler:[[} Iteratie & recursie]] label: "Bundel ↘">>}}}''

<<eval [=[Hieronder zijn in pseudocode{{ref{&#x200a;[[[1]|##1]]}}} twee eenvoudig gemodelleerde vormen van gestructureerd herhaalde handelingen weergegeven: de iteratieve en de recursieve./%

%/
!!Iteratief: een lus die herhaald doorlopen wordt
Het roodgekleurde {{sans t{IF}}}-blok zou een complexere structuur kunnen hebben met meer dan één {{sans t{BREAK}}}-statement. Buiten dit gedeelte worden zulke statements geacht niet voor te komen. M.a.w. het {{sans t{REPEAT}}}-blok heeft van een afstandje bekeken slechts één (uit een of meer deuren opgebouwde) uitgang tussen het onvoorwaardelijk en het voorwaardelijk uit te voeren deel.
{{ib pre{
''REPEAT {''
  //declarations//$0
  //unconditional_processing//$0
  {{fred{''IF'' //condition// ''{''
    //final_processing//$0
    ''BREAK;
  }''}}}
  //conditional_processing//$0
''}''
}}}
Om de omgeving niet te belasten met de interne gegevenshuishouding van het {{sans t{REPEAT}}}-blok, kan er -- mits de gebruikte programmeertaal zulks faciliteert -- binnen dat blok gebruik worden gemaakt van lokale variabelen:
{{ib pre{
//declarations// $--> $(''DECLARE'' //variable//'',''$___'';''$) $___
}}}/%

%/
!!Recursief: een procedure die zichzelf aanroept
Evenals in het iteratieve model zou het roodgekleurde {{sans t{IF}}}-blok binnen de procedure //{{sans t{name}}}// een complexere structuur kunnen hebben met meer dan één {{sans t{RETURN}}}-statement. Buiten dit gedeelte worden zulke statements geacht niet voor te komen. Dus ook hier is van een afstandje bekeken één (uit een of meer deuren opgebouwde) uitgang tussen het onvoorwaardelijk en het voorwaardelijk uit te voeren deel aanwezig. Helemaal aan het eind van de procedure bevindt zich de andere uitgang (zelfs als daar geen {{sans t{RETURN}}}-statement zou staan).

De blauwgekleurde recursieve aanroepen in onderstaande modellen zijn de enige die in de procedure //{{sans t{name}}}// voorkomen. In de linker opstelling vindt na de recursieve aanroep nog enige verwerking plaats. Rechts niet, daar is sprake van een zogeheten //tail-call//. In talen die //tail-call elimination// ondersteunen neemt de aangeroepen procedure de stack en het terugkeeradres van de aanroepende procedure over, zodat beschikbaar geheugen geen belemmering meer vormt voor de diepgang van de recursie. Feitelijk is de recursie op die manier een iteratie geworden, of een estafetteloop zo men wil.
{{lf pre{
$(''DECLARE'' {{fblu{//name//}}}$)$0

{{fblu{//name//}}} ''= PROCEDURE('' //parameters//$0 '') {''
  //declarations//$0
  //unconditional_processing//$0
  {{fred{''IF'' //condition// ''{''
    //final_processing//$0
    ''RETURN'' //expressions//$0'';
  }''}}}
  $(//conditional_preprocessing//$0
  $(//variables//'' =''$)$0 {{fblu{//name//''('' //arguments//$0 '')''}}}'';''
  //conditional_postprocessing//$0$) $___
  $(''RETURN'' //expressions//$0'';''$)$0
''}''

$(//variables// ''=''$)$0 {{fblu{//name//''('' //arguments//$0 '')''}}}
}}}/%

%/{{lf pre ml1em{
$(''DECLARE'' {{fblu{//name//}}}$)$0

{{fblu{//name//}}} ''= PROCEDURE('' //parameters//$0 '') {''
  //declarations//$0
  //unconditional_processing//$0
  {{fred{''IF'' //condition// ''{''
    //final_processing//$0
    ''RETURN'' //expressions//$0'';
  }''}}}
  //conditional_processing//$0
  ''RETURN ''{{fblu{//name//''('' //arguments//$0 '')''}}}'';''
''}''

$(//variables// ''=''$)$0 {{fblu{//name//''('' //arguments//$0 '')''}}}
}}}
{{clear block{met:
{{ib pre{
//parameters//  $--> //parameter//'',''$___
//expressions// $--> //expression//'',''$___
//arguments//   $--> //argument//'',''$___
//variables//   $--> //variable//'',''$___
}}}
}}}/%

%/Er kunnen twee programmeerstijlen worden aangehouden:
* //Functioneel://&nbsp; De procedure //{{sans{name}}}// stelt na afloop alleen een of meer retourwaarden beschikbaar en heeft verder geen effect op de omgeving.
* //Toestandgericht://&nbsp;  De procedure //{{sans{name}}}// verandert gegevens van de omgeving. Retourwaarden zijn dan niet noodzakelijk.

----
<html><a name="1">[1]</a></html>&nbsp; De gebezigde sleutelwoorden {{sans t{REPEAT}}}, {{sans t{BREAK}}}, {{sans t{PROCEDURE}}}, {{sans t{RETURN}}} en {{sans t{IF}}} spreken hopelijk voor zich. Bij {{sans t{DECLARE}}} moet men zich de declaratie van een of meer lokale variabelen binnen een programmablok voorstellen. Zonder zo'n declaratie wordt een variabele in de directe lexicale omgeving van het blok gezocht, bij afwezigheid aldaar vervolgens in de lexicale omgeving van die omgeving, enzovoort, totdat het globale niveau is bereikt. Globale variabelen worden in deze pseudocode niet gedeclareerd. Of er verschil is tussen globale variabelen en lokale variabelen op het hoogste niveau, is afhankelijk van de uiteindelijk gekozen programmeertaal.
Verder is deze pseudocode opgetuigd met uit [[Welsh Rarebit]] overgenomen meta-operatoren die facultatieve elementen ($0), herhalende elementen ($___) en groepering ($($)$!) markeren.
]=] f2m>>
<<tiddler [[{}::togglesliders]]>> <<eval [=[In LISP 1.5 kwamen de keywords {{tt t{begin}}}, {{tt t{let}}}, {{tt t{let*}}}, {{tt t{letrec}}}, {{tt t{letrec*}}} en {{tt t{rec}}} niet voor. Ze zijn hun bestaan later waarschijnlijk als macro's begonnen. Of ze dat in Scheme -- in het bijzonder Chez Scheme 9.5 -- in technisch opzicht werkelijk nog steeds zijn, weet ik niet zeker, maar in elk geval is hun betekenis wel uit te drukken in constructies met louter {{tt t{lambda}}} en waar nodig aangevuld met {{tt t{set!}}}.{{ref{[[[1]|##1]]}}}&#x200a;{{ref{[[[2]|##2]]}}}/%

%/
+++(~KeldersScheme_Lambda)!![lambda &darr;|show][lambda &uarr;|hide]
In de volgende aanroep van een lambda:
{{w45pct pref tt s med ws pblu d3 r scroll{
''(({{fblu{lambda}}} (''//var// $___$0'')'' //body// $___$0'')'' //expr// $___$0'')''
}}}/%
%/is de evaluatievolgorde van de actuele parameters {{tt{//expr//}}}... niet in de specificatie van de Scheme-taal gedefinieerd. Dit geldt voor elke aanroep {{pref hitt pblu z{''(''//proc// //expr// $___$0'')''}}}. Daarentegen is wel vastgelegd dat {{tt{//body//}}}... altijd van links naar rechts wordt geëvalueerd./%

%/
===
+++(~KeldersScheme_Set)!![set! &darr;|show][set! &uarr;|hide]
De uitdrukking:
{{w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{set!}}}'' //var// //expr//'')''
}}}/%
%/kent de waarde van {{tt{//expr//}}} aan de meest nabije variabele {{tt{//var//}}} toe. Mocht {{tt{//var//}}} nog niet bestaan, dan wordt er eerst een globale variable met die naam gecreëerd./%

%/
===
+++(~KeldersScheme_Begin)!![begin &darr;|show][begin &uarr;|hide]
Scheme kent twee vormen van {{tt t{begin}}}. De eerste vorm behoort tot de kern van de taal en kan daardoor niet uit iets anders worden afgeleid:
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{begin}}}'' //definition// $___$0'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct pref tt s med ws pblu d3 r scroll{
//definition// $--> ''({{fblu{define}}}'' //var// //expr//'')'' $| ''({{fblu{begin}}}'' //definition// $___$0'')''
}}}{{clear block{}}}/%

%/De tweede vorm is feitelijk een verkorte schrijfwijze voor een lambda-expressie en de aanroep daarvan:
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{begin}}}'' //body// $___'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct pref tt s med ws pblu d3 r scroll{
''(({{fblu{lambda}}} ()'' //body// $___''))''
}}}{{clear block{}}}/%

%/
===
+++(~KeldersScheme_Let)!![let &darr;|show][let &uarr;|hide]
Eerste vorm:
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{let}}} (''$(''(''//var// //expr//'')''$) $___$0'')'' //body// $___'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct pref tt s med ws pblu d3 r scroll{
((''{{fblu{lambda}}} (''//var// $___$0'')'' //body// $___'')'' //expr// $___$0'')''
}}}{{clear block{}}}/%

%/Tweede vorm:
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''(''{{fblu{''let'' //name//}}} ''(''$(''(''//var// //expr//'')''$) $___$0'')'' //body// $___'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct{{{pref tt s med ws pblu d3 r scroll{
''(({{fblu{letrec}}} ((''{{fblu{//name//}}} ''({{fblu{lambda}}} (''//var// $___$0) //body// $___'')))'' {{fblu{//name//}}}'')''
"""  """//expr// $___$0'')''
}}}Omdat {{tt t{letrec}}} hier slechts één variabele heeft, is deze toepassing ervan functioneel gelijkwaardig aan:
{{pref tt s med ws pblu d3 r scroll{
''(({{fblu{let}}} ((''{{fblu{//name//}}} //dummyValue//''))
"""    """({{fblu{set!}}}'' {{fblu{//name//}}} ''({{fblu{lambda}}} (''//var// $___$0'')'' //body// $___''))'' {{fblu{//name//}}}'')''
"""  """//expr// $___$0'')''
}}}Wat natuurlijk weer gelijk is aan:
{{pref tt s med ws pblu d3 r scroll{
''((({{fblu{lambda}}} (''{{fblu{//name//}}}'')
"""      """({{fblu{set!}}}'' {{fblu{//name//}}} ''({{fblu{lambda}}} (''//var// $___$0'')'' //body// $___''))'' {{fblu{//name//}}}'')''
"""    """//expr// $___$0'')''
"""  """//dummyValue//'')''
}}}}}}{{clear block{}}}/%

%/
===
+++(~KeldersScheme_LetStar)!![let* &darr;|show][let* &uarr;|hide]
Basisgeval:
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{let*}}} (''$(''(''//var// //expr//'')''$)$0'')'' //body// $___'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{let}}} (''$(''(''//var// //expr//'')''$)$0'')'' //body// $___'')''
}}}{{clear block{}}}/%

%/Uitbreidingen:
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{let*}}} ((''//var1// //expr1//'')'' $(''(''//var2// //expr2//'')''$) $___$0'')'' //body// $___'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{let}}} ((''//var1// //expr1//'')
"""  """({{fblu{let*}}} (''$(''(''//var2// //expr2//'')''$) $___$0'')'' //body// $___''))''
}}}{{clear block{}}}/%

%/
===
+++(~KeldersScheme_Letrec)!![letrec &darr;|show][letrec &uarr;|hide]
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{letrec}}} (''$(''(''//var// //expr//'')''$) $___$0'')'' //body// $___'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{let}}} (''$(''(''//var// //dummyValue//'')''$) $___$0'')
"""  """({{fblu{let}}} (''$(''(''//temp// //expr//'')''$) $___$0'')''
"""    """$(''({{fblu{set!}}}'' //var// //temp//'')''$) $___$0
"""    """//body// $___''))''
}}}{{clear block{}}}/%

%/
===
+++(~KeldersScheme_LetrecStar)!![letrec* &darr;|show][letrec* &uarr;|hide]
Niet opgenomen in R3RS t/m R5RS, daarvóór en daarna wel.
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{letrec*}}} (''$(''(''//var// //expr//'')''$) $___$0'')'' //body// $___'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{let}}} (''$(''(''//var// //dummyValue//'')''$) $___$0'')''
"""  """$(''({{fblu{set!}}}'' //var// //expr//'')''$) $___$0
"""  """//body// $___'')''
}}}{{clear block{}}}/%

%/
===
+++(~KeldersScheme_Rec)!![rec &darr;|show][rec &uarr;|hide]
Alleen in R1RS en R2RS opgenomen, maar evengoed aanwezig in de library {{tt t{(chezscheme)}}}.
{{lf w45pct pref tt s med ws pblu d3 r scroll{
''({{fblu{rec}}}'' //var// //expr//'')''
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>\]=\]\>\>{{lf w45pct{{{pref tt s med ws pblu d3 r scroll{
''({{fblu{letrec}}} ((''//var// //expr//''))'' //var//'')''
}}}Verder te expanderen tot:
{{pref tt s med ws pblu d3 r scroll{
''({{fblu{let}}} ((''//var// //dummyValue//''))
"""  """({{fblu{set!}}}'' //var// //expr//'')'' //var//'')''
}}}en uiteindelijk tot:
{{pref tt s med ws pblu d3 r scroll{
''(({{fblu{lambda}}} (''//var//'')
"""    """({{fblu{set!}}}'' //var// //expr//'')'' //var//'')''
"""  """//dummyValue//'')''
}}}}}}{{clear block{}}}/%

%/
===
]=] f3m>>
----
|plain |k
|<html><a name="1">[1]</a></html>|De //core syntax// zou alleen de keywords {{tt t{begin}}}, {{tt t{define}}}, {{tt t{if}}}, {{tt t{lambda}}}, {{tt t{quote}}} en {{tt t{set!}}} bevatten. Al de andere behoren daarmee tot de //syntax extensions//.<br>Zie &sect;&#x200a;3.1 van <<tiddler Bibliografie##Dybvig>> |
|<html><a name="2">[2]</a></html>|In [[Revised Report on the algorithmic language Scheme]] zijn macrodefinities voor de hier beschreven //derived forms// gegeven (R5RS &sect;&#x200a;7.3, R6RS appendix B, R7RS &sect;&#x200a;7.3). |
Bij wat in Python-documentatie veelal simpelweg als ingebouwde 'functie' wordt aangemerkt, blijkt het toch wel om objecten van diverse pluimage te gaan. Zo'n 35% is constructor van een gelijknamige class.{{ref{[[[1]|##1]]}}} Van ''{{{type}}}'' weet ik, dat het een dubbelrol vervult: alleen bij aanroep met drie of meer argumenten werkt het als constructor.

Dit is de stand bij versie 3.11:

{{lf w55pct z{
|capl col1 z |k
|!{{h6{Name}}}        |!{{h6{The object}}}                      |!{{h6{The object's class}}}                |
|''{{{abs}}}''        |{{{<built-in function abs>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{aiter}}}''&nbsp;&#x21bb; |{{{<built-in function aiter>}}} |{{{<class 'builtin_function_or_method'>}}} |
|''{{{all}}}''        |{{{<built-in function all>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{anext}}}''      |{{{<built-in function anext>}}}          |{{{<class 'builtin_function_or_method'>}}} |
|''{{{any}}}''        |{{{<built-in function any>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{ascii}}}''      |{{{<built-in function ascii>}}}          |{{{<class 'builtin_function_or_method'>}}} |
|''{{{bin}}}''        |{{{<built-in function bin>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{breakpoint}}}'' |{{{<built-in function breakpoint>}}}     |{{{<class 'builtin_function_or_method'>}}} |
|''{{{callable}}}''   |{{{<built-in function callable>}}}       |{{{<class 'builtin_function_or_method'>}}} |
|''{{{chr}}}''        |{{{<built-in function chr>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{compile}}}''    |{{{<built-in function compile>}}}        |{{{<class 'builtin_function_or_method'>}}} |
|''{{{delattr}}}''    |{{{<built-in function delattr>}}}        |{{{<class 'builtin_function_or_method'>}}} |
|''{{{dir}}}''        |{{{<built-in function dir>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{divmod}}}''     |{{{<built-in function divmod>}}}         |{{{<class 'builtin_function_or_method'>}}} |
|''{{{eval}}}''       |{{{<built-in function eval>}}}           |{{{<class 'builtin_function_or_method'>}}} |
|''{{{exec}}}''       |{{{<built-in function exec>}}}           |{{{<class 'builtin_function_or_method'>}}} |
|''{{{format}}}''     |{{{<built-in function format>}}}         |{{{<class 'builtin_function_or_method'>}}} |
|''{{{getattr}}}''    |{{{<built-in function getattr>}}}        |{{{<class 'builtin_function_or_method'>}}} |
|''{{{globals}}}''    |{{{<built-in function globals>}}}        |{{{<class 'builtin_function_or_method'>}}} |
|''{{{hasattr}}}''    |{{{<built-in function hasattr>}}}        |{{{<class 'builtin_function_or_method'>}}} |
|''{{{hash}}}''       |{{{<built-in function hash>}}}           |{{{<class 'builtin_function_or_method'>}}} |
|''{{{hex}}}''        |{{{<built-in function hex>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{id}}}''         |{{{<built-in function id>}}}             |{{{<class 'builtin_function_or_method'>}}} |
|''{{{input}}}''      |{{{<built-in function input>}}}          |{{{<class 'builtin_function_or_method'>}}} |
|''{{{isinstance}}}'' |{{{<built-in function isinstance>}}}     |{{{<class 'builtin_function_or_method'>}}} |
|''{{{issubclass}}}'' |{{{<built-in function issubclass>}}}     |{{{<class 'builtin_function_or_method'>}}} |
|''{{{iter}}}''&nbsp;&#x21bb; |{{{<built-in function iter>}}}   |{{{<class 'builtin_function_or_method'>}}} |
|''{{{len}}}''        |{{{<built-in function len>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{locals}}}''     |{{{<built-in function locals>}}}         |{{{<class 'builtin_function_or_method'>}}} |
|''{{{max}}}''        |{{{<built-in function max>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{min}}}''        |{{{<built-in function min>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{next}}}''       |{{{<built-in function next>}}}           |{{{<class 'builtin_function_or_method'>}}} |
|''{{{oct}}}''        |{{{<built-in function oct>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{open}}}''       |{{{<built-in function open>}}}           |{{{<class 'builtin_function_or_method'>}}} |
|''{{{ord}}}''        |{{{<built-in function ord>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{pow}}}''        |{{{<built-in function pow>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{print}}}''      |{{{<built-in function print>}}}          |{{{<class 'builtin_function_or_method'>}}} |
|''{{{repr}}}''       |{{{<built-in function repr>}}}           |{{{<class 'builtin_function_or_method'>}}} |
|''{{{round}}}''      |{{{<built-in function round>}}}          |{{{<class 'builtin_function_or_method'>}}} |
|''{{{setattr}}}''    |{{{<built-in function setattr>}}}        |{{{<class 'builtin_function_or_method'>}}} |
|''{{{sorted}}}''     |{{{<built-in function sorted>}}}         |{{{<class 'builtin_function_or_method'>}}} |
|''{{{sum}}}''        |{{{<built-in function sum>}}}            |{{{<class 'builtin_function_or_method'>}}} |
|''{{{vars}}}''       |{{{<built-in function vars>}}}           |{{{<class 'builtin_function_or_method'>}}} |
|''{{{__import__}}}'' |{{{<built-in function __import__>}}}     |{{{<class 'builtin_function_or_method'>}}} |
|{{mlbem{''44''}}}|c
}}}{{ib w40pct z{
|capl col1 z |k
|!{{h6{Name}}}          |!{{h6{The object}}}                  |!{{h6{The object's class}}} |
|''{{{bool}}}''         |{{{<class 'bool'>}}}                 |{{{<class 'type'>}}}        |
|''{{{bytearray}}}'' »  |{{{<class 'bytearray'>}}}            |{{{<class 'type'>}}}        |
|''{{{bytes}}}'' »      |{{{<class 'bytes'>}}}                |{{{<class 'type'>}}}        |
|''{{{classmethod}}}''  |{{{<class 'classmethod'>}}}          |{{{<class 'type'>}}}        |
|''{{{complex}}}''      |{{{<class 'complex'>}}}              |{{{<class 'type'>}}}        |
|''{{{dict}}}'' »       |{{{<class 'dict'>}}}                 |{{{<class 'type'>}}}        |
|''{{{enumerate}}}''&nbsp;&#x21bb; |{{{<class 'enumerate'>}}} |{{{<class 'type'>}}}        |
|''{{{filter}}}''&nbsp;&#x21bb; |{{{<class 'filter'>}}}       |{{{<class 'type'>}}}        |
|''{{{float}}}''        |{{{<class 'float'>}}}                |{{{<class 'type'>}}}        |
|''{{{frozenset}}}'' »  |{{{<class 'frozenset'>}}}            |{{{<class 'type'>}}}        |
|''{{{int}}}''          |{{{<class 'int'>}}}                  |{{{<class 'type'>}}}        |
|''{{{list}}}'' »       |{{{<class 'list'>}}}                 |{{{<class 'type'>}}}        |
|''{{{map}}}''&nbsp;&#x21bb; |{{{<class 'map'>}}}             |{{{<class 'type'>}}}        |
|''{{{memoryview}}}'' » |{{{<class 'memoryview'>}}}           |{{{<class 'type'>}}}        |
|''{{{object}}}''       |{{{<class 'object'>}}}               |{{{<class 'type'>}}}        |
|''{{{property}}}''     |{{{<class 'property'>}}}             |{{{<class 'type'>}}}        |
|''{{{range}}}'' »      |{{{<class 'range'>}}}                |{{{<class 'type'>}}}        |
|''{{{set}}}'' »        |{{{<class 'set'>}}}                  |{{{<class 'type'>}}}        |
|''{{{slice}}}''        |{{{<class 'slice'>}}}                |{{{<class 'type'>}}}        |
|''{{{staticmethod}}}'' |{{{<class 'staticmethod'>}}}         |{{{<class 'type'>}}}        |
|''{{{str}}}'' »        |{{{<class 'str'>}}}                  |{{{<class 'type'>}}}        |
|''{{{super}}}''        |{{{<class 'super'>}}}                |{{{<class 'type'>}}}        |
|''{{{tuple}}}'' »      |{{{<class 'tuple'>}}}                |{{{<class 'type'>}}}        |
|''{{{type}}}''         |{{{<class 'type'>}}}                 |{{{<class 'type'>}}}        |
|''{{{zip}}}''&nbsp;&#x21bb; |{{{<class 'zip'>}}}             |{{{<class 'type'>}}}        |
|{{ml3em{''25''}}} |c

|capl col1 z |k
|!{{h6{Name}}}                    |!{{h6{The object}}}        |!{{h6{The object's class}}} |!{{h6{Type of returned value}}}            |
|''{{{reversed}}}''&nbsp;&#x21bb; |{{tt{<class 'reversed'>}}} |{{{<class 'type'>}}}        |{{tt{<class '{{serif{//iterator//}}}'>}}} |
|{{ml3em{''1''}}} |c
{{pref hitt z{''reversed(''//iterable//'')''}}} is in staat een instance van de een van de volgende classes te retourneren:
* {{tt{list_reverseiterator}}}
* {{tt{dict_itemreverseiterator}}}
* {{tt{dict_keyreverseiterator}}}
* {{tt{dict_valuereverseiterator}}} 
* {{tt{range_iterator}}} (itereert ondanks de naam wel in omgekeerde volgorde)
Een {{tt t{set}}}, {{tt t{frozenset}}} of ingebouwde iterator{{ref{&#x200a;[[[2]|##2]]}}} laat zich niet omkeren, terwijl de omkering bij de iterabelen van het type {{tt t{bytearray}}}, {{tt t{bytes}}}, {{tt t{str}}} of {{tt t{tuple}}} resulteert in een niet nader gekwalificeerde maar evengoed correct ingerichte ''{{tt{reversed}}}''-instance.

|capl col1 z |k
|!{{h6{Name}}}          |!{{h6{The object}}}              |!{{h6{The object's class}}} |
|''{{{help}}}''         |//_sitebuiltins._Helper object// |{{{<class '_sitebuiltins._Helper'>}}} |
|{{mlaem{''1''}}} |c
}}}
{{block clear{De met &#x21bb; gemerkte 'functies' retourneren een iterator. Met » heb ik aangegeven van welke classes de instances iterabel zijn, d.w.z. via de ''{{{iter}}}''-functie naar een iterator kunnen worden omgezet.}}}/%
%/
----
|bare |k
|<html><a name="01">[1]</a></html>|Dit percentage is kunstmatig laag gehouden, zie een van de noten in [[Zichtbaarheid van Python-variabelen]]. Verder bestaan er onnoemelijk veel ingebouwde classes die het zonder identifier moeten stellen en niet (of moeilijk vindbaar) gedocumenteerd zijn. Wellicht zitten daar classes zonder eigen constructor tussen, maar ik ken uitsluitend andere gevallen. Zo kan {{hitt z{types.MappingProxyType}}} prima als constructor fungeren, en blijkt ook de view {{tt t{dict_keys}}} wel degelijk callable, al levert zo'n aanroep de foutmelding {{sans{"TypeError: cannot create 'dict_keys' instances"}}} op. Zie wat er in [['Iterabiliteit' in Python]] en [[Provider à la Python-iterator]] zoal voorbij getrokken is. |
|<html><a name="02">[2]</a></html>|Wat ik hier over iteratoren beweer, is gebaseerd op een beperkte test van enkele ingebouwde iteratoren. Ik verwacht dat het best mogelijk is een iterator te bouwen die wèl meewerkt met {{tt t{reversed}}}. Kwestie van een {{tt t{"""__reversed__"""}}}-method met de gewenste functionaliteit aanleggen. |
Bij ~MS-DOS en Windows zijn we gewend aan compressieprogramma's die een agglomeraat van bestanden in gecomprimeerde vorm inpakken in één archiefbestand. In Unix-achtige omgevingen is de traditie heel anders. Daar zijn specifieke aspecten van een bewerking toebedeeld aan verschillende gespecialiseerde programma's, die in een keten worden opgesteld om het gewenste eindresultaat te bereiken. In dit concrete geval: het bundelen van een agglomeraat van bestanden tot één archiefbestand en het comprimeren van bestanden is uitbesteed aan aparte programma's. Een archiefbestand wordt samengesteld met behulp van ''{{{tar}}}'' ('Tape ~ARchive', zie ook https://www.gnu.org/software/tar/manual/tar.pdf). Comprimeren doe je met een afzonderlijk compressieprogramma (''{{{compress}}}'', ''{{{gzip}}}'', ''{{{bzip2}}}'', ''{{{lzma}}}'', ''{{{xz}}}''), dat slechts in staat is een reeks bestanden één-op-één te //vervangen// door evenzoveel gecomprimeerde bestanden. Een uitzondering vormt het buitenbeentje ''{{{zip}}}'', dat als equivalent van gelijksoortige programma's op DOS/Windows zowel het bundelen als het comprimeren voor z'n rekening neemt.

Een keten voor bundeling en compressie kan op twee manieren worden ingericht. De ene houdt in, dat je eerst een aantal bestanden bundelt tot een ~TAR-bestand (extensie ''{{{.tar}}}''), en dit bestand vervolgens door het aanroepen van een compressieprogramma vervangt door een gecomprimeerde vorm (waarbij de toepasselijke compressie-extensie zoals ''{{{.gz}}}'' aan de bestandsnaam wordt toegevoegd). Het voordeel is, dat het compressie-algoritme op het gehele archiefbestand kan worden losgelaten, wat betere indikkingsmogelijkheden biedt. Het alternatief is, dat je de bestanden tijdens het bundelen één voor één comprimeert alvorens ze aan het archiefbestand toe te voegen. Qua ruimtebesparing net wat minder effectief misschien, maar wel één geïntegreerde handeling doordat je je compressiewensen opgeeft aan het ''{{{tar}}}''-programma, dat dan stilletjes het verlangde compressieprogramma voor je aanroept. Voor het uitpakken maakt het niet uit welke weg bij het inpakken is bewandeld, mits de juiste extensie aan het archiefbestand is toegekend.

In onderstaande tabel, waarin de meest relevante hoedanigheden van de verschillende opties uitgestald staan, zijn de volgende programma's mijns inziens het meest interessant:/%
%/
;{{tt{[[tar|Archiving with tar]]}}}
://Het// universele archiveringsprogramma in Unix-achtige omgevingen. Bundelt mappen en bestanden in één bestand. Veel Windows-gereedschappen kunnen er goed mee omgaan.
;{{{zip}}}
:Compressieprogramma met maximale Windows-compatibiliteit.
;{{tt{[[gzip|Compressing with gzip, bzip2, xz]]}}}
://Het// universele compressieprogramma in Unix-achtige omgevingen. Scoort qua verdichting beter dan ''{{{zip}}}''. Veel Windows-gereedschappen kunnen er goed mee overweg.
;{{tt{[[bzip2|Compressing with gzip, bzip2, xz]]}}}
:Weet significant betere reductie te bewerkstelligen dan {{{gzip}}}. De ondersteuning op Windows is vrij behoorlijk.
;{{tt{[[xz|Compressing with gzip, bzip2, xz]]}}}
:Interessant als de verkleiningsfactor ècht een zaak van belang is. Scoort in dit opzicht weer aanmerkelijk beter dan de andere compressieprogramma's. De ondersteuning op Windows is daarentegen wat spaarzamer./%
%/
Betere compressie gaat in de regel ten koste van de snelheid.

|!                                                           |bgcolor(black): !tar |bgcolor(black): !zip | !compress |bgcolor(black): !gzip |bgcolor(black): !bzip2 | !lzma   |bgcolor(black): !xz |
|bgcolor(#eec):Actueel (+) / verouderd (&minus;)             | +      | +            | &minus; @@color(#b95):[0]@@ | +                 | +                      | &minus;          | +             |
|bgcolor(#eec):Bundelfunctionaliteit                         | +      | +            | &minus;                | &minus;                | &minus;                | &minus;          | &minus;       |
|bgcolor(#eec):Omvang na compressie                          | (100%) | 51&minus;46% | 34&minus;62%           | 18&minus;46%           | 12&minus;23%           | 9&minus;13%      | 9&minus;13%   |
|bgcolor(#eec):Gradaties snelle &rarr; sterke compressie     |        | 0&minus;9    |                        | 1&minus;9              | 1&minus;9              | 0&minus;9        | 0&minus;9     |
|bgcolor(#eec):Defaultwaarde snel &rarr; sterk               |        | 6            |                        | 6                      | 9                      | 6                | 6             |
|bgcolor(#eec):Belangrijkste ''tar''-optie voor compressie   |        |              | ''{{{-Z}}}''           | ''{{{-z}}}''           | ''{{{-j}}}''           | ''{{{--lzma}}}'' | ''{{{-J}}}''  |
|bgcolor(#eec):Zelfstandige bestandsextensie(s)              | ''{{{.tar}}}'' | ''{{{.zip}}}'' | ''{{{.Z}}}'' | ''{{{.gz}}}'' | ''{{tt{__.bz2__<br>.bz}}}''     | ''{{{.lzma}}}''  | ''{{{.xz}}}'' |
|bgcolor(#eec):Met ''tar'' geïntegreerde bestandsextensie(s) | | | ''{{tt{__.taZ__<br>.tz}}}'' | ''{{tt{__.tgz__<br>.taz}}}'' | ''{{tt{.tbz2<br>__.tbz__<br>.tz2}}}'' | ''{{{.tlz}}}'' | ''{{{.txz}}}'' |
|bgcolor(#eec):Te lezen met ~WinZip                          | +      | +            | + @@color(#b95):[1]@@  | +                      | + @@color(#b95):[2]@@  | &minus;          | &minus;       |
|bgcolor(#eec):Te lezen met 7-Zip                            | +      | +            | + @@color(#b95):[3]@@  | + @@color(#b95):[4]@@  | + @@color(#b95):[5]@@  | +                | +             |
|bgcolor(#eec):Te lezen met Total Commander                  | +      | +            | &minus;                | + @@color(#b95):[6]@@  | &minus;                | &minus;          | &minus;       |
|bgcolor(#eec):Te lezen met Double Commander                 | +      | +            | + @@color(#b95):[7]@@  | ++ @@color(#b95):[8]@@ | ++ @@color(#b95):[9]@@ | ++               | ++            |

@@color(#b95):[0]@@ Zó verouderd, dat het op de SAS ~BI-omgeving niet eens meer wordt aangeboden.
@@color(#b95):[1]@@ Bij bestanden met extensie ''{{{.tz}}}'' moet ~WinZip even worden geholpen met het identificeren van het ingepakte ~TAR-bestand.
@@color(#b95):[2]@@ Bestanden met extensie ''{{{.tz2}}}'' kunnen niet worden ingelezen.
@@color(#b95):[3]@@ Bij bestanden met extensie ''{{{.tz}}}'' wordt de extensie ''{{{.tar}}}'' van het ingepakte ~TAR-bestand niet gezien.
@@color(#b95):[4]@@ Bij bestanden met extensie ''{{{.taz}}}'' wordt de extensie ''{{{.tar}}}'' van het ingepakte ~TAR-bestand niet gezien.
@@color(#b95):[5]@@ Bij bestanden met extensie ''{{{.tz2}}}'' wordt de extensie ''{{{.tar}}}'' van het ingepakte ~TAR-bestand niet gezien.
@@color(#b95):[6]@@ Bestanden met extensie ''{{{.taz}}}'' kunnen niet worden ingelezen.
@@color(#b95):[7]@@ Bestanden met extensie ''{{{.tz}}}'' kunnen niet worden ingelezen.
@@color(#b95):[8]@@ Bij bestanden met de extensie ''{{{.taz}}}'' wordt de extensie ''{{{.tar}}}'' van het ingepakte ~TAR-bestand niet gezien, waardoor dit niet kan worden ingelezen.
@@color(#b95):[9]@@ Bestanden met extensie ''{{{.bz}}}'', ''{{{.tbz2}}}'' of ''{{{.tz2}}}'' kunnen niet worden ingelezen.

De hier gegeven compressiecijfers zijn de uitkomsten van twee verschillende testopstellingen met waar dat instelbaar is zo sterk mogelijke compressie ingesteld. Als steekproef wat magertjes, maar het geeft wel een aardige indruk van de krachtsverhoudingen tussen de verschillende compressieprogramma's. Overigens verschillen de compressieratio's tussen de gradaties 6 en 9 niet zo veel, reden waarom 6 meestal als verstekwaarde gekozen is. Die verstekwaarde geldt ook wanneer een compressieprogramma vanuit ''{{{tar}}}'' wordt ingeschakeld. Daar valt langs die weg niets meer aan bij te stellen.

In de tests waarop deze bevindingen gebaseerd zijn, heb ik de extensies die met een ''{{{t}}}'' beginnen alleen toegepast waar ik comprimeerde via het ''{{{tar}}}''-programma. In gevallen waar meer dan één extensie correct heet te zijn, verdient de onderstreepte variant de voorkeur.

De aanduiding '++' bij de Double Commander betekent dat het niveau van het eventueel ingepakte ~TAR-bestand bij het openen van het gecomprimeerde bestand wordt overgeslagen en de inhoud van dat ~TAR-bestand direct wordt getoond. Bevat het gecomprimeerde bestand een andersoortig bestand, dan wordt niet de inhoud maar de aanwezigheid van dat bestand getoond.
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.5|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Insert Javascript executable code directly into your tiddler content.|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revisions
<<<
2009.04.11 [1.9.5] pass current tiddler object into wrapper code so it can be referenced from within 'onclick' scripts
2009.02.26 [1.9.4] in $(), handle leading '#' on ID for compatibility with JQuery syntax
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.InlineJavascriptPlugin= {major: 1, minor: 9, revision: 5, date: new Date(2009,4,11)};

config.formatters.push( {
	name: "inlineJavascript",
	match: "\\<script",
	lookahead: "\\<script(?: src=\\\"((?:.|\\n)*?)\\\")?(?: label=\\\"((?:.|\\n)*?)\\\")?(?: title=\\\"((?:.|\\n)*?)\\\")?(?: key=\\\"((?:.|\\n)*?)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",

	handler: function(w) {
		var lookaheadRegExp = new RegExp(this.lookahead,"mg");
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var src=lookaheadMatch[1];
			var label=lookaheadMatch[2];
			var tip=lookaheadMatch[3];
			var key=lookaheadMatch[4];
			var show=lookaheadMatch[5];
			var code=lookaheadMatch[6];
			if (src) { // external script library
				var script = document.createElement("script"); script.src = src;
				document.body.appendChild(script); document.body.removeChild(script);
			}
			if (code) { // inline code
				if (show) // display source in tiddler
					wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
				if (label) { // create 'onclick' command link
					var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
					var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
					link.code="function _out(place,tiddler){"+fixup+"\n};_out(this,this.tiddler);"
					link.tiddler=w.tiddler;
					link.onclick=function(){
						this.bufferedHTML="";
						try{ var r=eval(this.code);
							if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
								var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
							if(this.bufferedHTML.length)
								s.innerHTML=this.bufferedHTML;
							if((typeof(r)==="string")&&r.length) {
								wikify(r,s,null,this.tiddler);
								return false;
							} else return r!==undefined?r:false;
						} catch(e){alert(e.description||e.toString());return false;}
					};
					link.setAttribute("title",tip||"");
					var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
					URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
					URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
					link.setAttribute("href",URIcode);
					link.style.cursor="pointer";
					if (key) link.accessKey=key.substr(0,1); // single character only
				}
				else { // run script immediately
					var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
					var c="function _out(place,tiddler){"+fixup+"\n};_out(w.output,w.tiddler);";
					try	 { var out=eval(c); }
					catch(e) { out=e.description?e.description:e.toString(); }
					if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
				}
			}
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} )
//}}}

// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") window.wikifyPlainText=function(text,limit,tiddler) {
	if(limit > 0) text = text.substr(0,limit);
	var wikifier = new Wikifier(text,formatter,null,tiddler);
	return wikifier.wikifyPlain();
}
//}}}

// // GLOBAL FUNCTION: $(...) -- 'shorthand' convenience syntax for document.getElementById()
//{{{
if (typeof($)=='undefined') { function $(id) { return document.getElementById(id.replace(/^#/,'')); } }
//}}}
/***
|Name|InlineJavascriptPluginInfo|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.4|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|Documentation for InlineJavascriptPlugin|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Usage
<<<
This plugin adds wiki syntax for surrounding tiddler content with {{{<script>}}} and {{{</script>}}} markers, so that it can be recognized as embedded javascript code.
<script show>
	/* javascript code goes here... */
</script>Every time the tiddler content is rendered, the javascript code is automatically evaluated, allowing you to invoke 'side-effect' processing and/or produce dynamically-generated content that is then inserted into the tiddler content, immediately following the script (see below).  By including the optional ''show'' keyword as the final parameter in a {{{<script>}}} marker, the plugin will also include the script source code in the output that it displays in the tiddler.  This is helpful when creating examples for documentation purposes (such as used in this tiddler!)

__''Deferred execution from an 'onClick' link''__
<script label="click here" title="mouseover tooltip text" key="X" show>
	/* javascript code goes here... */
	alert('you clicked on the link!');
</script>
By including a {{{label="..."}}} parameter in the initial {{{<script>}}} marker, the plugin will create a link to an 'onclick' script that will only be executed when that specific link is clicked, rather than running the script each time the tiddler is rendered.  You may also include a {{{title="..."}}} parameter to specify the 'tooltip' text that will appear whenever the mouse is moved over the onClick link text, and a {{{key="X"}}} parameter to specify an //access key// (which must be a //single// letter or numeric digit only).

__''Loading scripts from external source files''__
<script src="URL" show>
	/* optional javascript code goes here... */
</script>You can also load javascript directly from an external source URL, by including a src="..." parameter in the initial {{{<script>}}} marker (e.g., {{{<script src="demo.js"></script>}}}).  This is particularly useful when incorporating third-party javascript libraries for use in custom extensions and plugins.  The 'foreign' javascript code remains isolated in a separate file that can be easily replaced whenever an updated library file becomes available.

In addition to loading the javascript from the external file, you can also use this feature to invoke javascript code contained within the {{{<script>...</script>}}} markers.  This code is invoked //after// the external script file has been processed, and can make immediate use of the functions and/or global variables defined by the external script file.
>Note: To ensure that your javascript functions are always available when needed, you should load the libraries from a tiddler that is rendered as soon as your TiddlyWiki document is opened, such as MainMenu.  For example: put your {{{<script src="..."></script>}}} syntax into a separate 'library' tiddler (e.g., LoadScripts), and then add {{{<<tiddler LoadScripts>>}}} to MainMenu so that the library is loaded before any other tiddlers that rely upon the functions it defines. 
>
>Normally, loading external javascript in this way does not produce any direct output, and should not have any impact on the appearance of your MainMenu.  However, if your LoadScripts tiddler contains notes or other visible content, you can suppress this output by using 'inline CSS' in the MainMenu, like this: {{{@@display:none;<<tiddler LoadScripts>>@@}}}
<<<
!!!!!Creating dynamic tiddler content and accessing the ~TiddlyWiki DOM
<<<
An important difference between TiddlyWiki inline scripting and conventional embedded javascript techniques for web pages is the method used to produce output that is dynamically inserted into the document: in a typical web document, you use the {{{document.write()}}} (or {{{document.writeln()}}}) function to output text sequences (often containing HTML tags) that are then rendered when the entire document is first loaded into the browser window.

However, in a ~TiddlyWiki document, tiddlers (and other DOM elements) are created, deleted, and rendered "on-the-fly", so writing directly to the global 'document' object does not produce the results you want (i.e., replacing the embedded script within the tiddler content), and instead will //completely replace the entire ~TiddlyWiki document in your browser window (which is clearly not a good thing!)//.  In order to allow scripts to use {{{document.write()}}}, the plugin automatically converts and buffers all HTML output so it can be safely inserted into your tiddler content, immediately following the script.

''Note that {{{document.write()}}} can only be used to output "pure HTML" syntax.  To produce //wiki-formatted// output, your script should instead return a text value containing the desired wiki-syntax content'', which will then be automatically rendered immediately following the script.  If returning a text value is not sufficient for your needs, the plugin also provides an automatically-defined variable, 'place', that gives the script code ''direct access to the //containing DOM element//'' into which the tiddler output is being rendered.  You can use this variable to ''perform direct DOM manipulations'' that can, for example:
* generate wiki-formatted output using {{{wikify("...content...",place)}}}
* vary the script's actions based upon the DOM element in which it is embedded
* access 'tiddler-relative' DOM information using {{{story.findContainingTiddler(place)}}}
Note:
''When using an 'onclick' script, the 'place' element actually refers to the onclick //link text// itself, instead of the containing DOM element.''  This permits you to directly reference or modify the link text to reflect any 'stateful' conditions that might set by the script.  To refer to the containing DOM element from within an 'onclick' script, you can use "place.parentNode" instead.
<<<
!!!!!Instant "bookmarklets"
<<<
You can also use an 'onclick' link to define a "bookmarklet": a small piece of javascript that can be ''invoked directly from the browser without having to be defined within the current document.''  This allows you to create 'stand-alone' commands that can be applied to virtually ANY TiddlyWiki document... even remotely-hosted documents that have been written by others!!  To create a bookmarklet, simply define an 'onclick' script and then grab the resulting link text and drag-and-drop it onto your browser's toolbar (or right-click and use the 'bookmark this link' command to add it to the browser's menu).

Notes:
*When writing scripts intended for use as bookmarklets, due to the ~URI-encoding required by the browser, ''you cannot not use ANY double-quotes (") within the bookmarklet script code.''
*All comments embedded in the bookmarklet script must ''use the fully-delimited {{{/* ... */}}} comment syntax,'' rather than the shorter {{{//}}} comment syntax.
*Most importantly, because bookmarklets are invoked directly from the browser interface and are not embedded within the TiddlyWiki document, there is NO containing 'place' DOM element surrounding the script.  As a result, ''you cannot use a bookmarklet to generate dynamic output in your document,''  and using {{{document.write()}}} or returning wiki-syntax text or making reference to the 'place' DOM element will halt the script and report a "Reference Error" when that bookmarklet is invoked.  
Please see [[InstantBookmarklets]] for many examples of 'onclick' scripts that can also be used as bookmarklets.
<<<
!!!!!Special reserved function name
<<<
The plugin 'wraps' all inline javascript code inside a function, {{{_out()}}}, so that any return value you provide can be correctly handled by the plugin and inserted into the tiddler.  To avoid unpredictable results (and possibly fatal execution errors), this function should never be redefined or called from ''within'' your script code.
<<<
!!!!!$(...) 'shorthand' function
<<<
As described by Dustin Diaz [[here|http://www.dustindiaz.com/top-ten-javascript/]], the plugin defines a 'shorthand' function that allows you to write:
{{{
$(id)
}}}
in place of the normal standard javascript syntax:
{{{
document.getElementById(id)
}}}
This function is provided merely as a convenience for javascript coders that may be familiar with this abbreviation, in order to allow them to save a few bytes when writing their own inline script code.
<<<
!!!!!Examples
<<<
simple dynamic output:
><script show>
	document.write("The current date/time is: "+(new Date())+"<br>");
	return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
dynamic output using 'place' to get size information for current tiddler:
><script show>
	if (!window.story) window.story=window;
	var title=story.findContainingTiddler(place).getAttribute("tiddler");
	var size=store.getTiddlerText(title).length;
	return title+" is using "+size+" bytes";
</script>
dynamic output from an 'onclick' script, using {{{document.write()}}} and/or {{{return "..."}}}
><script label="click here" show>
	document.write("<br>The current date/time is: "+(new Date())+"<br>");
	return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
creating an 'onclick' button/link that accesses the link text AND the containing tiddler:
><script label="click here" title="clicking this link will show an 'alert' box" key="H" show>
	if (!window.story) window.story=window;
	var txt=place.firstChild.data;
	var tid=story.findContainingTiddler(place).getAttribute('tiddler');
	alert('Hello World!\nlinktext='+txt+'\ntiddler='+tid);
</script>
dynamically setting onclick link text based on stateful information:
>{{block{
{{{
<script label="click here">
	/* toggle "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.innerHTML=on?"enable":"disable";
	config.txtSomething=on?"OFF":"ON";
	return "\nThe current value is: "+config.txtSomething;
</script><script>
	/* initialize onclick link text based on current "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.lastChild.previousSibling.innerHTML=on?"disable":"enable";
</script>
}}}
<script label="click here">
	/* toggle "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.innerHTML=on?"enable":"disable";
	config.txtSomething=on?"OFF":"ON";
	return "\nThe current value is: "+config.txtSomething;
</script><script>
	/* initialize onclick link text based on current "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.lastChild.innerHTML=on?"enable":"disable";
</script>
}}}
loading a script from a source url:
>http://www.TiddlyTools.com/demo.js contains:
>>{{{function inlineJavascriptDemo() { alert('Hello from demo.js!!') } }}}
>>{{{displayMessage('InlineJavascriptPlugin: demo.js has been loaded');}}}
>note: When using this example on your local system, you will need to download the external script file from the above URL and install it into the same directory as your document.
>
><script src="demo.js" show>
	return "inlineJavascriptDemo() function has been defined"
</script>
><script label="click to invoke inlineJavascriptDemo()" key="D" show>
	inlineJavascriptDemo();
</script>
<<<
!!!!!Revisions
<<<
2009.02.26 [1.9.4] in $(), handle leading '#' on ID for compatibility with JQuery syntax
2008.06.11 [1.9.3] added $(...) function as 'shorthand' for document.getElementById()
2008.03.03 [1.9.2] corrected fallback declaration of wikifyPlainText() (fixes Safari "parse error")
2008.02.23 [1.9.1] in onclick function, use string instead of array for 'bufferedHTML' (fixes IE errors)
2008.02.21 [1.9.0] output from 'onclick' scripts (return value or document.write() calls) are now buffered and rendered into into a span following the script.  Also, added default 'return false' handling if no return value provided (prevents HREF from being triggered -- return TRUE to allow HREF to be processed).  Thanks to Xavier Verges for suggestion and preliminary code.
2008.02.14 [1.8.1] added backward-compatibility for use of wikifyPlainText() in TW2.1.3 and earlier
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 [1.8.0] added support for key="X" syntax to specify custom access key definitions
2007.12.15 [1.7.0] autogenerate URI encoded HREF on links for onclick scripts.  Drag links to browser toolbar to create bookmarklets.  IMPORTANT NOTE: place is NOT defined when scripts are used as bookmarklets.  In addition, double-quotes will cause syntax errors.  Thanks to PaulReiber for debugging and brainstorming.
2007.11.26 [1.6.2] when converting "document.write()" function calls in inline code, allow whitespace between "write" and "(" so that "document.write ( foobar )" is properly converted.
2007.11.16 [1.6.1] when rendering "onclick scripts", pass label text through wikifyPlainText() to parse any embedded wiki-syntax to enable use of HTML entities or even TW macros to generate dynamic label text.
2007.02.19 [1.6.0] added support for title="..." to specify mouseover tooltip when using an onclick (label="...") script
2006.10.16 [1.5.2] add newline before closing '}' in 'function out_' wrapper.  Fixes error caused when last line of script is a comment.
2006.06.01 [1.5.1] when calling wikify() on script return value, pass hightlightRegExp and tiddler params so macros that rely on these values can render properly
2006.04.19 [1.5.0] added 'show' parameter to force display of javascript source code in tiddler output
2006.01.05 [1.4.0] added support 'onclick' scripts.  When label="..." param is present, a button/link is created using the indicated label text, and the script is only executed when the button/link is clicked.  'place' value is set to match the clicked button/link element.
2005.12.13 [1.3.1] when catching eval error in IE, e.description contains the error text, instead of e.toString().  Fixed error reporting so IE shows the correct response text.  Based on a suggestion by UdoBorkowski
2005.11.09 [1.3.0] for 'inline' scripts (i.e., not scripts loaded with src="..."), automatically replace calls to 'document.write()' with 'place.innerHTML+=' so script output is directed into tiddler content.  Based on a suggestion by BradleyMeck
2005.11.08 [1.2.0] handle loading of javascript from an external URL via src="..." syntax
2005.11.08 [1.1.0] pass 'place' param into scripts to provide direct DOM access 
2005.11.08 [1.0.0] initial release
<<<
//~ArchiMate// is an open and independent enterprise architecture modeling language to support the description, analysis and visualization of architecture within and across business domains in an unambiguous way. It's a technical standard from The Open Group nowadays. The main concepts and relationships of the language can be seen as a framework, the so-called ~ArchiMate Framework./%

%/
!!!Documentation
*[[The ArchiMate Framework of aspects and layers — legend for the symbols|Notation of ArchiMate concepts]]
*https://en.wikipedia.org/wiki/ArchiMate
*{{f3m{//An Introduction to the ~ArchiMate 3.0.1 Specification// (white paper): https://publications.opengroup.org/w168 (PDF edition & PDF slideset)}}}
*{{f3m{//The ~ArchiMate 3.0.1 Modeling Language -- Understanding the Basics// (white paper): https://publications.opengroup.org/w175}}}
*{{f3m{//~ArchiMate 3.0.1 Specification// (Open Group Standard): http://pubs.opengroup.org/architecture/archimate3-doc/ (HTML edition online)}}}
*{{z t ls{19 JUNE 2023}}}: new links in https://publications.opengroup.org/archimate-library /%

%/
!!!Videos@@float:right;margin-left:0.5em;position-:relative;top:-1em;[img[data/images/ArchiMate/Rectangles-reduced.png]]@@
*{{multiLine{https://www.youtube.com/watch?v=ULl9lf0OZco&list=PLB8F2ECDADEE616AA&index=1 (6'28")
This is part 1 of a series //Introduction to Archimate 3.0//+++(~ArchiMate3InPractice)[&darr;|show series][&uarr;|hide series]
#The Framework (6'28")
#Generic Metamodel (1'36")
#Motivation & Strategy (6'47")
#Physical Elements (6'09")
#Relationships (8'02")
#Improvements & Notation (8'06")
#Viewpoints, Standards & Wrap-up (4'58")
=== by Marc Lankhorst (published 2016-06-17).}}}
*{{multiLine{https://www.youtube.com/watch?v=_kmYkxKb_-o&index=8&list=PLB8F2ECDADEE616AA (14'47")
This is part 1 of a series //Archimate 3.0 in Practice//+++(~anotherArchiMate3InPractice)[&darr;|show series][&uarr;|hide series]
#Introduction (14'47")
#Capability-based Planning (10'03")
#Digital Transformation (8'44")
#The Internet of Things (4'02")
#Manufacturing (4'54")
=== by Marc Lankhorst (published 2016-06-27).
--{{f3m{Roughly covered by https://www.ngi-ngn.nl/Afdelingen/Architectuur/Evenementen/Whats-new/Bijlagen/ArchiMate-3-in-Practice-NGI-GIA-60.pdf.}}}--}}}/%

%/
!!!Tooling
*Archi:
**[[https://en.wikipedia.org/wiki/Archi_(tool)|https://en.wikipedia.org/wiki/Archi_(tool)]]
**https://archimatetool.com/
*ARIS{{ref{&#x200a;[[[1]|##1]]&#x200a;}}} for ~ArchiMate:
**https://en.wikipedia.org/wiki/Architecture_of_Integrated_Information_Systems
**--{{f3m{http://www1.softwareag.com/corporate/rc/rc_perma.asp?key=16-113493}}}--
*Visio stencils set for ~ArchiMate 3.0:
**https://publications.opengroup.org/i163

----
<html><a name="1">[1]</a></html>&nbsp; You might be interested in the free [[ARIS Express|http://www.ariscommunity.com/aris-express]] software, even though architecture is not included. See also https://en.wikipedia.org/wiki/ARIS_Express.
''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''

Bij lezing van hoofdstuk 23 over //iteratoren// en //generatoren// in Sproncks Programmeursleerling{{ref{&#x200a;[[[1]|##1]]}}} viel me op dat deze constructies in vergelijking met wat ik gewend was niet echt voor de hand liggen. Het gaat hier niet zozeer om exclusieve Python-concepten, want in andere talen zijn ze ook te vinden. Aan het eind van het hoofdstuk gekomen leek ik het me wel een goed idee de verschillende manieren van itereren eens met elkaar te vergelijken en op die manier de onderliggende mechanismen beter te doorgronden. (Als het je erom begonnen is snel een overzicht te krijgen van hoe als Python-programmeur een iteratieopgave aan te pakken, trek dan even een klein half uurtje uit voor [[deze presentatie van Ned Batchelder|https://www.youtube.com/watch?v=EnSu9hHGq5o&t=1184s&ab_channel=NextDayVideo]].) /%

%/
!!Aanloop
Eerst maar even een recapitulatie van de oervormen, hier gecodeerd in [[Lua]] (ik zal alle Lua-code hier ter onderscheid van andere talen op een lichtgroene achtergrond plaatsen). Onderstaand algoritme print de getallen 1 t/m 4 onder elkaar:
{{pre4{
i = 1
''while'' """i <= 4 do
  print(i)
  i = i + 1
end"""
}}}/%

%/Naast zo'n ''{{{while}}}''-lus kennen veel programmeertalen ook een numerieke ''{{{for}}}''-lus:{{ref{&#x200a;[[[2]|##2]]}}}
{{pre4{
''for'' """i = 1, 4 do
  print(i)
end"""
}}}/%

%/Feitelijk een overbodig luxe-artikel wanneer er al in {{tt t{while}}} is voorzien, maar toch wel prettig in de omgang, omdat al het administratieve werk om de iteratievorderingen bij te houden in die ene formule {{pref hitt4 z{i = 1, 4}}} gevangen is (met een derde waarde kan bovendien de stapgrootte worden ingesteld; de verstekwaarde hiervoor is {{tt t{1}}}). In C en veel daarvan afgeleide talen is {{tt t{for}}} wat verder opgetuigd tot een meer generieke constructie:
{{pre3{
''for'' """(i = 1; i <= 4; i++)
  printf("%d\n", i);"""
}}}/%

%/Tussen de haakjes op de eerste regel staan drie expressies: een initialisatie, de voorwaarde om met itereren door te gaan, en tot slot een bewerking die aan het eind van elke iteratie moet worden uitgevoerd. De flexibiliteit die deze constructie biedt, evenaart die van de {{tt t{while}}}-lus. Toch is {{tt t{while}}} in C wel gehandhaafd. Zo niet in [[Go|https://go.dev/]] en [[V|https://vlang.io/]], waar alleen de {{tt t{for}}}-lus is overgebleven. Python is een andere weg ingeslagen. Daar ontbreekt de numerieke {{tt t{for}}}, maar is wel een generieke ''{{tt{for&mdash;in}}}''-constructie aanwezig die in staat is door 'iterabele objecten' zoals een [[sequentie|Nomenclatuur van sequences en maps]] heen te wandelen (wat in Go, V en vele andere eigentijdse talen overigens evenzeer mogelijk is) en daardoor vaak een prominente rol in Python-programma's vervult:
{{pre{
numbers = [10, 20, 30]    {{fgre{//# a Python list of three numbers//}}}

''for'' n ''in'' numbers:
"""    print(n)"""
}}}/%

%/Dat doet bij mij de vraag rijzen wat er bij deze {{tt t{for&mdash;in}}} onder water precies gebeurt. Is het gedrag te simuleren? Uitproberen maar&#x200a;!/%

%/
!!Wat zou er in {{tt{for&mdash;in}}} kunnen zitten?
Hieronder een eerste poging om Python's ''{{tt{for&mdash;in}}}'' na te bootsen met een in Lua geprogrammeerde functie ''{{{each}}}'':
{{pre4{
function ''each'' """(seq, fun)                  """{{fgre{//"""--""" second parameter is a function: functions are first-class objects in Lua//}}}
"""  local i = 1                             """{{fgre{//"""--""" indexing of sequences starts at 1 in Lua//}}}
"""  while i <= #seq do                      """{{fgre{//"""--""" {{t{#seq}}} is the length of seq//}}}
"""    fun(seq[i])                           """{{fgre{//"""--""" function {{t{fun}}} is called//}}}
"""    i = i + 1
  end
end

numbers = {10, 20, 30}                    """{{fgre{//"""--""" a Lua sequence of three numbers//}}}

''each''"""(numbers, function (n) print(n) end)  """{{fgre{//"""--""" second argument is an anonymous function (aka lambda)//}}}
}}}/%

%/Ja, dit programmaatje slaagt er inderdaad in de waarden {{tt t{10}}}, {{tt t{20}}} en {{tt t{30}}} van de sequentie {{tt t{numbers}}} af te drukken.{{ref{[[[3]|##3]]}}} Maar wat als ik te maken krijg met een andere zeer populaire datacomposiet, de [[dictionary|Nomenclatuur van sequences en maps]]? Bij de volgende instructies:
{{pre{
keyed_numbers = {'A': 10, 'B': 11, 'C': 12}  {{fgre{//# a Python dictionary of three key/value pairs//}}}

''for'' k ''in'' keyed_numbers:
"""    print(k, keyed_numbers[k])"""
}}}/%
%/drukt Python de sleutel/waarde-paren {{tt t{A}}} {{tt t{10}}}, {{tt t{B}}} {{tt t{11}}} en {{tt t{C}}} {{tt t{12}}} af. Hoe zoiets te imiteren in Lua? De aanpak voor {{tt t{each}}} hierboven werkt nu niet meer, daar Lua geen voorzieningen bevat om de omvang van een dictionary op te vragen ({{hitt4 z{#keyed_numbers}}} levert {{tt t{0}}} op) of via een volgnummer de sleutelwaarden op te vragen. Lua is vrij primitief maar toch behoorlijk veelzijdig, wat precies de reden is waarom ik deze taal heb uitgekozen om de onderliggende mechanismen zichtbaar te maken. Uiteindelijk blijkt er één basaal middel aanwezig om systematisch door een Lua-dictionary {{pref hitt4 z{"""{A = 10, B = 11, C = 12}"""}}} heen te wandelen, namelijk de ingebouwde functie ''{{{next}}}''. De aanroep {{pref hitt4 z{next(keyed_numbers)}}} levert de eerste sleutel en de ermee geassocieerde waarde op. Veronderstel dat dit het paar {{tt t{A}}} {{tt t{10}}} is. Roep vervolgens {{tt t{next}}} nog eens aan met de verkregen {{tt t{A}}} als tweede parameter: {{pref hitt4 z{next(keyed_numbers, "A")}}}. Dat retourneert het volgende sleutel/waarde-paar, en dat zou best {{tt t{C}}} {{tt t{12}}} kunnen zijn, want de interne volgorde van de paren is in Lua onbepaald. Waar het om gaat, is dat uiteindelijk alle paren op deze manier kunnen worden afgewerkt. De functie retourneert {{tt t{nil}}} als er geen volgend paar meer over is, dus een stopcriterium wordt eveneens aangereikt. Hiermee kan ik wel uit de voeten.

Moet ik niet eerst uitzoeken hoe Lua's {{tt t{next}}} werkt? Wat mij betreft: nee. Ik zie dat als een interne aangelegenheid van Lua zelf. Ik weet nu genoeg om de werking van {{tt t{for&mdash;in}}} op een interessant abstractieniveau te kunnen modelleren./%

%/
!!Vier rollen en één bijzondere taak
Het hele iteratiegebeuren is een samenspel van verschillende componenten die een verschillende rol vervullen. Ik onderscheid vier rollen in dit spel:
; Provider {{n{-- //Leverancier//}}}
: De provider zorgt ervoor dat er data beschikbaar zijn. Dat kan de vorm hebben van een concrete datacollectie in het geheugen, zoals een sequentie of dictionary, maar ook virtuele collecties zijn denkbaar, zoals het ''{{{range}}}''-object in Python of een willekeurig algoritme dat een nieuw gegeven produceert zodra erom gevraagd wordt.
; Deliverer {{n{-- //Bezorger//}}}
: De deliverer levert het beschikbare gegeven daadwerkelijk af op de plaats waar het nodig is.
; Pilot {{n{-- //Loods//}}}
: De pilot brengt het iteratieproces tot leven en leidt het in goede banen, met name door te stoppen wanneer de provider uitgeput blijkt.
; Procedure
: De al dan niet geparametriseerde procedure die bij elke iteratie moet worden uitgevoerd.
In veel iteratieconstructies is elke rol aan één specifieke softwarecomponent toegewezen. Het is echter evengoed mogelijk verschillende rollen te combineren in één component. Zo is de {{tt t{each}}}-functie in mijn eerste poging hierboven om {{tt t{for&mdash;in}}} na te bootsen tegelijkertijd deliverer en pilot, terwijl de providerrol wordt vervuld door de sequentie die als argument aan {{tt t{each}}} wordt meegegeven.

Configuraties kunnen complexer zijn dan maximaal vier spelers (voor elke rol een). Denk aan ketens van providers, ketens van deliverers, geneste pilots en procedures die op hun beurt ook weer iteratieve deelprocessen laten draaien.

Naast de genoemde rollen is er nog een speciale taak te onderkennen, namelijk de ''administratie van de toestand'' waarin het iteratieproces zich bevindt. Die taak kan bij elk van de vier rollen worden belegd. In de meeste opstellingen zal er een of andere vorm van boekhouding worden bijgehouden. Soms is een apart boekhoudings&shy;systeem niet nodig. Betekent levering vanuit een provider dat diens voorraad afneemt, dan is de voorraad zelf al de administratie en ligt het voor de hand de provider als 'boekhouder' te zien. Aan de andere kant van de keten kan het de procedure zijn die vaststelt wanneer het verzadigingspunt is bereikt en op grond daarvan ingrijpt in het iteratieproces.

Met dit bescheiden begrippenapparaat zou het mogelijk moeten zijn verschillende situaties in ogenschouw te nemen en daar op goed gearticuleerde wijze verslag van te doen. Laten we beginnen met mijn ambitie om de werking van het {{tt t{for&mdash;in}}}-statement in Python, Ruby en Lua te ontsluieren. In [[Simulaties van for...in...-statement]] staan mijn bevindingen opgetekend. Ondanks forse onderlinge verschillen vervult het statement bij alle drie overduidelijk de pilot-rol. Alleen de Lua-implementatie van deze pilot houdt bovendien ook de toestand nog eens bij./%

%/
!!De gebouwde iteratiemodellen
In onderstaande tabel is per model aangegeven hoe de verschillende rollen zijn ingevuld. Ik heb hierbij component&shy;typeringen aangehouden volgens de taal waaraan het model is ontleend. Dit geldt echter niet voor het closuremodel, dat niet specifiek voor een van de hier behandelde talen is (ze ondersteunen alle drie closures, omdat functies daar eersterangs objecten{{ref{&#x200a;[[[4]|##4]]}}} zijn die bovendien variabelen uit hun omgeving kunnen lezen en muteren).
|!Model                                               |!Provider                      |!Deliverer                                |!Pilot                             |
|[[Provider à la Python-iterator]]                    |''iterator''                   |{{{next}}}-functie, {{{__next__}}}-method |{{tt{for&mdash;in}}}-statement     |
|[[Boekhoudende pilot in Python|Het samenspel van iter en __getitem__ in Python]] |iterable |{{{__get_item__}}}-method           |''{{tt{for&mdash;in}}}-statement'' |
|[[Provider à la Python-generator]]                   |''generator''                  |{{{next}}}-functie, {{{__next__}}}-method |{{tt{for&mdash;in}}}-statement     |
|[[Geïntegreerde provider/deliverer/pilot à la Ruby]] |''object / iterator''          |''iterator''                              |''iterator''                       |
|[[Pilot à la Lua]]                                   |iterator factory               |iterator            |''{{tt{for&mdash;in}}}-statement'' ('true iterator')     |
|[[Delivery by closure]]                              |function factory               |''function'' (in Ruby: 'lambda')          |{{{while}}}-statement              |
De partij die de administratie voert is vet gedrukt.

Voor elke configuratie wordt de omgang met een als subroutine uitgevoerde teller aan de tand gevoeld. Aanvankelijk had ik de verzameling van alle natuurlijke getallen groter dan {{tt t{0}}} in gedachten, maar om ongelukken te voorkomen heb ik de teller van een ingebouwde rem voorzien, zodat de productie vanzelf stokt na vier waarden te hebben opgeleverd. Voor de aardigheid heb ik het toegepaste increment in de subroutine geparametriseerd.

Het tweede geval betreft een stukje passieve data in de vorm van een collectie van gegevenselementen. Ik heb daarvoor een [[dictionary|Nomenclatuur van sequences en maps]] van drie sleutel/waarde-paren gekozen met de sleutels {{tt t{"A"}}}, {{tt t{"B"}}}, {{tt t{"C"}}} en de respectievelijke waarden {{tt t{10}}}, {{tt t{11}}}, {{tt t{12}}}. Niet bij alle configuraties levert dat ten opzichte van het tellergeval meer inzicht op. Dan heb ik het voor het gemak maar helemaal weggelaten.

''{{fred sans{~!~ Deze tiddler is nog niet helemaal af. En hoe zit het met --{{hitt be fwhi z{enumerate}}}-- en {{hitt be fwhi z{map}}} (Pickaxe p. 55)? {{hitt be fwhi z{map}}} wordt pas interessant als ik iets over comprehensions wil schrijven. ~!~}}}''

----
|plain |k
|<html><a name="1">[1]</a></html>|<<tiddler Bibliografie##Spronck>> |
|<html><a name="2">[2]</a></html>|Dit voorbeeld is niet helemaal gelijkwaardig aan het vorige. In Lua is de besturingsvariabele van een {{tt t{for}}}-lus namelijk per definitie lokaal. Zoiets verschilt per taal. |
|<html><a name="3">[3]</a></html>|Er is wel een klein verschil met het Python-origineel: in de imitatie is de variabele {{tt t{n}}} ten gevolge van de scoping-regels na afloop niet meer zichtbaar. |
|<html><a name="4">[4]</a></html>|Dat houdt in dat ze als argument in een functieaanroep kunnen worden meegegeven en ook als returnwaarde kunnen worden teruggegeven. |
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Commentaar bij [[Iteratiemechanismen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''

Het aantal verschillende iteratiestatements in Python is erg overzichtelijk: ''{{{while}}}'' en ''{{{for}}}''. Ze zijn daarentegen best wel bijzonder. Ze bevatten namelijk een ''{{{else}}}''-clausule. Het werkt als volgt.
{{lf w35pct pr3em{{{pre{
''while'' //testBefore//'':''
"""    """//activityA//
"""    """''if'' //testInside//'':''
"""        """//activityC//
"""        """''break''
"""    """//activityB//
{{fblu{''else'':
"""    """//activityD//}}}
}}}/%

%/De {{tt t{else}}}-tak wordt alleen uitgevoerd als er //geen// {{tt t{break}}} plaatsvindt. Je kunt het lezen als: "Itereer nog eens als //{{{testBefore}}}// positief uitvalt, en voer anders de {{tt t{else}}}-tak uit." Door de {{tt t{break}}} komt het nooit tot een negatieve uitslag van //{{{testBefore}}}//.

Bij {{tt t{for}}} gaat het op dezelfde manier. Het enige verschil is, dat je minder vrijheid hebt //{{{testBefore}}}// naar believen in te richten. Bij {{tt t{while}}} is alles wat zich als een booleaanse expressie laat evalueren toe te passen, terwijl het bij {{tt t{for}}} onverbiddelijk neerkomt op: "Is het gegeven object nog in staat nieuwe gegevens te leveren?" Verrassend hoeveel er in dat keurslijf toch nog mogelijk is.<br>&nbsp;}}}
{{up{{{up{[img[data/images/AD while-else in Python.png]]}}}}}}/%
%/
{{clear block{(Ondanks dat het als een activiteitendiagram volgens UML gestileerd is, is bovenstaande grafische representatie van het {{tt t{while}}}-mechanisme gewoon een ouderwets stroom­schema. De regelen der UML-kunst hadden gewild dat ik zo'n iteratief proces als een zogeheten //expansion region// zou weergeven. Geen adequaat abstractie­niveau om dit soort beslissings­logica te illustreren, dus heb ik toch maar weer eens terug­gegrepen naar meer klassieke technieken.)}}}/%

%/+++(~IteratieStatementsGenesteWhiles)!!![Een praktische toepassing van else &darr;|show][Een praktische toepassing van else &uarr;|hide]
{{lf w35pct pr3em{
De {{tt t{else}}}-clausule kan heel goed van pas komen wanneer je in een geneste iteratie wilt uitbreken naar een hoger niveau dan het direct bovenliggende:
{{pre{
{{fblu{''while'' //outerTestBefore//'':''
"""    """//activityZ//}}}
"""    """''while'' //testBefore//'':''
"""        """//activityA//
"""        """''if'' //testInside//'':''
"""            """//activityC//
"""            """''break''
"""        """//activityB//
{{fblu{"""    """''else:''
"""        """//activityD//
"""        """''continue''
"""    """''break''}}}
}}}/%

%/Hoe verder je het hogerop zoekt, des te langer de keten van tussen&shy;liggende {{tt t{break}}}s. Dat is misschien wel een beetje jammer.

Hoe zou ik dit geval in een aantal andere talen waar ik graag mee werk aanpakken? Ruby heeft er een ''{{tt{throw&mdash;catch}}}''-mechanisme voor:
{{pref tt s med ws pred d2p r scroll{
{{fred{''catch(:stop) do''}}}
"""  """{{fblu{''while'' //outerTestBefore// ''do''
"""    """//activityZ//}}}
"""    """''while'' //testBefore// ''do''
"""      """//activityA//
"""      """''if'' //testInside// ''then''
"""        """//activityC//
"""        """{{fred{''throw :stop''}}}
"""      """''end''
"""      """//activityB//
"""    """end
"""    """{{fblu{//activityD//
"""  """''end''}}}
{{fred{''end''}}}
}}}/%

%/Sinds de invoering van ''{{{goto}}}'' in Lua versie 5.3 is een grote sprong daar eveneens zonder gedoe met extra vlagvariabelen of iets dergelijks te realiseren:
{{pre4{
{{fblu{''while'' //outerTestBefore// ''do''
"""  """//activityZ//}}}
"""  """''while'' //testBefore// ''do''
"""    """//activityA//
"""    """''if'' //testInside// ''then''
"""      """//activityC//
"""      """{{fred{''goto STOP''}}}
"""    """''end''
"""    """//activityB//
"""  """''end''
"""  """{{fblu{//activityD//
''end''}}}
{{fred{''::STOP::''}}}
}}}
}}}
{{up{{{up{[img[data/images/AD nested whiles in Python.png]]}}}}}}
===
/%

%/{{clear block{+++(~IteratieStatementsRecursie)!!!["Iteratie is voor watjes" &darr;|show]["Iteratie is voor watjes" &uarr;|hide]{{rf pl1em w35pct lift{{{pre4{
i = 0
{{b1f{do}}}
  {{b1f{local}}}""" function """''_while''""" ()
    """''if''""" i < n """''then''"""      """{{fgre{"""--""" //testBefore//}}}"""
      print(i)         """{{fgre{"""--""" //activityA//}}}"""
      """''if'' i == 4 ''then''"""   """{{fgre{"""--""" //testInside//}}}"""
        print "Four!"  """{{fgre{"""--""" //activityC//}}}"""
        """''return''"""         """{{fgre{"""--""" ''break'' //equivalent//}}}"""
      """''end''"""
      i = i + 1        """{{fgre{"""--""" //activityB//}}}"""
      """''_while()''"""         """{{fgre{"""--""" ''recursive call'' }}}"""
    """{{fblu{''else''}}}"""
      """{{fblu{print "Done!"}}}"""    """{{fgre{"""--""" //activityD// & ''return''}}}"""
    """''end''"""
  end
  """''_while()''
{{b1f{end}}}
}}}}}}
{{lift{De echte diehards kunnen het natuurlijk zonder dergelijke fratsen stellen. Zij doen het recursief, zoals de uitwerking in Lua hiernaast van de constructie waarmee dit stuk begon. Voor {{tt t{n}}} = 4 eindigt de lus met {{sans{"Done!"}}} en voor {{tt t{n}}} = 6 met {{sans{"Four!"}}}. (Het strikt lokaal maken van de functie {{tt t{_while}}} door het in te pakken in een {{tt t{do&mdash;end}}}-blok is misschien wat al te puristisch. Ik pleeg voor zeer plaatselijke toekenningen de variabelenaam ''{{{_}}}'' te gebruiken en me verder niet te bekommeren om de scope ervan.)

Degenen wier kijk op de wereld geheel naar het Lisp-stramien is gaan staan, zullen nu wellicht onwillekeurig denken aan het patroon dat ik hieronder in de vorm van een stukje Scheme-code heb uitgeschreven.
{{pref tt s med ws pblu d3 r scroll{
@@background-color:#c5d5e1;(let@@ ''_while'' ()
<html>            </html>(''if'' (< i n)<html>                                        </html>; //testBefore//
<html>                (begin (display i) (newline)                   </html>; //activityA//
<html>                       </html>(''if'' (= i 4)<html>                             </html>; //testInside//
<html>                           (begin (display "Four!") (newline)) </html>; //activityC// & ''return''
<html>                           (begin </html>{{byel{(set! i (+ i 1))}}} (''_while''))))<html> </html>; //activityB// & ''recursive call''
<html>                </html>{{fblu{(begin (display "Done!") (newline))}}}<html>)))</html>@@background-color:#c5d5e1;)@@<html>        </html>; //activityD// & ''return''
}}}/%

%/{{clear block{}}}{{rf pl1em w35pct lift{{{pre4{
{{b1f{do}}}
  {{b1f{local}}}""" function """''_while''""" (i)
    """''if''""" i < n """''then''"""      """{{fgre{"""--""" //testBefore//}}}"""
      print(i)         """{{fgre{"""--""" //activityA//}}}"""
      """''if'' i == 4 ''then''"""   """{{fgre{"""--""" //testInside//}}}"""
        print "Four!"  """{{fgre{"""--""" //activityC//}}}"""
        """''return''"""         """{{fgre{"""--""" ''break'' //equivalent//}}}"""
      """''end''"""
      """''_while(''i + 1'')''"""    """{{fgre{"""--""" //activityB// & ''recursive call'' }}}"""
    """{{fblu{''else''}}}"""
      """{{fblu{print "Done!"}}}"""    """{{fgre{"""--""" //activityD// & ''return''}}}"""
    """''end''"""
  end
  """''_while(''0'')''
{{b1f{end}}}
}}}}}}/%

%/Om vervolgens die lelijke toekenning {{hws pblu d3 r tt z{(set! i (+ i 1))}}} te willen verwijderen. Dat kunnen we bij het Lua-voorbeeld eveneens doen. De vraag is natuurlijk of er verderop, buiten de {{tt t{_while}}}-lus, nog behoefte is aan de bijgewerkte waarde van {{tt t{i}}}. Als je te werk gaat volgens het paradigma 'functioneel programmeren', zou dat niet het geval moeten zijn.
{{pref tt s med ws pblu d3 r scroll{
@@background-color:#c5d5e1;(letrec@@ ((''_while''
<html>           (lambda (i)
             </html>(''if'' (< i n)<html>                                        </html>; //testBefore//
<html>                 (begin (display i) (newline)                   </html>; //activityA//
<html>                        </html>(''if'' (= i 4)<html>                             </html>; //testInside//
<html>                            (begin (display "Four!") (newline)) </html>; //activityC// & ''return''
<html>                            (</html>''_while (''+ i 1'')'')))<html>                  </html>; //activityB// & ''recursive call''
<html>                 </html>{{fblu{(begin (display "Done!") (newline))}}}<html>))))        </html>; //activityD// & ''return''
<html>        </html>''(_while'' 0'')''@@background-color:#c5d5e1;)@@
}}}}}}
Wanneer we op een nette manier uit een bouwwerk van geneste recursies willen springen, lijkt de functionele aanpak me daartoe het meest geschikt. Dat houdt in dat de {{tt t{_while}}}-functie via een return&shy;code aangeeft of er sprake is van een break. Het naast&shy;hogere niveau besluit vervolgens wat er met die informatie moet worden gedaan, zelf oplossen of de kwestie ook weer door&shy;geven naar boven. Een strikt hiërarchische opzet dus, vergelijk&shy;baar met de halver&shy;wege dit verhaal getoonde {{tt t{break}}}s-keten in het Python-schema.
===
JSON (~JavaScript Object Notation, spreek uit //dj&eacute;son//) is een extreem lichtgewicht formaat voor gegevensuitwisseling, gemakkelijk te lezen en te schrijven voor zowel mens als machine. Eigenlijk is JSON geen aparte taal, maar simpelweg een geldige expressie in ~JavaScript.

De bouwstenen zijn waarden (bv. ''{{{"HCC"}}}'' en eigenschappen (eigenschapnaam/waarde-paren, bv. ''{{{"vereniging": "HCC"}}}''). Waarden kunnen worden gebundeld tot een array (bv. ''{{{["HCC", "ANWB"]}}}'', en eigenschappen tot een object (bv. ''<html><code>{"vereniging": "HCC", "interessegroep": "HCC!programmeren"}</code></html>''). Een array of een object kan zelf ook weer fungeren als een waarde.

Uit de ''<html><code>{}</code></html>''-notatie blijkt dat de verzameling van objecteigenschappen feitelijk een associatieve array (oftewel hash table) is. Inderdaad kan {{{object.property}}} in ~JavaScript net zo goed worden geschreven als {{{object["property"]}}}.

Met een beperkt stelsel van regels is JSON volledig te definieren. In onderstaande ~BNF-notatie zijn "::=" ("is gedefinieerd als") en "&brvbar;" ("of") metasymbolen, zijn niet-terminale symbolen gecursiveerd, en tellen spaties niet mee. De rest is terminaal, dus datgene wat letterlijk kan worden ingevuld in een geldige ~JSON-expressie.
<<<
//object// ::= ''<html><code>{}</code></html>'' &nbsp;&brvbar;&nbsp; ''{{{{}}}'' //members// ''<html><code>}</code></html>''

//members// ::= //string// ''{{{:}}}'' //value// &nbsp;&brvbar;&nbsp; //members// ''{{{,}}}'' //string// ''{{{:}}}'' //value//

//array// ::= ''{{{[]}}}'' &nbsp;&brvbar;&nbsp; ''{{{[}}}'' //elements// ''{{{]}}}''

//elements// ::= //value// &nbsp;&brvbar;&nbsp; //elements// ''{{{,}}}'' //value//

//value// ::= //string// &nbsp;&brvbar;&nbsp; //number// &nbsp;&brvbar;&nbsp; //object// &nbsp;&brvbar;&nbsp; //array// &nbsp;&brvbar;&nbsp; ''{{{true}}}'' &nbsp;&brvbar;&nbsp; ''{{{false}}}'' &nbsp;&brvbar;&nbsp; ''{{{null}}}''

//string// ::= ''{{{""}}}'' &nbsp;&brvbar;&nbsp; ''{{{"}}}'' //chars// ''{{{"}}}''

//chars// ::= //char// &nbsp;&brvbar;&nbsp; //chars// //char//

//char// ::= //<nowiki>any-Unicode-except-"-or-\-or-control-character</nowiki>// &nbsp;&brvbar;&nbsp; ''{{{\"}}}'' &nbsp;&brvbar;&nbsp; ''{{{\\}}}'' &nbsp;&brvbar;&nbsp; ''{{{\/}}}'' &nbsp;&brvbar;&nbsp; ''{{{\b}}}'' &nbsp;&brvbar;&nbsp; ''{{{\f}}}'' &nbsp;&brvbar;&nbsp; ''{{{\n}}}'' &nbsp;&brvbar;&nbsp; ''{{{\r}}}'' &nbsp;&brvbar;&nbsp; ''{{{\t}}}'' &nbsp;&brvbar;&nbsp; ''{{{\u}}}'' //four-hex-digits//

//four-hex-digits// ::= //hex-digit// //hex-digit// //hex-digit// //hex-digit//

//hex-digit// ::= //digit// &nbsp;&brvbar;&nbsp; ''{{{a}}}'' &nbsp;&brvbar;&nbsp; ''{{{b}}}'' &nbsp;&brvbar;&nbsp; ''{{{c}}}'' &nbsp;&brvbar;&nbsp; ''{{{d}}}'' &nbsp;&brvbar;&nbsp; ''{{{e}}}'' &nbsp;&brvbar;&nbsp; ''{{{f}}}'' &nbsp;&brvbar;&nbsp; ''{{{A}}}'' &nbsp;&brvbar;&nbsp; ''{{{B}}}'' &nbsp;&brvbar;&nbsp; ''{{{C}}}'' &nbsp;&brvbar;&nbsp; ''{{{D}}}'' &nbsp;&brvbar;&nbsp; ''{{{E}}}'' &nbsp;&brvbar;&nbsp; ''{{{F}}}''

//number// ::= //int// &nbsp;&brvbar;&nbsp; //int// //frac// &nbsp;&brvbar;&nbsp; //int// //exp// &nbsp;&brvbar;&nbsp; //int// //frac// //exp//

//int// ::= //digit// &nbsp;&brvbar;&nbsp; //digit1-9// //digits// &nbsp;&brvbar;&nbsp; ''{{{-}}}'' //digit// &nbsp;&brvbar;&nbsp; ''{{{-}}}'' //digit1-9// //digits//

//frac// ::= ''{{{.}}}'' //digits//

//exp// ::= //e// //digits//

//digit// ::= ''{{{0}}}'' &nbsp;&brvbar;&nbsp; //digit1-9//

//digit1-9// ::= ''{{{1}}}'' &nbsp;&brvbar;&nbsp; ''{{{2}}}'' &nbsp;&brvbar;&nbsp; ''{{{3}}}'' &nbsp;&brvbar;&nbsp; ''{{{4}}}'' &nbsp;&brvbar;&nbsp; ''{{{5}}}'' &nbsp;&brvbar;&nbsp; ''{{{6}}}'' &nbsp;&brvbar;&nbsp; ''{{{7}}}'' &nbsp;&brvbar;&nbsp; ''{{{8}}}'' &nbsp;&brvbar;&nbsp; ''{{{9}}}''

//digits// ::= //digit// &nbsp;&brvbar;&nbsp; //digits// //digit//

//e// ::= ''{{{e}}}'' &nbsp;&brvbar;&nbsp; ''{{{e+}}}'' &nbsp;&brvbar;&nbsp; ''{{{e-}}}'' &nbsp;&brvbar;&nbsp; ''{{{E}}}'' &nbsp;&brvbar;&nbsp; ''{{{E+}}}'' &nbsp;&brvbar;&nbsp; ''{{{E-}}}''
<<<
Omwille van de leesbaarheid mogen de ~JSON-tokens ''{{{{}}}'', ''<html><code>}</code></html>'', ''{{{[}}}'', ''{{{]}}}'', ''{{{:}}}'' en ''{{{,}}}'' naar believen worden omgeven met spaties en regelovergangen; voor de betekenis van de expressie heeft dat geen gevolgen. Verder staan ~JSON-parsers doorgaans toe om ~JavaScript-achtig commentaar op te nemen (tussen ''{{{/*}}}'' en ''{{{*/}}}''), dat bij het verwerken van de expressie wordt genegeerd.

Zie ook de [[officiële JSON-website|http://json.org/]], de [[W3Schools-website|https://www.w3schools.com/js/js_json_syntax.asp]], en voor een vergelijking met andere populaire uitwisselingsformaten de tiddler [[XML, YAML en JSON]].
Het commando {{high2{{{tt{''suspend ''@@color(darkorange)://[//@@''-f''@@color(darkorange)://]//@@}}}}}} bewerkstelligt dat het huidige voorgrondproces wordt stilgezet en naar de achtergrond geplaatst. Alleen is het in de meeste situaties niet mogelijk die opdracht vanuit het voorgrondproces te geven. Er is gelukkig een alternatief in de vorm van de toetscombinatie ''~Ctrl-Z''. Je krijgt dan zoiets te zien als:
<html><pre>
[1]+  Stopped                 <font color="darkorange"><i>«command»</i></font> 
</pre></html>/%
%/Het jobnummer (job ID) -- niet te verwarren met het procesnummer (process ID oftewel PID) -- staat tussen teksthaakjes. Het plusteken markeert de huidige job, en een minteken de direct daaraan voorafgaande job.

Ook is het mogelijk een proces meteen in de achtergrond te starten door een ampersand aan de opdracht toe te voegen: {{high2{{{tt{@@color(darkorange)://«command»//@@'' &''}}}}}}.

Voor het beheer van voorgrond- en achtergrondjobs staan de volgende commando's ter beschikking:
*{{high2{{{tt{''bg ''@@color(darkorange)://[«job» ...]//@@}}}}}} -- Verplaatst de opgegeven (of huidige, als er niets is opgegeven) jobs naar de achtergrond (alsof ze met een afsluitende {{high2{''{{tt{&}}}''}}} waren gestart). Wanneer een job al in de achtergrond stond en de status 'Stopped' had, wordt deze weer in gang gezet (de status wordt dan 'Running'). Althans, voor zover het betrokken proces bereid is in de achtergrond actief te zijn. In de praktijk is alleen deze reanimatiefunctie van belang.
*{{high2{{{tt{''fg ''@@color(darkorange)://[«job»]//@@}}}}}} -- Verplaatst de opgegeven (of huidige, als er niets is opgegeven) job naar de voorgrond.
*{{high2{{{tt{''jobs ''@@color(darkorange)://[«options»] [«job» ...]//@@}}}}}} -- Presenteert een lijst van bestaande jobs.
*{{high2{{{tt{''kill -9 ''@@color(darkorange)://«job»// ...@@}}}}}} -- Beëindigt de opgegeven jobs. In eerste instantie krijgen ze de status 'Killed', en vervolgens verdwijnen ze ook als job.
*{{high2{{{tt{''kill -18 ''@@color(darkorange)://«job»// ...@@}}}}}} -- Zet de opgegeven jobs weer in gang. Zelfde effect als het ''{{{bg}}}''-commando, maar omslachtiger geformuleerd.
*{{high2{{{tt{''kill -19 ''@@color(darkorange)://«job»// ...@@}}}}}} -- Zet de opgegeven jobs stil.
*{{high2{{{tt{''stty tostop''}}}}}} -- Zet achtergrondjobs stil zodra ze uitvoer naar de terminal proberen te sturen. Dit is geen bash- maar een Linux-commando.
*{{high2{{{tt{''wait ''@@color(darkorange)://[«id»]//@@}}}}}} -- Wacht op voltooiing van opgegeven proces (@@color(darkorange)://«id»//@@ = @@color(darkorange)://«pid»//@@) of job (@@color(darkorange)://«id»//@@ = @@color(darkorange)://«job»//@@). Handig om te weten is, dat de variabele ''{{{$!}}}'' het PID van het meest recente achtergrondproces bevat./%
%/
Een //@@color(darkorange):«job»@@// kan als volgt worden gespecificeerd:
*{{high2{{{tt{''%''@@color(darkorange)://«n»//@@}}}}}} -- Jobnummer. 
*{{high2{{{tt{''%''@@color(darkorange)://«s»//@@}}}}}} -- Het commando begint met de string @@color(darkorange)://«s»//@@.
*{{high2{{{tt{''%?''@@color(darkorange)://«s»//@@}}}}}} -- Het commando bevat de string @@color(darkorange)://«s»//@@.
*{{high2{{{tt{''%%''}}}}}} -- De huidige job.
*{{high2{{{tt{''%+''}}}}}} -- De huidige job.
*{{high2{{{tt{''%-''}}}}}} -- De vorige job.
Op Linux mag het procentteken bij de commando's ''{{{bg}}}'', ''{{{fg}}}'' en ''{{{jobs}}}'' worden weggelaten.
!Hello, world!
Simpel:
{{pblu pre{
(display "Hello, world!")
}}}
Recursief:
{{pblu pre{
(define (r x)
  (if (null? x)
    (newline)
    (begin
      (display (car x))
      (r (cdr x))))))

(r (string->list "Hello, world!"))
}}}/%

%/<<div [=[!Scheme Request for Implementation #49
Extreme toepassing van [[SRFI-49: Indentation-sensitive syntax|https://srfi.schemers.org/srfi-49/srfi-49.html]] in Scheme:
{{pblu pre{
define
  r
    x
  if
    null?
      x
    (newline)
    begin
      display
        car
          x
      r
        cdr
          x
}}}
Beheerste toepassing:
{{pblu pre{
define (r x)
  if (null? x)
    (newline)
    begin
      display (car x)
      r (cdr x)
}}}
Alleen lists van twee of meer elementen kunnen in deze inspringspringnotatie worden weergegeven. Vandaar dat de haakjes in ''{{hitt pblu z{(newline)}}}'' onvermijdelijk zijn en ook een lege list alleen maar met ''{{hitt pblu z{()}}}'' kan worden weergegeven.]=]>>/%

%/<<div [=[!Disjuncte gegevenstypen in Scheme
Onderstaande predicatentabel somt de disjuncties van Scheme's basistypen volgens de verschillende [[Revised Reports|Revised Report on the algorithmic language Scheme]] op:
|col1 bold1 capl |k
|!Type                   |!RS5RS &sect;&#x200a;3.2 | !R6RS &sect;&#x200a;11.1 | !R7RS &sect;&#x200a;3.2 |
|{{{boolean?}}}          | &times; | &times; | &times; |
|{{tt f2{bytevector?}}}  |         |         | &times; |
|{{{char?}}}             | &times; | &times; | &times; |
|{{tt f2{eof-object?}}}  |         |         | &times; |
|{{{null?}}}             |         | &times; | &times; |
|{{{number?}}}           | &times; | &times; | &times; |
|{{{pair?}}}             | &times; | &times; | &times; |
|{{{port?}}}             | &times; |         | &times; |
|{{{procedure?}}}        | &times; | &times; | &times; |
|{{{string?}}}           | &times; | &times; | &times; |
|{{{symbol?}}}           | &times; | &times; | &times; |
|{{{vector?}}}           | &times; | &times; | &times; |
|{{n f2{//record-type^^ a^^//}}} | |         | &times; |
|{{f2{//^^a^^//}}} {{z{Gecreëerd via {{tt t{define-record-type}}}}}}|c
In R5RS is {{tt t{null?}}} weggelaten, vermoedelijk wegens de overlap met {{tt t{list?}}}. Maar die overlap is er in de latere Scheme-versies net zo goed. Waarschijnlijk is de redenering achter de latere rapporten geweest, dat het fenomeen 'list' geen basistype is, maar een speciale constructie. Het predicaat {{tt t{port?}}} had in R5RS ook moeten ontbreken, want alleen {{tt t{input-port?}}} en {{tt t{output-port?}}} waren gedefinieerd. Pas bij R6RS is er voorzichting een {{tt t{port?}}} in de library {{tt t{(rnrs io port (6))}}} geplaatst en bij R7RS is {{tt t{port?}}} vervolgens naar de library {{tt t{(scheme base)}}} gehaald. In Chez Scheme 9.5 (een superset van R6RS) kunnen we alle typen die met de in deze tabel weergegeven predicaten zijn aangeduid wel als //onderling// disjunct beschouwen.

Alle gegevenstypen behalve //pair// zijn 'atomair'. In Chez Scheme is daar het predicaat {{tt t{atom?}}} voor gedefinieerd, gelijkwaardig aan ''{{pref hitt pblu z{(lambda (x) (not (pair? x)))}}}''. De lege list ''{{hitt pblu z{()}}}'', te verifiëren met {{tt t{null?}}}, is de enige list die geen //pair// is. Met het predicaat {{tt t{list?}}} kan worden beproefd of een gegeven een //proper list// is. Een //pair// hoeft niet per se een //proper list// te zijn. //Improper lists// zijn eveneens mogelijk, maar er is geen afzonderlijk predicaat om daarop te testen. Met ''{{pref hitt pblu z{(lambda (x) (and (pair? x) (not (list? x))))}}}''  kun je zoiets natuurlijk zelf maken. ''{{pref hitt pblu z{(list? '())}}}'' geeft {{tt t{#t}}}. Een lege list is dus een //proper list// (maar geen //pair//). 

Scheme kent ook subtypes. Zo zijn bijvoorbeeld //integer//, //rational//, //real// en //complex// subtypes van //number//.

Ik zal alle gegevenstypen waarvoor een gelijknamig predicaat bestaat (of naar mijn mening zou moeten bestaan) voortaan in kleinkapitalen schrijven wanneer ik ze zo ondubbelzinnig mogelijk wil benoemen. Dus {{sc{boolean}}}, {{sc{char}}}, {{sc{null}}}, {{sc{number}}}, {{sc{integer}}}, enzovoort. Dat betekent dat {{sc{list}}} een 'proper list' aanduidt en dat een 'improper list' beslist geen {{sc{list}}} is (maar wel een {{sc{pair}}}).]=]>>
Voorlopige conclusies m.b.t. pointers in de taal Scheme{{ref{&#x200a;[[[1]|##1]]}}} en de implementatie Chez Scheme{{ref{&#x200a;[[[2]|##2]]}}}:
* Gegevens van de volgende typen zijn //immediate values// oftewel -- wegens het gedrag van {{tt t{eq?}}} -- pseudosingletons:
** {{sc{boolean}}}: in Chez Scheme
** {{sc{char}}}: in Chez Scheme
** {{sc{null}}}: men spreekt ook wel van //null-pointer//
** {{sc{number}}}: kleine {{sc{integer}}}s in Chez Scheme
** lege {{sc{string}}}: in Chez Scheme
** {{sc{void}}}: bestaat niet in de standaard; in Chez Scheme ''{{hitt pblu z{(eq? (if #f 1) (void))}}}'' &rArr; {{tt t{#t}}}, waarbij ''{{hitt pblu{(void)}}}'' &rArr; {{tt t{#<void>}}}
* De overige waarden worden via een echte pointer bereikt:
** Ieder {{sc{symbol}}} is een echte singleton, d.w.z. iedere waarde komt maar één keer voor in het werkgeheugen.
** Voor andere waarden zijn er geen uniciteitsrestricties.{{ref{[[[3]|##3]]}}}
Interessant geval:
* {{_{Een {{sc{port}}} is een pointer naar een specifieke datastroom. Twee keer dezelfde soort port naar hetzelfde toegankelijk te maken object levert twee verschillende {{sc{port}}}-objecten op:
{{pre pblu{
(define s "Hallo!")
(define sip1 (open-string-input-port s))
(define sip2 (open-string-input-port s))
(eq? sip1 sip2)                           ;=> {{fred{#f}}}
}}}}}}
Zie ook:
* [[Journaal van 27 juli 2023|Journal 2023-07-27 (Thursday): Scheme]]
* [[(eq? eq? eq?)]]

----
|plain |k
|<html><a name="1">[1]</a></html>|<<tiddler Bibliografie##RnRS>> |
|<html><a name="2">[2]</a></html>|<<tiddler Bibliografie##CSUG>> |
|<html><a name="3">[3]</a></html>|Althans, voor zover ik dat dezer dagen heb nagetrokken. |
Opvallend in [[R7RS §6.1|(eq? eq? eq?)]] is deze specificatie:

''{{ml2em hitt pblu{(let ((n (+ 2 3))) (eq? n n))}}}'' &rArr; //unspecified//

Deze {{tt t{let}}}-uitdrukking is [[een equivalent|In de kelders van Scheme]] van:

|bare |k
|''{{ml2em pref hitt pblu{((lambda (n) (eq? n n)) (+ 2 3))}}}'' |--|in Python te schrijven als ''{{pref hitt{(lambda n: n is n) (2 + 3)}}}'' |
|                                                               |  |en in Ruby als ''{{pref hitt pred{lambda {|n| n.equal? n } [2 + 3]}}}'' |

Zie maar eens een Scheme-implementatie te vinden die een uitkomst anders dan {{tt t{#t}}} produceert.
[[Pass by value confusion in Scheme|https://stackoverflow.com/questions/53694761/pass-by-value-confusion-in-scheme#:~:text=So%2C%20what%20'call%20by%20value,binding%20with%20the%20same%20value.]]:
<<<
So, what 'call by value' means is that when you call a procedure with an argument which is a variable (a binding) what is passed to it is the value of the variable binding, not the binding itself. The procedure then creates a new binding with the same value. Two things follow from that:
* the original binding can not be altered by the procedure -- this follows because the procedure only has the value of it, not the binding itself, and bindings are not first-class so you can't cheat by passing the binding itself as the value;
* if the value is itself a mutable object (arrays & conses are example of objects which usually are mutable, numbers are examples of objects which are not) then the procedure can mutate that object.
<<<
Zie ook [[Evaluation strategy|https://en.wikipedia.org/wiki/Evaluation_strategy]].
<<eval [=[!!Metaoperator AND
{{sans z{U+0026 AMPERSAND}}}:
{{pre{
//datum//      $--> //simpleDatum// $| //composedDatum//    $// {{pref serif{7.1.2  External representations}}}

//expression// $--> $( //variable//                     $// {{pref serif{7.1.3  Expressions}}}
              $| //literal//                      $// {{pref serif{7.1.3  Expressions}}}
              $| //procedureCall//                $// {{pref serif{7.1.3  Expressions}}}
              $| //lambdaExpression//             $// {{pref serif{7.1.3  Expressions}}}
              $| //conditional//                  $// {{pref serif{7.1.3  Expressions}}}
              $| //assignment//                   $// {{pref serif{7.1.3  Expressions}}}
              $| //derivedExpression//            $// {{pref serif{7.1.3  Expressions}}}
              $| //macroUse//                     $// {{pref serif{7.1.3  Expressions}}}
              $| //macroBlock//                   $// {{pref serif{7.1.3  Expressions}}}
              $)
            {{w fred{^^&^^}}} //datum//                          $// {{serif{inclusion}}}
}}}/%

%/{{sans z{U+03D7 GREEK KAI SYMBOL}}}:
{{pre{
//datum//      $--> //simpleDatum// $| //composedDatum//    $// {{serif{7.1.2 External representations}}}

//expression// $--> $( //variable//                     $// {{pref serif{7.1.3  Expressions}}}
              $| //literal//                      $// {{pref serif{7.1.3  Expressions}}}
              $| //procedureCall//                $// {{pref serif{7.1.3  Expressions}}}
              $| //lambdaExpression//             $// {{pref serif{7.1.3  Expressions}}}
              $| //conditional//                  $// {{pref serif{7.1.3  Expressions}}}
              $| //assignment//                   $// {{pref serif{7.1.3  Expressions}}}
              $| //derivedExpression//            $// {{pref serif{7.1.3  Expressions}}}
              $| //macroUse//                     $// {{pref serif{7.1.3  Expressions}}}
              $| //macroBlock//                   $// {{pref serif{7.1.3  Expressions}}}
              $)
            {{w{{{stix fred up{&#X03D7;}}}}}} //datum//                          $// {{serif{inclusion}}}
}}}/%

%/{{_{
!!Metaoperator EXCEPT FOR (= BUT NOT = AND NOT)
{{sans t z{U+00AC NOT SIGN}}}:
{{pre{
//stringElement// $--> AnyCharacter $~! ''"'' $~! ''\\'' $| ''\\"'' $| ''\\\\''      $// {{pref serif{7.1.1  Lexical structure}}}
}}}/%

%/{{sans{Combination of {{z{U+0026 AMPERSAND}}} and {{z{U+00AC NOT SIGN}}}}}}:
{{pre{
//stringElement// $--> AnyCharacter {{w fred{^^&^^}}}$~! ''"'' {{w fred{^^&^^}}}$~! ''\\'' $| ''\\"'' $| ''\\\\''    $// {{pref serif{7.1.1  Lexical structure}}}
}}}/%

%/{{sans z{U+0AEC DOUBLE NOT SIGN}}}:
{{pre{
//stringElement// $--> AnyCharacter ''{{w{{{fred stix{^^&#x2aec;^^}}}}}}'' ''"'' ''{{w{{{fred stix{^^&#x2aec;^^}}}}}}'' ''\\'' $| ''\\"'' $| ''\\\\''      $// {{pref serif{7.1.1  Lexical structure}}}
}}}/%

%/{{sans z{U+23FE POWER SLEEP SYMBOL}}}:
{{pre{
//stringElement// $--> AnyCharacter {{w{{{stix fred{^^&#x23fe;^^}}}}}} ''"'' {{w{{{stix fred{^^&#x23fe;^^}}}}}} ''\\'' $| ''\\"'' $| ''\\\\''      $// {{pref serif{7.1.1  Lexical structure}}}
}}}}}}/%

%/{{_{
!!Priorities
|col1 thick1 |k
| !Priority | !Metaoperator                   | !Type  |
|         1 | {{hitt{$0}}}, {{hitt{$___}}}    |postfix |
|         2 | //implicit concatenation//      |infix   |
|         3 | {{hitt{$&!}}}, {{hitt{$&!$~!}}} |infix   |
|         4 | {{hitt{$|}}}                    |infix   |
|         5 | {{hitt{$-->}}}                  |infix   |
|         6 | //implicit rule transition//, {{hitt f2m{&para;}}}    |infix   |
}}}]=] f2m>>
<<eval [=[{{tt{
!!!Repetition
|plain pref |k
|list = "[", [expr, {",", expr}], "]";       |{{serif f2m{-- [[EBNF (ISO/IEC 14977)|https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form]]}}} |
|List ::= "[" (Expr ("," Expr)*)? "]"        |{{serif f2m{-- [[W3C Recommendation's EBNF (in XML 1.0 recommendation)|https://www.w3.org/TR/xml/]]}}} |
|list = "[" *1(expr *("," expr)) "]"         |{{serif f2m{-- [[ABNF (STD 68, RFC 5234)|https://en.wikipedia.org/wiki/Augmented_Backus%E2%80%93Naur_form]]}}} |
|list = "[", expr * ",", "]";                |{{serif f2m{-- Overhauled BNF (OBNF)}}} |
|//list// {{ww{&xrarr;}}} {{w hdn{{{stix h4 tight up1px{&lsquo;}}}}}}''[''{{w hdn{{{stix h4 tight up1px{&rsquo;}}}}}} [ //expr// { {{w hdn{{{stix h4 tight up1px{&lsquo;}}}}}}'',''{{w hdn{{{stix h4 tight up1px{&rsquo;}}}}}} //expr// } ] {{w hdn{{{stix h4 tight up1px{&lsquo;}}}}}}'']''{{w hdn{{{stix h4 tight up1px{&rsquo;}}}}}} |{{serif f2m{-- one of those extended BNFs}}} |
|//list// $--> ''[''//expr//'',''$___$0'']'' |{{serif f2m{-- ökonomische BNF (öBNF), codename 'Welsh Rarebit' (WR)}}} |
!!!Grouping
|plain pref |k
|if statement = "if ", expr, " then ", block, {" elseif ", expr, " then ", block}, [" else ", block], " end";   |{{serif f2m{-- EBNF (ISO/IEC 14977)}}} |
|IfStatement ::= "if " Expr " then " Block (" elseif " Expr " then " Block)* (" else " Block)? " end"           |{{serif f2m{-- W3C Recommendation's EBNF}}} |
|ifstatement ::= "if " expr " then " block *(" elseif " expr " then " block) *1(" else " block) " end"          |{{serif f2m{-- ABNF}}} |
|if statement = "if ", expr, " then ", block, (" elseif ", expr, " then ", block)*, (" else ", block)?, " end"; |{{serif f2m{-- OBNF}}} |
|//ifstatement// {{ww{&xrarr;}}} ''if'' //expr// ''then'' //block// { ''elseif'' //expr// ''then'' //block// } [ ''else'' //block// ] ''end'' |{{serif f2m{-- one of those extended BNFs}}} |
|//ifstatement// $--> ''if'' //expr// ''then'' //block// $(''elseif'' //expr// ''then'' //block//$) $___$0 $(''else'' //block//$)$0 ''end'' |{{serif f2m{-- Welsh Rarebit}}} |
/%

%/+++(~Journal20230920)!!!!![(Alternative spacing) &darr;|show][(Alternative spacing) &uarr;|hide]
|plain pref |k
|if statement = "if", expr, "then", block, {"elseif", expr, "then", block}, ["else", block], "end";   |{{serif f2m{-- EBNF (ISO/IEC 14977)}}} |
|IfStatement ::= "if" Expr "then" Block ("elseif" Expr "then" Block)* ("else" Block)? "end"           |{{serif f2m{-- W3C Recommendation's EBNF}}} |
|ifstatement ::= "if" expr "then" block *("elseif" expr "then" block) *1("else" block) "end"          |{{serif f2m{-- ABNF}}} |
|if statement = "if", expr, "then", block, ("elseif", expr, "then", block)*, ("else", block)?, "end"; |{{serif f2m{-- OBNF}}} |

===
!!!Empty string
//pair//&nbsp; &nbsp; $--> //left//$.//right//
//integer// $--> //sign//$0//digit//$.$___/%

%/
!!!Whitespace
{{pref{//ifstatement// $--> ''if'' //expr//'':''
               $.!$.!$.!$.!//block//
               $(''elif'' //expr//'':''
               $.!$.!$.!$.!//block//$) $___$0
               $(''else:''
               $.!$.!$.!$.!//block//$)$0}}}

{{pref{//ifstatement// $--> ''if'' //expr//'':''
                   //block//
               $(''elif'' //expr//'':''
                   //block//$) $___$0
               $(''else:''
                   //block//$)$0}}}/%

%/
!!!Syntax vs usage formulas
|plain |k
|//functioncall// $--> //identifier//''(''//expr//'',''$___$0'')'' |$// {{serif{syntax specification -- just about lexical forms -- öBNF}}} |
|''abs(''{{serif{//number//}}}'')'' |$// {{serif{usage specification -- about syntax with semantics (i.e. lexical forms and underlying values) -- WR Example Notation (WREN)}}}  |
|''abs(''{{serif{//number//}}}'')'' $=> {{serif{//number//}}} |$// {{serif{extended usage specification -- WREN}}}  |
}}}]=] f2d>>
<<eval [=[!!Een vraag
Deze week heb ik wat met enkele onalledaagse constructies in C geëxperimenteerd:
# {{pref tt{{{hitt{''number = (1, 2);''}}} {{stix{&rArr;}}} {{t{2}}}}}}
# {{pref tt{{{hitt{''number = 1, 2;''}}}   {{stix{&rArr;}}} {{t{1}}}}}}
# {{pref tt{{{hitt{''return (1, 2);''}}}   {{stix{&rArr;}}} {{t{2}}}}}}
# {{pref tt{{{hitt{''return 1, 2;''}}}     {{stix{&rArr;}}} {{t{2}}}}}}
De uitkomsten van de gevallen 1 en 3 verbaasden me niet erg, de logica van geval 4 kon ik op zich ook navoelen, maar het afwijkende gedrag van 2 prikkelde me vervolgens wel om te achterhalen hoe de grammatica van C tot juist deze interpretaties moet leiden. Dus waarom {{hitt{$(''anser = 1''$)'','' ''2;''}}} naast {{hitt{''return'' $(''1, 2''$)'';''}}} ?/%

%/
!!Het boek
Kernighan en Ritchie hebben in een tamelijk gezaghebbend boek de syntaxis van C helemaal uitgespeld.{{ref{[[[1]|##01]]}}} Ik geef de in dit kader belangrijkste formules hier weer in [[Welsh Rarebit]]-notatie. K&R's dubbele punt {{hitt6{//://}}} is daarmee vervangen door de productiepijl {{hitt6{$-->}}}{{ref{&#x200a;[[[2]|##02]]}}}, het subscript {{hitt6{~~//opt//~~}}} is vervangen door het superscript {{hitt6{$0}}} en de alternatieven zijn gescheiden door {{hitt6{$|}}}. De meeste identifiers van nonterminals zijn bovendien wat ingekort. In het rechterlid van de productieregels heb ik de op mijn zoekspoor gelegen nonterminals omkaderd:

{{ib ml2em pref tt suf{
//statement//       $--> //labeledStmt//
                 $| {{hws u2d d2d r{//expressionStmt//}}}
                 $| //compoundStmt//
                 $| //selectionStmt//
                 $| //iterationStmt//
                 $| {{hws u2d d2d r{//jumpStmt//}}}
//expressionStmt//  $--> {{hws u2d d2d r{//expression//}}}$0 '';''
//jumpStmt//        $--> ''goto'' //identifier// '';''
                 $| ''continue;''
                 $| ''break;''
                 $| ''return'' //expression//$0 '';''

//expression//      $--> {{hws u2d d2d r{//assignmentExpr//}}}
                 $| //expression// '','' {{hws u2d d2d r{//assignmentExpr//}}}
//assignmentExpr//  $--> {{hws u2d d2d r{//conditionalExpr//}}}
                 $| {{hws u2d d2d r{//unaryExpr//}}} //assignmentOperator// //assignmentExpr//
//conditionalExpr// $--> {{hws u2d d2d r{//logicalOrExpr//}}}
                 $| {{hws u2d d2d r{//logicalOrExpr//}}} ''?'' //expression// '':'' //conditionalExpr//
//unaryExpr//       $--> {{hws u2d d2d r{//postfixExpr//}}}
                 $| ''++'' //unaryExpr//
                 $| ''"""--"""'' //unaryExpr//
                 $| //unaryOperator// //castExpr//
                 $| ''sizeof'' //unaryExpr//
                 $| ''sizeof ('' //typeName// '')''
//postfixExpr//     $--> {{hws u2d d2d r{//primaryExpr//}}}
                 $| //postfixExpr// ''['' //expression// '']''
                 $| //postfixExpr// ''('' //argumentExprList//$0 '')''
                 $| //postfixExpr// ''.'' //identifier//
                 $| //postfixExpr// ''->'' //identifier//
                 $| //postfixExpr// ''++''
                 $| //postfixExpr// ''"""--""" ''
//primaryExpr//     $--> //identifier//
                 $| //constant//
                 $| //string//
                 $| ''('' //expression// '')''
}}}

Vanuit {{sans{//logicalOrExpr//}}} is een route te vinden die naar de hierboven uitgewerkte {{sans{//unaryExpr//}}} leidt. Ik laat het aan de lezer over dat zelf in het boek (of anders in bijvoorbeeld [[ISO/IEC 9899:TC3|https://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf]] van 7 september 2007) na te trekken./%
%/
!!Drie expedities
In onderstaande schema's is de grammaticale opbouw van drie van de vier statements uitgewerkt, waarbij de pijl {{ww tt{$=<!}}} wijst van een meer abstracte structuur aan de rechterkant naar een nadere concretisering daarvan aan de linkerkant. Het uiteindelijke doel is om tegen de pijlrichting in de meest abstracte nonterminal {{sans{//statement//}}} te bereiken. Waar de syntactische interpretatie van het statement zich het duidelijkst aftekent, is een vlaggetje geplaatst.

{{ib ml2em pref tt suf{
{{hitt{''number = (1, 2);''}}}
   $=<!  //identifier// //assignmentOperator// {{hitt{''(''}}}//integerConstant//{{hitt{'',''}}} //integerConstant//{{hitt{'');''}}}
   $=<!  //primaryExpr// //assignmentOperator// {{hitt{''(''}}}//constant//{{hitt{'',''}}} //constant//{{hitt{'');''}}}
   $=<!  //postfixExpr// //assignmentOperator// {{hitt{''(''}}}//primaryExpr//{{hitt{'',''}}} //primaryExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//postfixExpr//{{hitt{'',''}}} //postfixExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//unaryExpr//{{hitt{'',''}}} //unaryExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//castExpr//{{hitt{'',''}}} //castExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//multiplicativeExpr//{{hitt{'',''}}} //multiplicativeExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//additiveExpr//{{hitt{'',''}}} //additiveExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//shiftExpr//{{hitt{'',''}}} //shiftExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//relationalExpr//{{hitt{'',''}}} //relationalExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//equalityExpr//{{hitt{'',''}}} //equalityExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//AndExpr//{{hitt{'',''}}} //AndExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//exclusiveOrExpr//{{hitt{'',''}}} //exclusiveOrExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//inclusiveOrExpr//{{hitt{'',''}}} //inclusiveOrExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//logicalAndExpr//{{hitt{'',''}}} //logicalAndExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//logicalOrExpr//{{hitt{'',''}}} //logicalOrExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//conditionalExpr//{{hitt{'',''}}} //conditionalExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//assignmentExpr//{{hitt{'',''}}} //assignmentExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//expression//{{hitt{'',''}}} //assignmentExpr//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// {{hitt{''(''}}}//expression//{{hitt{'');''}}}
   $=<!  //unaryExpr// //assignmentOperator// //primaryExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //postfixExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //unaryExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //castExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //multiplicativeExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //additiveExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //shiftExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //relationalExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //equalityExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //AndExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //exclusiveOrExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //inclusiveOrExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //logicalAndExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //logicalOrExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //conditionalExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //assignmentExpr//{{hitt{'';''}}}  $//!
   $=<!  //assignmentExpr//{{hitt{'';''}}}
   $=<!  //expression//{{hitt{'';''}}}
   $=<!  //expressionStmt//
   $=<!  //statement//

{{hitt{''number = 1, 2;''}}}
   $=<!  //identifier// //assignmentOperator// //integerConstant//{{hitt{'',''}}} //integerConstant//{{hitt{'';''}}}
   $=<!  //primaryExpr// //assignmentOperator// //constant//{{hitt{'',''}}} //constant//{{hitt{'';''}}}
   $=<!  //postfixExpr// //assignmentOperator// //primaryExpr//{{hitt{'',''}}} //primaryExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //postfixExpr//{{hitt{'',''}}} //postfixExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //unaryExpr//{{hitt{'',''}}} //unaryExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //castExpr//{{hitt{'',''}}} //castExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //multiplicativeExpr//{{hitt{'',''}}} //multiplicativeExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //additiveExpr//{{hitt{'',''}}} //additiveExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //shiftExpr//{{hitt{'',''}}} //shiftExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //relationalExpr//{{hitt{'',''}}} //relationalExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //equalityExpr//{{hitt{'',''}}} //equalityExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //AndExpr//{{hitt{'',''}}} //AndExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //exclusiveOrExpr//{{hitt{'',''}}} //exclusiveOrExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //inclusiveOrExpr//{{hitt{'',''}}} //inclusiveOrExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //logicalAndExpr//{{hitt{'',''}}} //logicalAndExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //logicalOrExpr//{{hitt{'',''}}} //logicalOrExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //conditionalExpr//{{hitt{'',''}}} //conditionalExpr//{{hitt{'';''}}}
   $=<!  //unaryExpr// //assignmentOperator// //assignmentExpr//{{hitt{'',''}}} //assignmentExpr//{{hitt{'';''}}}
   $=<!  //assignmentExpr//{{hitt{'',''}}} //assignmentExpr//{{hitt{'';''}}}  $//!
   $=<!  //expression//{{hitt{'',''}}} //assignmentExpr//{{hitt{'';''}}}
   $=<!  //expression//{{hitt{'';''}}}
   $=<!  //expressionStmt//
   $=<!  //statement//

{{hitt{''return 1, 2;''}}}
   $=<!  {{hitt{''return''}}} //integerConstant//{{hitt{'',''}}} //integerConstant//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //constant//{{hitt{'',''}}} //constant//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //primaryExpr//{{hitt{'',''}}} //primaryExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //postfixExpr//{{hitt{'',''}}} //postfixExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //unaryExpr//{{hitt{'',''}}} //unaryExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //castExpr//{{hitt{'',''}}} //castExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //multiplicativeExpr//{{hitt{'',''}}} //multiplicativeExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //additiveExpr//{{hitt{'',''}}} //additiveExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //shiftExpr//{{hitt{'',''}}} //shiftExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //relationalExpr//{{hitt{'',''}}} //relationalExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //equalityExpr//{{hitt{'',''}}} //equalityExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //AndExpr//{{hitt{'',''}}} //AndExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //exclusiveOrExpr//{{hitt{'',''}}} //exclusiveOrExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //inclusiveOrExpr//{{hitt{'',''}}} //inclusiveOrExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //logicalAndExpr//{{hitt{'',''}}} //logicalAndExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //logicalOrExpr//{{hitt{'',''}}} //logicalOrExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //conditionalExpr//{{hitt{'',''}}} //conditionalExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //assignmentExpr//{{hitt{'',''}}} //assignmentExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //expression//{{hitt{'',''}}} //assignmentExpr//{{hitt{'';''}}}
   $=<!  {{hitt{''return''}}} //expression//{{hitt{'';''}}}  $//!
   $=<!  //jumpStmt//
   $=<!  //statement//
}}}
+++(~j20231108_Toegift)!![Toegift &darr;|show][Toegift &uarr;|hide]
Behalve de overbekende [['dangling else'|The dangling else]] zijn er wel meer syntactische dubbelzinnigheden aan te wijzen. Zoals deze:

{{lf ml2em pref tt suf{
{{hitt{''a"""+++"""b''}}}
   $=<!  //identifier//{{hitt{''"""+++"""''}}}//identifier//
   $=<!  //primaryExpr//{{hitt{''"""+++"""''}}}//primaryExpr//
   $=<!  //postfixExpr//{{hitt{''"""+++"""''}}}//postfixExpr//
   $=<!  {{fblu{//postfixExpr//}}}{{hitt{''"""+"""''}}}//unaryExpr//
   $=<!  //unaryExpr//{{hitt{''"""+"""''}}}//unaryExpr//
   $=<!  //castExpr//{{hitt{''"""+"""''}}}//castExpr//
   $=<!  //multiplicativeExpr//{{hitt{''"""+"""''}}}//multiplicativeExpr//
   $=<!  //additiveExpr//{{hitt{''"""+"""''}}}//multiplicativeExpr//
   $=<!  //additiveExpr//
   $=<!  $=<!  $=<!  $=<!  $=<!  $=<!  $=<!  $=<! 
   $=<!  //conditionalExpr//
   $=<!  //assignmentExpr//
   $=<!  //expression//
}}}{{lf vrl ml2em pl1em pref tt suf{
{{hitt{''a"""+++"""b''}}}
   $=<!  //identifier//{{hitt{''"""+++"""''}}}//identifier//
   $=<!  //primaryExpr//{{hitt{''"""+++"""''}}}//primaryExpr//
   $=<!  //postfixExpr//{{hitt{''"""+++"""''}}}//postfixExpr//
   $=<!  //unaryExpr//{{hitt{''"""+++"""''}}}//unaryExpr//
   $=<!  //unaryExpr//{{hitt{''"""+"""''}}}{{fblu{//unaryExpr//}}}
   $=<!  //castExpr//{{hitt{''"""+"""''}}}//castExpr//
   $=<!  //multiplicativeExpr//{{hitt{''"""+"""''}}}//multiplicativeExpr//
   $=<!  //additiveExpr//{{hitt{''"""+"""''}}}//multiplicativeExpr//
   $=<!  //additiveExpr//
   $=<!  $=<!  $=<!  $=<!  $=<!  $=<!  $=<!  $=<! 
   $=<!  //conditionalExpr//
   $=<!  //assignmentExpr//
   $=<!  //expression//
}}}{{block clear{}}}/%
%/
In het linker voorbeeld zijn de eerste twee plustekens inbegrepen in de blauwe nonterminal {{sans fblu{//postfixExpr//}}}, terwijl in het rechter voorbeeld de twee laatste plustekens in de blauwe nonterminal {{sans fblu{//unaryExpr//}}} zijn vervat. Van parsers verwacht ik dat ze de code van links naar rechts scannen en daarbij pogen zo veel mogelijk van het voorliggende materiaal op het hoogst mogelijke niveau syntactisch te duiden, zodat in dit geval de linker interpretatie {{pref hitt{$(''a++''$)'' + b''}}} ontstaat. Maar puur grammaticaal bekeken staat niets de rechter ontleding tot {{pref hitt{''a +'' $(''++ b''$)}}} in de weg. Een aardig experiment zou zijn het in deze ambiguïteit betrokken deel van de productieregels om te zetten naar retrograde productieregels oftewel beperkingen.{{ref{[[[2]|##02]]}}} En op basis daarvan vervolgens trachten een zinvolle interpretatievolgorde te bepalen. Het is niet mijn ambitie tot een complete C-parser te komen.{{ref{[[[3]|##03]]}}}

Ik meen me te herinneren dat Prata nog een andere dubbel&shy;zinnig&shy;heid aandroeg, maar die kan ik niet zo een-twee-drie terugvinden.{{ref{[[[4]|##04]]}}} Er staat me bij dat het iets met pointers of functies te maken had.

===
]=] f3m>>/%
%/
----
|plain |k
|<html><a name="01">[1]</a></html> |<<tiddler Bibliografie##K&R>> Ook in [[PDF-vorm|https://colorcomputerarchive.com/repo/Documents/Books/The%20C%20Programming%20Language%20(Kernighan%20Ritchie).pdf]] te vinden. Van de [[gepubliceerde errata|https://gist.github.com/ttilley/1159475]] heb ik kennisgenomen. |
|<html><a name="2">[2]</a></html> |<<eval [=[Wanneer er interpretatieregels worden aangeboden van het type {{pref hi d2p r sans{//«lvalue»// //«connector»// //«rvalue»//}}} waarbij niet duidelijk is vermeld wat de functie van die connector is, zie ik drie mogelijkheden:<br>/%|
%/&nbsp;''&bull;'' {{hitt6{//x// $--> //a// $| //b//}}} <<eval "\$==?+" fblu>\> ''X'' {{stix z up1px{&supe;}}} ''A'' {{stix up1px{&cup;}}} ''B'' -- dit is een productieregel, overal waar //x// staat kan op z'n minst //a// of //b// worden ingevuld (zo werken BNF en de extensies ervan);<br>/%|
%/&nbsp;''&bull;'' {{hitt6{//x// $--< //a// $| //b//}}} <<eval "\$==?+" fblu>\> ''X'' {{stix z up1px{&sube;}}} ''A'' {{stix up1px{&cup;}}} ''B'' -- dit is een beperking, overal waar //x// staat mag niets anders dan //a// of //b// worden ingevuld, zonder garantie dat elke //a// of //b// wèl voldoet;<br>/%|
%/&nbsp;''&bull;'' {{hitt6{//x// $--? //a// $| //b//}}} <<eval "\$==?+" fblu>\> ''X'' = ''A'' {{stix up1px{&cup;}}} ''B'' -- deze combinatie van de vorige twee typen regels is een volledige definitie van //x//.<br>/%|
%/''X'', ''A'' en ''B'' zijn de verzamelingen van respectievelijk alle geldige //x//'en, //a//'s en //b//'s. ]=] f3m>> |
|<html><a name="03">[3]</a></html> |Zoals Mark Hjelm in 1992 of iets eerder wèl heeft ondernomen, getuige zijn vragen (met mijn cursiveringen):<br>/%|
%/{{ib ml2em z{I have a parser, written using //Yacc and Lex//, for ANSI C. The grammar is taken pretty much verbatim from the standard. The scanner uses the symbol table to decide whether to return "identifier" or "typedef name" as the token type for an identifier. How do I KNOW that there are no situations which, due to //parser lookahead//, would cause the scanner to return an incorrect token type for an identifier (i.e.  return "identifier", even though the identifier was just/will be made into a "typedef name")?  Is there a general answer to this question for other parsing strategies (possibly with //other amounts of lookahead//) and other grammars (languages)?}}}<br>waarop Jim Roskind reageert met een [[interessant betoog|https://pdos.csail.mit.edu/archive/l/c/roskind.html]]. |
|<html><a name="04">[4]</a></html> |<<tiddler Bibliografie##Prata>> |
Syntactisch juist, maar semantisch beslist niet, is het volgende uit de grammatica van C afgeleide statement:

{{lf ml2em pref tt{
                 {{u2s d2s rr{//statement//}}}
                      &darr;
               {{u2s d2s rr{//expressionStmt//}}}
                      &darr;
                  {{u2s d2s rr{__//expr//__ ''{{hitt{;}}}''}}}
                      &darr;
              {{u2s d2s rr{//assignmentExpr//}}} ''{{hitt{;}}}''
                      &darr;
{{u2s d2s rr{__//unaryExpr//__ __//assignmentOperator//__ __//assignmentExpr//__}}} ''{{hitt{;}}}''
       &darr;              &darr;            &darr;
{{u2s d2s rr{''{{hitt{++}}}'' __//unaryExpr//__}}}       ''{{hitt{=}}}''    {{u2s d2s rr{//conditionalExpr//}}} ''{{hitt{;}}}''
          &darr;                        &darr;
''{{hitt{++}}}'' {{u2s d2s rr{//postfixExpr//}}}     ''{{hitt{=}}}''    {{u2s d2s rr{      ...      }}} ''{{hitt{;}}}''
          &darr;                        &darr;
''{{hitt{++}}}'' {{u2s d2s rr{__//postfixExpr//__ ''{{hitt{++}}}''}}} ''{{hitt{=}}}''      {{u2s d2s rr{//primaryExpr//}}}   ''{{hitt{;}}}''
          &darr;                        &darr;
''{{hitt{++}}}'' {{u2s d2s rr{//primaryExpr//}}} ''{{hitt{++}}}'' ''{{hitt{=}}}''        {{u2s d2s rr{//constant//}}}    ''{{hitt{;}}}''
          &darr;                        &darr;
''{{hitt{++}}}''  {{u2s d2s rr{//identifier//}}} ''{{hitt{++}}}'' ''{{hitt{=}}}''    {{u2s d2s rr{//integerConstant//}}} ''{{hitt{;}}}''
          &darr;                        &darr;
''{{hitt{++}}}''    ''{{hitt{answer}}}'' {{serif{ &#x200a;}}}  ''{{hitt{++}}}'' ''{{hitt{=}}}''  {{serif{ &#x200a;}}}        ''{{hitt{42}}}''        ''{{hitt{;}}}''
}}}<<eval [=[{{lf vrl ml2em pl2em pref tt z{{{z suf{

{{u2s d2s rr{//conditionalExpr//}}}
$--> {{u2s d2s rr{//logicalOrExpr//}}}
   $--> {{u2s d2s rr{//logicalAndExpr//}}}
      $--> {{u2s d2s rr{//inclusiveOrExpr//}}}
         $--> {{u2s d2s rr{//exclusiveOrExpr//}}}
            $--> {{u2s d2s rr{//AndExpr//}}}
               $--> {{u2s d2s rr{//equalityExpr//}}}
                  $--> {{u2s d2s rr{//relationalExpr//}}}
                     $--> {{u2s d2s rr{//shiftExpr//}}}
                        $--> {{u2s d2s rr{//additiveExpr//}}}
                           $--> {{u2s d2s rr{//multiplicativeExpr//}}}
                              $--> {{u2s d2s rr{//castExpr//}}}
                                 $--> {{u2s d2s rr{//unaryExpr//}}}
                                    $--> {{u2s d2s rr{//postfixExpr//}}}
                                       $--> {{u2s d2s rr{//primaryExpr//}}}

}}}}}}]=]>>{{block clear{}}}
De pre- en postfixoperatoren ''{{hitt{++}}}'' vereisen een identifier als operand, en evenzo vereisen alle {{sans t{//assignmentOperator//}}}s een identifier als lvalue. In het hierboven via productie&shy;regels verkregen statement wordt geprobeerd de waarde {{tt t{42}}} toe te kennen aan een waarde verkegen door een ophoging van de variabele ''{{hitt{answer}}}''. Ook op zichzelf is de {{sans {//unaryExpr//}}} ''{{pref hitt{++answer++}}}'' niet uitvoerbaar, omdat de eerst geëvalueerde {{sans t{//postfixExpr//}}} ''{{pref hitt{answer++}}}'' de waarde van ''{{hitt{answer}}}'' vóór de ophoging zou opleveren, waar de prefixoperator niets mee kan aanvangen. De compiler zal al gauw in de gaten hebben dat deze constructie niet deugt, dus tot een runtime error zal het nooit komen.
XXXXXXXXXX | -- normal
{{widenq{XXXXXXXXXX}}} | -- widenq
{{ls{XXXXXXXXXX}}} | -- ls
{{widenh{XXXXXXXXXX}}} | -- widenh
{{widen1{XXXXXXXXXX}}} | -- widen1

{{pre pred{pred}}} {{pre pora{pora}}} {{pre pyel{pyel}}} {{pre pbei{pbei}}} {{pre pgre{pgre}}} {{pre poli{poli}}} {{pre pblu{pblu}}} {{pre ppur{ppur}}}

{{pre5{b2w&nbsp;}}} {{pre5{b2w&nbsp;}}} {{pre5{b2w&nbsp;}}} {{pre5{b2w&nbsp;}}} {{pre5{b2w&nbsp;}}} {{pre5{b2w&nbsp;}}} {{pre5{b2w&nbsp;}}} {{pre5{b2w&nbsp;}}}

{{pre6{b3w&nbsp;}}} {{pre6{b3w&nbsp;}}} {{pre6{b3w&nbsp;}}} {{pre6{b3w&nbsp;}}} {{pre6{b3w&nbsp;}}} {{pre6{b3w&nbsp;}}} {{pre6{b3w&nbsp;}}} {{pre6{b3w&nbsp;}}}

{{pre2{b2p&nbsp;}}} {{pre2{b2p&nbsp;}}} {{pre2{b2p&nbsp;}}} {{pre2{b2p&nbsp;}}} {{pre2{b2p&nbsp;}}} {{pre2{b2p&nbsp;}}} {{pre2{b2p&nbsp;}}} {{pre2{b2p&nbsp;}}}

{{pre3{b3p&nbsp;}}} {{pre3{b3p&nbsp;}}} {{pre3{b3p&nbsp;}}} {{pre3{b3p&nbsp;}}} {{pre3{b3p&nbsp;}}} {{pre3{b3p&nbsp;}}} {{pre3{b3p&nbsp;}}} {{pre3{b3p&nbsp;}}}

{{pre4{b1w&nbsp;}}} {{pre4{b1w&nbsp;}}} {{pre4{b1w&nbsp;}}} {{pre4{b1w&nbsp;}}} {{pre4{b1w&nbsp;}}} {{pre4{b1w&nbsp;}}} {{pre4{b1w&nbsp;}}} {{pre4{b1w&nbsp;}}}

{{pre1{b1p&nbsp;}}} {{pre1{b1p&nbsp;}}} {{pre1{b1p&nbsp;}}} {{pre1{b1p&nbsp;}}} {{pre1{b1p&nbsp;}}} {{pre1{b1p&nbsp;}}} {{pre1{b1p&nbsp;}}} {{pre1{b1p&nbsp;}}}
''{{up1px sans{<<showPopup tiddler:[[} Iteratie & recursie]] label: "Bundel ↘">>}}}''
!!!No-brainer
{{lf pre w15pct{{{_{
fac = 1
i   = 1

{{f2m{//# iteration//}}}
while i <= 5:
    fac *= i
    i   += 1

print(fac)



}}}}}}{{ml1em lf pre{{{_{
fac = 1
i   = 1

def f5():
    global fac, i
    if i <= 5:
        fac *= i
        i   += 1
        f5()  {{f2m{//# tail recursion//}}}

f5()
print(fac)
}}}}}}{{ml1em lf pre{{{_{
def f(n, fac=1, i=1):
    if i > n: return fac
    return f(n, fac*i, i+1)  {{f2m{//# tail recursion//}}}

print(f(5))







}}}}}}{{clear block{}}}<<div 

[=[!!!The art of programming
{{ib pre{{{_{
def fac(n):
    if n <= 1: return 1
    return n * fac(n-1)  {{f2m{//# recursion, but not a tail recursion!//}}}

print(fac(5))}}}}}}
]=]>>
|bare xcol1 |k
|>|{{h4 sans{//Infix://}}} |
|&nbsp; &nbsp; |''{{pref hitt{1 + 2 * 3 + 4                 }}}''|Klassiek met infix-operatoren, zoals op school geleerd |
|              |''{{pref hitt{1 + (2 * 3) + 4               }}}''|In Rebol-dialecten zijn haakjes nodig om te voorkomen dat de operaties van links naar rechts worden uitgevoerd |
|              |''{{pref hitt{1.add(2.multiply(3)).add(4)   }}}''|Objectgeoriënteerd met methoden, ook hier haakjes nodig om de juiste volgorde af te dwingen |
|              |''{{pref hitt{1.add(2.multiply 3).add 4     }}}''|Idem met wat minder haakjes, zoals Ruby toestaat{{ref{&#x200a;[[[1]|##01]]}}} |
|              |''{{pref hitt{(1.add 2.multiply 3).add 4    }}}''|En zo kan het in Ruby ook nog{{ref{&#x200a;[[[1]|##01]]}}} |
|>|{{h4 sans{//Prefix://}}} |
|              |''{{pref hitt{add(add(2, multiply(3, 4), 5) }}}''|Klassiek met functies, zoals bij programmeren in ALGOL 60 geleerd |
|              |''{{pref hitt{(+ (+ 1 (* 2 3)) 4)           }}}''|Eveneens met functies, zoals in Lisp-dialecten |
|              |''{{pref hitt{(add (add 1 (multiply 2 3)) 4)}}}''|Idem met wat langere functienamen als alias voor ''{{{+}}}'' en ''{{{*}}}'' |
|              |''{{pref hitt{add add 1 multiply 2 3 4      }}}''|Functie-aanroepen zonder enige haakjes (een pure vorm van Poolse notatie dus), zoals in Rebol-dialecten |
|>|{{h4 sans{//Postfix://}}} |
|              |''{{pref hitt{1 2 3 * + 4 +                 }}}''|Omgekeerde Poolse notatie (d.w.z. met postfix-operatoren en zonder haakjes), zoals in Forth |
|              |''{{pref hitt{1 2 3 multiply add 4 add      }}}''|Idem met aliassen voor ''{{{*}}}'' en ''{{{+}}}'' |

----
<html><a name="01">[1]</a></html>&nbsp; Extra spatiëring is daarbij geoorloofd: ''{{pref hitt{1 .add (2 .multiply 3) .add 4}}}'' respectievelijk ''{{pref hitt{(1 .add 2 .multiply 3) .add 4}}}''. In Scala kun je dan (//moet// je dan, zelfs) de puntjes weglaten.
{{s suf{
{{lf{

{{up{''&rarr;''}}}
}}}{{lf{

{{up{''Serif''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXX{{ref{X}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf vrl plqem sans{

{{up{''Sans''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXX{{ref{X}}}
}}}{{lf vrl plqem saco{

{{up{''~SaCo''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXX{{ref{X}}}
}}}{{lf vrl plqem tt{

{{up{''Mono''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXX{{ref{X}}}
}}}{{lf vrl pl1em prhem{
| !Serif | !Sans | !~SaCo | !Mono |
| XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXX{{ref{X}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX | {{sans{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} | {{saco{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} | {{tt{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} |
}}}{{lf vrl pl1em prhem{
|sans|k
| !Sans |
| {{sans{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} |
}}}{{ib vrl pl1em prhem sans{
| !Sans |
| {{sans{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} |
}}}}}}
5 december 2024
<<tiddler ToggleLeftSidebar>>
<<tiddler RefreshPageDisplay with: {{config.options.chkFixLeftSidebar ? "&#x2b0d;" : "&#x1f793;";}} {{(config.options.chkFixLeftSidebar ? "un" : "") + "fix both sidebars";}}>>
<script>
  var co = config.options;
  var mm = document.getElementById('mainMenu');

  co.chkFixLeftSidebar = !co.chkFixLeftSidebar;

  mm.style.position = co.chkFixLeftSidebar ? 'absolute' : 'fixed';
  mm.style.bottom   = co.chkFixLeftSidebar ? ''         : '0';
</script>
!!!!!Lettertype {{n{(font-family, font-style, font-weight)}}} 
*{{_{~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //IBM Plex Serif// (''Bold, //~BoldItalic//'') -- impliciet
@@font-family:IBM Plex Serif, monospace;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //IBM Plex Serif// (''Bold, //~BoldItalic//'') -- expliciet@@
{{t{~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //Text// -- impliciet (class="t")}}}
@@font-family:IBM Plex Serif, monospace;font-weight:500;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //Text// -- expliciet@@}}}
*{{_{{{sans{~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //IBM Plex Sans// (''Bold, //~BoldItalic//'') -- impliciet (class="sans")}}}
@@font-family:IBM Plex Sans, monospace;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //IBM Plex Sans// (''Bold, //~BoldItalic//'') -- expliciet@@
{{sans t{~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //Text// -- impliciet (class="sans t")}}}
@@font-family:IBM Plex Sans, monospace;font-weight:500;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //Text// -- expliciet@@}}}
*{{_{{{saco{~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //IBM Plex Sans Condensed// (''Bold, //~BoldItalic//'') -- impliciet (class="saco")}}}
@@font-family:IBM Plex Sans Condensed, monospace;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //IBM Plex Sans Condensed// (''Bold, //~BoldItalic//'') -- expliciet@@
{{saco t{~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //Text// -- impliciet (class="saco t")}}}
@@font-family:IBM Plex Sans Condensed, monospace;font-weight:500;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //Text// -- expliciet@@}}}
*{{_{{{tt{~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //IBM Plex Mono// (''Bold, //~BoldItalic//'') -- impliciet (class="tt")}}}
@@font-family:IBM Plex Mono, serif;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //IBM Plex Mono// (''Bold, //~BoldItalic//'') -- expliciet@@
{{tt t{~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //Text// -- impliciet (class="tt t")}}}
@@font-family:IBM Plex Mono, serif;font-weight:500;~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 -- //Text// -- expliciet@@}}}/%

%/
!!!!!Letterhoogte {{n{(font-size)}}}
*ZZZZZ{{sans{ZZZZZ}}}{{saco{ZZZZZ}}}{{sans{ZZZZZ}}}{{{ZZZZZ}}} -- //bovenkast//
*zzzzz{{sans{zzzzz}}}{{saco{zzzzz}}}{{sans{zzzzz}}}{{{zzzzz}}} -- //onderkast///%

%/
!!!!!Regelafstand {{n{(line-height)}}}
{{lf{

{{up{''&rarr;''}}}
}}}{{lf{

{{up{''Serif''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXX{{ref{X}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
}}}{{lf vrl plqem sans{

{{up serif{''Sans''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXX{{ref{X}}}
}}}{{lf vrl plqem sans{

{{up{''Sans''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXX{{ref{X}}}
}}}{{lf vrl plqem saco{

{{up{''~SaCo''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXX{{ref{X}}}
}}}{{lf vrl plqem tt{

{{up{''Mono''}}}
XXXXX
{{u1 d1{XXXXX
XXXXX}}}
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
XXXX{{ref{X}}}
}}}{{lf vrl pl1em prhem{
| !Serif | !Sans | !~SaCo | !Mono |
| XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXX{{ref{X}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX | {{sans{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} | {{saco{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} | {{tt{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} |
}}}{{lf vrl pl1em prhem{
|sans|k
| !Sans |
| {{sans{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} |
}}}{{ib vrl pl1em prhem sans{
| !Sans |
| {{sans{XXXXX<br>{{u1 d1{XXXXX}}}<br>{{u1 d1{XXXXX}}}<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXXX<br>XXXX{{ref{X}}}}}} |
}}}

!!!{{lift{Kleinkapitalen}}}
T{{sc{he quick brown}}}e fox jumps over the lazy dog, 1234567890!
{{sans{T{{sc{he quick brown}}}e fox jumps over the lazy dog, 1234567890!}}}
{{saco{T{{sc{he quick brown}}}e fox jumps over the lazy dog, 1234567890!}}}
<script show>
  return "&rArr; " + document.location.toString();
</script>
Locking is een omvangrijker onderwerp dan me lief is. Op deze plaats houd ik het bij een paar contouren van het fenomeen. De omvang van een lock kan in ~DB2 variëren (zie [[hier|Hoe zat het ook alweer met DB2?]] voor de verschillende eenheden):
*Row
*Page (in simple tablespace / segmented tablespace / partitioned tablespace)
*Table
*Tablespace  (simple ~ / segmented ~ / all partitions of partitioned ~)/%
%/
~DB2 onderscheidt drie lockcategorieën: ''{{{S}}}'' = share, ''{{{U}}}'' = update, en ''{{{X}}}'' = exclusive. De laatste categorie is niet van toepassing op isolatieniveau ''{{{UC}}}''. De vier isolatieniveaus zijn (tekst grotendeels gekopieerd van [[DBA to DBA|http://www.dbatodba.com/db2/how-to-do/what-are-the-db2-isolation-levels]]):/%
%/
#''{{high1{{{{UR}}}}}} - Uncommitted Read'' (aka //Dirty Read//)
**For read only queries, no record locking
**Will see uncommitted changes by other transactions
**Good for accessing read only tables
**Statements in ''{{{UR}}}'' which modify data are upgraded internally to ''{{{CS}}}''/%
%/
#''{{high1{{{{CS}}}}}} - Cursor Stability''
**Default isolation level (volgens andere bronnen is ''{{{RR}}}'' de default)
**Locks and unlocks each row, 1 at a time (never has 2 locks at once)
**Guaranteed to only return data which was committed at the time of the read/%
%/
#''{{high1{{{{RS}}}}}} - Read Stability''
**Will keep all qualifying rows locked until the transaction is completed
**Does release locks on rows that do not satisfy query predicates
**Use for result set stability or when future actions on returned rows may be taken/%
%/
#''{{high1{{{{RR}}}}}} - Repeatable Read''
**Default? (zie ''{{{CS}}}'')
**Locks the table within a unit of work. An application can retrieve and operate on rows in the table as many times as needed. However, the entire table is locked, not just the rows that are retrieved. Until the unit of work completes, no other application can update, delete, or insert a row that would affect the table./%
%/
Binnen het [[IBM Knowledge Center|http://www-01.ibm.com/support/knowledgecenter/SSEPEK/db2z_prodhome.html?lang=nl]] is meer over dit onderwerp te vinden. Vlak ook de documentatie onder [[Linux-UNIX-Windows (LUW)|http://www-01.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.admin.perf.doc/doc/c0004121.html]] niet uit. Zo her en der komt die wat duidelijker bij me over dan het z/~OS-equivalent.

Wat je hier uiteindelijk als vraagsteller aan hebt, is dit. Met isolatieniveau ''{{{UR}}}'' loop je minder kans last te hebben van locking door andere processen of zelf een stoorfactor te zijn. Je moet dan voor lief nemen dat het resultaat minder betrouwbaar is. In een query stel je het //isolation level// aldus expliciet in:
<html><pre>
select ... <b>with </b><i>{</i><b>UR</b><i>|</i><b>CS</b><i>|</i><b>RS</b><i>|</i><b>RR</b><i>}</i>
</pre></html>
@@position:absolute;top:200px;left:74px;{{h3{<<tiddler ToggleSliders with: "mainMenu" "&darr;&darr;" "&uarr;&uarr;" "Expand (&darr;&darr;) or collapse (&uarr;&uarr;) all sliders in main menu">>}}}@@<<tiddler SiteLogo>>
++++(~TwmmIntroductie)!![Introductie &darr;|show][Introductie &uarr;|hide]
[[Welkom|Hoe verder gekomen, hoe langer te gaan]]
/%[[Nieuws]]
[[Podia]]
%/[[Tags]]
[[Reageren?]]
{{button{<<tiddler BreadcrumbsCommand with: "Kruimelspoor ↘" "Toon kruimelspoor">>}}}
===/%

%/++++(~TwmmHoeZatDat)!![Hoe zat dat met...? &darr;|show][Hoe zat dat met...? &uarr;|hide]
[[DB2|Hoe zat het ook alweer met DB2?]]
[[Normaalvormen|Hoe zat het ook alweer met normaalvormen?]]
[[Scheme (← Lisp)|Hoe zat het ook alweer met Scheme?]]
===/%

%/++++(~TwmmProgrammeren)!![Programmeren &darr;|show][Programmeren &uarr;|hide]
<<showPopup tiddler:[[} Iteratie & recursie]] label: "Iteratie & recursie ↘">>
<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Iteratiemechanismen ↘">>
<<showPopup tiddler:[[} Zichtbaarheid van Python-variabelen]] label: "Python-scopes ↘">>
<<showPopup tiddler:[[} Reguliere expressies]] label: "Reguliere expressies ↘">>
<<showPopup tiddler:[[} Stapelingen]] label: "Stapelingen ↘">>
===/%

++++(~Twmm3)!![Gebruik &darr;|show][Gebruik &uarr;|hide]
[[De wakkere wikinaut]]
{{f2 s{//(gebruiksaanwijzingen hier)//}}}
===/%

%/+++(~Twmm4)!![Onderhoud &darr;|show][Onderhoud &uarr;|hide]
/%[[Style|Style guide]]
%/[[Markup|TiddlyWiki Markup Language]]
<<showPopup tiddler:[[} Showrooms]] label: "Showrooms ↘">>
{{f2 s{//(onderhoudsinstructies hier)//}}}
[[Laatste wijzigingsdatum|Last modification date]]
===

~~Based on~~
^^[[TiddlyWiki]] <<version>>^^
Vanuit een dictionary ''//{{{D}}}//'' kun je met @@text-decoration:line-through;text-decoration-color:red;text-decoration-thickness:2px;{{hitt z{//D//.proxy}}}@@ @@text-decoration:line-through;text-decoration-color:red;text-decoration-thickness:2px;{{hitt z{//D//.mapping}}}@@ {{hitt z{//D//.items().mapping}}}, {{hitt z{//D//.keys().mapping}}}, {{hitt z{//D//.values().mapping}}} of {{hitt z{types.MappingProxyType(//D//)}}} een read-only view op {{tt t{//D//}}} van het type @@text-decoration:line-through;text-decoration-color:red;text-decoration-thickness:2px;''{{tt{dictproxy}}}''@@ ''{{tt{mappingproxy}}}'' verkrijgen. De naams&shy;wijziging van {{tt t{dictproxy}}} naar {{tt t{mappingproxy}}} in Python 3.3 duidt erop dat Python ook andere mapping&shy;variëteiten dan {{tt t{dict}}} kent. //Plus ultra&#x200a;!//... andere werelden beginnen thans door te schemeren. Ik neem tenminste aan dat het niet om subclasses van {{tt t{dict}}} gaat.{{ref{[[[1]|##1]]}}} Later maar eens wat verkennings&shy;tochten ondernemen, misschien. Nu even concentreren op het eigenlijke onderwerp.

Het suffix //-proxy// geeft de essentie aan: het gaat om een indirect aanspreekpunt voor een achterliggend object. Wanneer de inhoud van dat object verandert, wordt dit onmiddellijk zichtbaar in de proxy. Het bijzondere van de {{tt t{mappingproxy}}} is, dat deze niet kan worden gebruikt om de achterliggende mapping te muteren, alleen kijken is toegestaan. Een typische toepassing ervan is te vinden in het {{tt t{"""__dict__"""}}}-attribuut van objecten.
{{pre{
class C: pass
"""print(C.__dict__.__class__)      """{{fgre{#=> prints <class 'mappingproxy'>}}}
"""print(C().__dict__.__class__)    """{{fgre{#=> prints <class 'dict'>}}}
}}}/%
%/Class-attributen mogen dus niet via {{tt t{"""__dict__"""}}} worden gewijzigd, instance-attributen wel. Enkele andere bijzonder&shy;heden zijn genoemd in [[Provider à la Python-iterator]].

----
|plain |k
|<html><a name="1">[1]</a></html>|In de standard library van 3.11:|
| |{{tt z{collections.Counter<br>collections.defaultdict<br>collections.OrderedDict<br>enum._EnumDict<br>idlelib.config.ConfigChanges<br>idlelib.pyparse.ParseMap<br>urllib.parse._Quoter}}} |
/***
|Name|MatchTagsPlugin|
|Source|http://www.TiddlyTools.com/#MatchTagsPlugin|
|Documentation|http://www.TiddlyTools.com/#MatchTagsPluginInfo|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|'tag matching' with full boolean expressions (AND, OR, NOT, and nested parentheses)|
!!!!!Documentation
> see [[MatchTagsPluginInfo]]
!!!!!Revisions
<<<
2008.09.04 [2.0.0] added "report" and "panel" options to generate formatted results and store in a tiddler.  Also, added config.macros.matchTags.formatList(place,fmt,sep) API to return formatted output for use with other plugins/scripts
| please see [[MatchTagsPluginInfo]] for additional revision details |
2008.02.28 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.MatchTagsPlugin= {major: 2, minor: 0, revision: 0, date: new Date(2008,9,4)};

// store.getMatchingTiddlers() processes boolean expressions for tag matching
//    sortfield (optional) sets sort order for tiddlers - default=title
//    tiddlers (optional) use alternative set of tiddlers (instead of current store)
TiddlyWiki.prototype.getMatchingTiddlers = function(tagexpr,sortfield,tiddlers) {

	var debug=config.options.chkDebug; // abbreviation
	var cmm=config.macros.matchTags; // abbreviation
	var r=[]; // results are an array of tiddlers
	var tids=tiddlers||store.getTiddlers(sortfield||"title");
	if (tiddlers && sortfield) store.sortTiddlers(tids,sortfield);
	if (debug) displayMessage(cmm.msg1.format([tids.length]));

	// try simple lookup to quickly find single tags or tags that
	// contain boolean operators as literals, e.g. "foo and bar"
	for (var t=0; t<tids.length; t++)
		if (tids[t].isTagged(tagexpr)) r.pushUnique(tids[t]);
	if (r.length) {
		if (debug) displayMessage(cmm.msg4.format([r.length,tagexpr]));
		return r;
	}
	
	// convert expression into javascript code with regexp tests,
	// so that "tag1 AND ( tag2 OR NOT tag3 )" becomes
	// "/\~tag1\~/.test(...) && ( /\~tag2\~/.test(...) || ! /\~tag3\~/.test(...) )"

	// normalize whitespace, tokenize operators, delimit with "~"
	var c=tagexpr.trim(); // remove leading/trailing spaces
	c = c.replace(/\s+/ig," "); // reduce multiple spaces to single spaces
	c = c.replace(/\(\s?/ig,"~(~"); // open parens
	c = c.replace(/\s?\)/ig,"~)~"); // close parens
	c = c.replace(/(\s|~)?&&(\s|~)?/ig,"~&&~"); // &&
	c = c.replace(/(\s|~)AND(\s|~)/ig,"~&&~"); // AND
	c = c.replace(/(\s|~)?\|\|(\s|~)?/ig,"~||~"); // ||
	c = c.replace(/(\s|~)OR(\s|~)/ig,"~||~"); // OR
	c = c.replace(/(\s|~)?!(\s|~)?/ig,"~!~"); // !
	c = c.replace(/(^|~|\s)NOT(\s|~)/ig,"~!~"); // NOT
	c = c.replace(/(^|~|\s)NOT~\(/ig,"~!~("); // NOT(
	// change tag terms to regexp tests
	var terms=c.split("~"); for (var i=0; i<terms.length; i++) { var t=terms[i];
		if (/(&&)|(\|\|)|[!\(\)]/.test(t) || t=="") continue; // skip operators/parens/spaces
		if (t==config.macros.matchTags.untaggedKeyword)
			terms[i]="tiddlertags=='~~'"; // 'untagged' tiddlers
		else
			terms[i]="/\\~"+t+"\\~/.test(tiddlertags)";
	}
	c=terms.join(" ");
	if (debug) { displayMessage(cmm.msg2.format([tagexpr])); displayMessage(cmm.msg3.format([c])); }

	// scan tiddlers for matches
	for (var t=0; t<tids.length; t++) {
	 	// assemble tags from tiddler into string "~tag1~tag2~tag3~"
		var tiddlertags = "~"+tids[t].tags.join("~")+"~";
		try { if(eval(c)) r.push(tids[t]); } // test tags
		catch(e) { // error in test
			displayMessage(cmm.msg2.format([tagexpr]));
			displayMessage(cmm.msg3.format([c]));
			displayMessage(e.toString());
			break; // skip remaining tiddlers
		}
	}
	if (debug) displayMessage(cmm.msg4.format([r.length,tagexpr]));
	return r;
}
//}}}
//{{{
config.macros.matchTags = {
	msg1: "scanning %0 input tiddlers",
	msg2: "looking for '%0'",
	msg3: "using expression: '%0'",
	msg4: "found %0 tiddlers matching '%1'",
	noMatch: "no matching tiddlers",
	untaggedKeyword: "-",



	untaggedLabel: "no tags",
	untaggedPrompt: "show tiddlers with no tags",
	defTiddler: "MatchingTiddlers",
	defFormat: "%0",
	defSeparator: "\n",
	reportHeading: "Found %0 tiddlers tagged with: '{{{%1}}}'\n----\n",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var mode=params[0]?params[0].toLowerCase():'';
		if (mode=="inline")
			params.shift();
		if (mode=="report" || mode=="panel") {
			params.shift();
			var target=params.shift()||this.defTiddler;
		}
		if (mode=="popup") {
			params.shift();
			if (params[0]&&params[0].substr(0,6)=="label:") var label=params.shift().substr(6);
			if (params[0]&&params[0].substr(0,7)=="prompt:") var prompt=params.shift().substr(7);
		} else {
			var fmt=(params.shift()||this.defFormat).unescapeLineBreaks();
			var sep=(params.shift()||this.defSeparator).unescapeLineBreaks();
		}
		var sortBy="+title";
		if (params[0]&&params[0].substr(0,5)=="sort:") sortBy=params.shift().substr(5);
		var expr = params.join(" ");
		if (mode!="panel" && (!expr||!expr.trim().length)) return;
		if (expr==this.untaggedKeyword)
			{ var label=this.untaggedLabel; var prompt=this.untaggedPrompt };
		switch (mode) {
			case "popup": this.createPopup(place,label,expr,prompt,sortBy); break;
			case "panel": this.createPanel(place,expr,fmt,sep,sortBy,target); break;
			case "report": this.createReport(target,expr,fmt,sep,sortBy); break;
			case "inline": default: this.createInline(place,expr,fmt,sep,sortBy); break;
		}
	},
	formatList: function(tids,fmt,sep) {
		var out=[];
		for (var t=0; t<tids.length; t++) {
			var title="[["+tids[t].title+"]]";
			var who=tids[t].modifier;
			var when=tids[t].modified.toLocaleString();
			var text=tids[t].text;
			var first=tids[t].text.split("\n")[0];
			var desc=store.getTiddlerSlice(tids[t].title,"description");
			desc=desc||store.getTiddlerSlice(tids[t].title,"Description");
			desc=desc||store.getTiddlerText(tids[t].title+"##description");
			desc=desc||store.getTiddlerText(tids[t].title+"##Description");
			out.push(fmt.format([title,who,when,text,first,desc]));
		}
		return out.join(sep);
	},
	createInline: function(place,expr,fmt,sep,sortBy) {
		wikify(this.formatList(store.sortTiddlers(store.getMatchingTiddlers(expr),sortBy),fmt,sep),place);
	},
	createPopup: function(place,label,expr,prompt,sortBy) {
		var btn=createTiddlyButton(place,
			(label||expr).format([expr]),
			(prompt||config.views.wikified.tag.tooltip).format([expr]),
			function(ev){ return config.macros.matchTags.showPopup(this,ev||window.event); });
		btn.setAttribute("sortBy",sortBy);
		btn.setAttribute("expr",expr);
	},
	showPopup: function(here,ev) {
		var p=Popup.create(here); if (!p) return false;
		var tids=store.getMatchingTiddlers(here.getAttribute("expr"));
		store.sortTiddlers(tids,here.getAttribute("sortBy"));
		var list=[]; for (var t=0; t<tids.length; t++) list.push(tids[t].title);
		if (!list.length) createTiddlyText(p,this.noMatch);
		else {
			var b=createTiddlyButton(createTiddlyElement(p,"li"),
				config.views.wikified.tag.openAllText,
				config.views.wikified.tag.openAllTooltip,
				function() {
					var list=this.getAttribute("list").readBracketedList();
					story.displayTiddlers(null,tids);
				});
			b.setAttribute("list","[["+list.join("]] [[")+"]]");
			createTiddlyElement(p,"hr");
		}
		var out=this.formatList(tids," &nbsp;%0&nbsp; ","\n"); wikify(out,p);
		Popup.show();
		ev.cancelBubble=true;
		if(ev.stopPropagation) ev.stopPropagation();
		return false;
	},
	createReport: function(target,expr,fmt,sep,sortBy) {
		var tids=store.sortTiddlers(store.getMatchingTiddlers(expr),sortBy);
		if (!tids.length) { displayMessage('no matches for: '+expr); return false; }
		var msg=config.messages.overwriteWarning.format([target]);
		if (store.tiddlerExists(target) && !confirm(msg)) return false;
		var out=this.reportHeading.format([tids.length,expr])
		out+=this.formatList(tids,fmt,sep);
		store.saveTiddler(target,target,out,config.options.txtUserName,new Date(),[],{});
		story.closeTiddler(target); story.displayTiddler(null,target);
	},
	createPanel: function(place,expr,fmt,sep,sortBy,tid) {
		var html="<form style='display:inline'><!-- \
			--><input type='text'    name='expr' style='width:55%' title='tag expression'><!-- \
			--><input type='text'    name='fmt'  style='width:10%' title='list item format'><!-- \
			--><input type='text'    name='sep'  style='width:5%'  title='list item separator'><!-- \
			--><input type='text'    name='tid'  style='width:20%' title='target tiddler title'><!-- \
			--><input type='button'  name='go'   style='width:8%'  value='go' onclick=\" \
				var expr=this.form.expr.value; \
				if (!expr.length) { alert('Enter a boolean tag expression'); return false; } \
				var fmt=this.form.fmt.value; \
				if (!fmt.length) { alert('Enter the list item output format'); return false; } \
				var sep=this.form.sep.value.unescapeLineBreaks(); \
				var tid=this.form.tid.value; \
				if (!tid.length) { alert('Enter a target tiddler title'); return false; } \
				config.macros.matchTags.createReport(tid,expr,fmt,sep,'title'); \
				return false;\"> \
			</form>";
		var s=createTiddlyElement(place,"span"); s.innerHTML=html;
		var f=s.getElementsByTagName("form")[0];
		f.expr.value=expr; f.fmt.value=fmt; f.sep.value=sep.escapeLineBreaks(); f.tid.value=tid;
	}
};
//}}}
//{{{
// SHADOW TIDDLER for displaying default panel input form
config.shadowTiddlers.MatchTags="{{smallform{<<matchTags panel>>}}}";
//}}}
//{{{
// TWEAK core filterTiddlers() for enhanced boolean matching in [tag[...]] syntax:
// use getMatchingTiddlers instead getTaggedTiddlers
var fn=TiddlyWiki.prototype.filterTiddlers;
fn=fn.toString().replace(/getTaggedTiddlers/g,"getMatchingTiddlers");
eval("TiddlyWiki.prototype.filterTiddlers="+fn);
//}}}
//{{{
// REDEFINE core handler for enhanced boolean matching in tag:"..." paramifier
// use filterTiddlers() instead of getTaggedTiddlers() to get list of tiddlers.
config.paramifiers.tag = {
	onstart: function(v) {
		var tagged = store.filterTiddlers("[tag["+v+"]]");
		story.displayTiddlers(null,tagged,null,false,null);
	}
};
//}}}
/***
|Name|MatchTagsPluginInfo|
|Source|http://www.TiddlyTools.com/#MatchTagsPlugin|
|Documentation|http://www.TiddlyTools.com/#MatchTagsPluginInfo|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for [[MatchTagsPlugin]]|
!!!!!Usage
<<<
This plugin extends the {{{[tag[tagname]]}}} macro parameter syntax used by the TiddlyWiki core {{{<<list>>}}} macro so that, instead of a simple tagname value, you can specify a complex combination of tagname values using a //boolean expression// containing AND, OR, and NOT operators, enclosed in nested parentheses if needed.
{{{
<<list filter "[tag[expression]]">>
}}}
In addition, the plugin defines a new macro, {{{<<matchTags ...>>}}} that can be used instead of the core {{{<<list>>}}} macro to output a list of matching tiddlers //using a custom 'item format' and 'separator'//.  You can also use this macro to create a command link that displays the matching tiddlers within a popup list, similar to the standard {{{<<tag tagName>>}}} macro, but matching a combination of tag values rather than a single tag value.
{{{
<<matchTags inline "format" "separator" sort:fieldname tag expression>>
<<matchTags popup "label:..." "prompt:..." sort:fieldname tag expression>>
<<matchTags report TiddlerName "format" "separator" sort:fieldname tag expression>>
<<matchTags panel  Tiddlername "format" "separator" sort:fieldname tag expression>>
}}}
where:
* ''inline'', ''report'', ''panel'', and ''popup''<br>are keywords that indicate the type of output that the macro should produce:
** ''inline'' //(default)// - displays a list of matching tiddlers embedded directly in tiddler content
** ''popup'' - embeds a command button that, when clicked, lists matching tiddlers in a ~TiddlyWiki popup display
** ''report'' - generates a list of matching tiddler in a separate [[MatchingTiddlers]] report tiddler
** ''panel'' - displays an interactive form for generating a [[MatchingTiddlers]] report
* ''format''<br>defines the wiki-syntax for rendering list items.  The following //substitution markers// can be used to insert tiddler-specific information for each matched tiddler:
** {{{%0}}} - title
** {{{%1}}} - modifier (author)
** {{{%2}}} - modified (date of last change)
** {{{%3}}} - text (all tiddler content)
** {{{%4}}} - firstline (tiddler content up to the first newline)
** {{{%5}}} - description (tiddler slice or section content named "description" or "Description")
* ''separator''<br>defines the wiki-syntax to use //between// each matching title (e.g., ", " creates a comma-separated list, while "\n" displays one tiddler per line).
* ''sort:fieldname'' (optional)<br>specifies the sort order for the resulting list of tiddlers.  You can specify any tiddler field name (standard or custom-defined).  Standard tiddler fieldnames include: //title, created, modified, modifier//.  If not specified, tiddlers are sorted by title.  You can prefix the fieldname with "+" or "-" to indicate ascending or descending order, respectively.
* ''tag expression''<br>the remaining parameter(s) are joined together to define the boolean expression to be matched.
When using the ''popup'' option, there are two additional (and optional) parameters you can specify:
* ''"label:..."''(optional)<br> indicates the text for the popup command link.  The default is to display the specified tag expression itself.
* ''"prompt:..."'' (optional)<br>indicates the mouseover 'tooltip' for the popup command link.
When using the ''report'' or ''panel'' option, an additional parameter may be provided:
* ''~TiddlerName''<br>specifies the target tiddler into which the output will be generated (default: [[MatchingTiddlers]])
Notes:
*A tag expression can use any combination of text operators: ''AND'', ''OR'', ''NOT'' (or their equivalent javascript operators: ''&&'', ''||'', ''!''), contained in nested parentheses as needed.
*Operators should be delimited by spaces or parentheses.
*Before matching, leading/trailing spaces are automatically trimmed and multiple spaces are reduced to single spaces.
*Tag values containing embedded spaces do //not// have to be enclosed in {{{[[...]]}}}.
*Tag values that contain boolean operators as ''literal text'' (e.g., {{{"foo and bar"}}} or {{{"foo && bar"}}} cannot be used within a compound boolean expression, but //can// be matched if specified by themselves, without any other tag values or operators.
*To match tiddlers that are untagged, use "-" as a special tag value within the expression.
*You can match "wildcard" tags  by using //regular expression// (i.e., "text pattern") syntax within a tag value, e.g. {{{[Tt]agvalue.*}}}
<<<
!!!!!Examples:
<<<
display a popup list:
{{{
<<matchTags popup sample OR (settings AND systemConfig)>>
}}}
><<matchTags popup sample OR (settings AND systemConfig)>>
display a popup list with custom label:
{{{
<<matchTags popup "label:samples and settings" sample OR (settings AND systemConfig)>>
}}}
><<matchTags popup "label:samples and settings" sample OR (settings AND systemConfig)>>
display a popup list of untagged tiddlers:
{{{
<<matchTags popup ->>
}}}
><<matchTags popup ->>
generate a report using interactive form control panel
{{{
<<matchTags panel "MatchingTiddlers" "%0" "\n" sample OR (settings AND systemConfig)>>
}}}
>{{smallform{<<matchTags panel "MatchingTiddlers" "%0" "\n" sample OR (settings AND systemConfig)>>}}}
comma-separated list:
{{{
<<matchTags "%0" ", " sample OR (settings AND systemConfig)>>
}}}
><<matchTags "%0" ", " sample OR (settings AND systemConfig)>>
numbered list (sorted by modification date, most recent first):
{{{
<<matchTags "#%0 (%2)<br>^^%5^^" "\n" sort:-modified sample OR (settings AND systemConfig)>>
}}}
><<matchTags "#%0 (%2)<br>^^%5^^" "\n" sort:-modified sample OR (settings AND systemConfig)>>
bullet-item list (using the TiddlyWiki core {{{<<list filter ...>>}}} macro):
//(Note: when using the core {{{<<list>>}}} macro, you should always enclose the entire tag filter parameter within quotes)//
{{{
<<list filter "[tag[sample OR (settings AND systemConfig)]]">>
}}}
><<list filter "[tag[sample OR (settings AND systemConfig)]]">>
<<<
!!!!!Revisions
<<<
2008.09.04 [2.0.0] added "report" and "panel" options to generate formatted results and store in a tiddler.  Also, added config.macros.matchTags.formatList(place,fmt,sep) API to return formatted output for use with other plugins/scripts
2008.09.01 [1.9.2] fixed return value from popup button handler so IE doesn't attempt to leave the page
2008.08.31 [1.9.1] improved expression conversion handling to permit use of regular expressions for "wildcard" matching within tag values
2008.06.12 [1.9.0] added support for formatted output of: title, who, when, text, firstline, description (slice or section)
2008.06.05 [1.8.0] in getMatchingTiddlers(), added optional sortfield and tiddlers params to support use of alternative set of tiddlers instead of using current store content (provides filtering support for ImportTiddlersPlugin)
2008.06.04 [1.7.1] in getMatchingTiddlers(), reworked conversion of expression for more robust parsing of whitespace, parentheses and javascript operators and allow use of "-" (untagged) //within// expressions
2008.05.19 [1.7.0] in getMatchingTiddlers(), use reverseLookup() instead of forEachTiddler() to permit access to tiddlers included via [[IncludePlugin|http://tiddlywiki.abego-software.de/#IncludePlugin]]
2008.05.17 [1.6.0] in getMatchingTiddlers(), rewrote expression conversion to handle tags with spaces tag values that are substrings of other tag values.
2008.05.16 [1.5.0] added special case using "-" to find UNTAGGED tiddlers
2008.05.15 [1.4.0] added "popup" output option
2008.05.14 [1.3.4] instead of hijacking getTaggedTiddlers(), added tweak of filterTiddlers() prototype to replace getTaggedTiddlers() with getMatchingTiddler() so that core use of getTaggedTiddlers() does not perform boolean processing of tiddler titles such as [[To Be or not To Be]].  Also, improved "filter error" messages in getMatchingTiddlers() to report tag expression in addition to actual eval error.
2008.04.25 [1.3.3] in getTaggedTiddlers(), fixed handling for "not" embedded within a tag
2008.04.21 [1.3.2] in getTaggedTiddlers(), fixed handling for initial "NOT" and "NOT(expr)" syntax
2008.04.20 [1.3.1] in getTaggedTiddlers(), corrected check for boolean expression to avoid excess processing of tags containing spaces.  Also, improved handling for non-existing tags that contain text of existing tags
2008.04.19 [1.3.0] in filterTiddlers(), use getTaggedTiddlers() instead of matchTags(), and then hijack getTaggedTiddlers() to add matchTags() handling
2008.04.19 [*.*.*] plugin size reduction: moved documentation to [[MatchTagsPluginInfo]]
2008.03.25 [1.2.0] added optional "sort:fieldname" parameter
2008.03.20 [1.1.2] in handler(), replace 'encodeTiddlyLink' with explicit [[...]] brackets to ensure that one-word tiddler titles are properly rendered as TiddlyLinks
2008.02.29 [1.1.1] in matchTags(), added handling to skip remaining tiddlers if expression has an error
2008.02.29 [1.1.0] refactored to define store.matchTags() and extend store.filterTiddlers()
2008.02.28 [1.0.0] initial release
<<<
|col1 bare sans popup |k
|''<<slider chkIteratiemechanismen "} Iteratiemechanismen" "Menu ↕" "toon/verberg menu">>''|


Twee regels wit en dan kan er weer geschreven worden.

''{{sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Menu ↘">>}}}''

Eén regel wit en dan kan er weer geschreven worden.

|<<tiddler "} Iteratiemechanismen">> |

'//~MicroContent// being a fashionable word for self-contained fragments of content that are typically smaller than entire pages. Often ~MicroContent is presented via some kind of aggregation that reduces the perceptual shock and resource cost of context switching (e.g. Blogs aggregating several entries onto a page or Flickr presenting photos in an album). This [[TiddlyWiki]] aggregates ~MicroContent items that I call "[[tiddlers|Tiddler]]" into pages that are loaded in one gulp and progressively displayed as the user clicks hypertext links to read them.' -- [[Jeremy Ruston|http://www.tiddlywiki.com/]]
<<tiddler WithholdTiddlerTags>>{{rf block{+++[Tags &darr;|show][Tags &uarr;|hide]{{up{<<tags [tiddler]>>}}}
===}}}<<tiddler [[{}::togglesliders]]>> <<eval [=[Van welke van de procedurele en declaratieve talen waarmee ik te maken heb gehad is de syntaxis eigenlijk op formele wijze gedefinieerd? Die vraag was de aanleiding om een kleine privéverzameling van definities op het hoogste niveau aan te leggen. Dat zullen dus fragmenten zijn met een betekenis in de trant van "een X-programma bestaat uit een sequentie van de volgende syntactische componenten...", maar dan in de vorm van formules of diagrammen. Deze vormen het beginpunt van verdere uitwerking van die componenten op dezelfde wijze, tot op het niveau van afzonderlijke letters, cijfers en leestekens. Die uitwerking neem ik niet in deze collectie op. Meer dan een beperkte catalogus van taalspecificaties bied ik hier dus niet.

De eerste taaldefinitie die ik onder ogen (en ook werkelijk fysiek in eigendom) kreeg, betrof ALGOL 60. Destijds besefte ik niet welke historische waarde dat rapport had. Het bevat de eerste op de buitenwereld gerichte uitspraken in [[BNF|Backus-Naur Form]], een metataal waarop later tal van uitbreidingen zijn bedacht, meestal onder de noemer 'Extended BNF' (EBNF).

Ik heb in dit overzicht steeds geprobeerd zo goed mogelijk recht te doen aan de oorspronkelijke formulering of verbeelding. Deze heb ik aan de linkerkant getoond. Aan de rechterkant staat de vertaling in [[Welsh Rarebit]], een eigen EBNF-dialect.
{{clear block{
+++(~Startsymbolen_Algol)![ALGOL 60 &darr;|show][ALGOL 60 &uarr;|hide]
{{lf w45pct pre{
|plain |k
|$<{{serif{program}}}$> | {{serif{:&#x200a;:&#x200a;=}}}|$<{{serif{block}}}$> |
|                       |                            $|@|$<{{serif{compound statement}}}$> |
}}}{{lf w45pct mlhem pre{
//program// $--> //block//
         $| //compoundStatement//
}}}{{clear block{Bron: <<tiddler Bibliografie##Algol-60>\>}}}
===/%

%/+++(~Startsymbolen_ABNF)![Augmented BNF (ABNF) &darr;|show][Augmented BNF (ABNF) &uarr;|hide]
ABNF doet dienst als metataal voor IETF-protocollen. Deze metataal kan zichzelf definiëren:
{{lf w45pct pre{
rulelist = 1*( rule / (*c-wsp c-nl) )
}}}{{lf w45pct mlhem pre{
//rulelist// $--> $(//rule// $| //cWsp// $___$0 //cNl//$) $___
}}}{{clear block{Bronnen: [[Wikipedia|https://en.wikipedia.org/wiki/Augmented_Backus%E2%80%93Naur_form]], https://datatracker.ietf.org/doc/html/rfc5234}}}
===/%

%/+++(~Startsymbolen_C)![C &darr;|show][C &uarr;|hide]
Het begrip //programma// is informeel gedefinieerd: "A program consists of one or more //translation units// stored in files." De translation unit is vervolgens het startpunt voor de formele grammatica:
{{lf w45pct pre{
|plain serif|k
|>|//translation-unit:// |
|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |//external-declaration// |
| |//translation-unit external-declaration// |
}}}{{lf w45pct mlhem pre{
//translationUnit// $--> //externalDeclaration//
                 $| //translationUnit// //externalDeclaration//

}}}{{clear block{Bron: <<tiddler Bibliografie##K&R>\>}}}
===/%

%/+++(~Startsymbolen_EBNF)![Extended BNF (EBNF) &darr;|show][Extended BNF (EBNF) &uarr;|hide]
De gestandaardiseerde versie van Extended BNF wordt gebruikt om de syntaxis van de gestandaardiseerde versie van Extended BNF te definiëren. Verder wordt deze notatie weinig toegepast. Alles en iedereen hanteert namelijk zijn eigen EBNF-dialect. Zelf heb ik er dan ook maar een stel bedacht.
{{lf w45pct pre{
syntax = syntax rule, {syntax rule};
}}}{{lf w45pct mlhem pre{
//syntax// $--> //syntaxRule// $___
}}}{{clear block{Bron: <<tiddler Bibliografie##EBNF>\>}}}
===/%

%/+++(~Startsymbolen_OBNF)![Overhauled BNF (OBNF) &darr;|show][Overhauled BNF (OBNF) &uarr;|hide]
Na bestudering van Extended BNF meende ik dat ik op basis van het gelezene zelf betere alternatieven kon bedenken. Dat heeft geleid tot enkele miljoenen metatalen, bijeen&shy;gebracht onder de noemer 'Overhauled BNF'. Evenals EBNF kan OBNF goed gelezen worden door een computer. Evenals EBNF is OBNF een kwelling voor de menselijke lezer. Na één toepassing besloot ik dat ik het in op mensen gerichte tekst over een andere boeg moest gooien, wat resulteerde in [[Welsh Rarebit]] (WR). De OBNF-dialecten kunnen hun eigen syntaxis definiëren:
{{lf w45pct pre{
syntax := rule+;
}}}{{lf w45pct mlhem pre{
//syntax// $--> //rule// $___
}}}{{clear block{Bronnen: //(nog niet vrijgegeven//)}}}
===]=]>>/%

%/+++(~Startsymbolen_Pascal)![Pascal &darr;|show][Pascal &uarr;|hide]
In de Pascal-wereld zijn syntaxdiagrammen nogal populair. Wat Wirth als definitie van //programma// had getekend, was iets te mager uitgevallen: de optionele //program heading// ontbrak daarin. Omdat ik voornamelijk met Turbo Pascal 6 heb gewerkt, heb ik het diagram van Swan er maar bij gepakt. Ook daarin ontbrak een kleinigheidje: de puntkomma die de eventuele {{tt t{uses}}}-specificatie moet scheiden van de rest van het programma. Dat heb ik hieronder rechtgezet. In Free Pascal is de program heading net als in Turbo Pascal verplicht en kan deze bovendien programma&shy;parameters bevatten. Die heb ik nu niet meegenomen.
{{lf w45pct pre low{
{{monoz{
//program//
<<draw [=[
   ''program'' @00@00@00@00@00 //identifier// @00@00@00@00@00 '';'' @00@00@00@00@00{{up1px{@b6}}}

      {{up1px{@b6}}}@00@00@00@2c@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@00@2c@00@00 //block// @00@00@00@00@00 ''.''
          @70@00@00 ''uses'' @00@00@00@00 //identifier// @00@2c@00@00 '';'' @00@00@6f
                     {{zi10{{{up{{{up{@b2}}}}}}}}}@70@00@00@00@00@00 '','' @00@00@00@00@00@00@6f
]=] mono1z>>}}}}}}<<eval [=[{{lf w45pct mlhem pre{
//program// $--> ''program'' //identifier// '';'' $(''uses'' //identifier//'',''$___ '';''$)$0 //block// ''.''




{{h6 suf{ }}}
}}}]=]>>{{clear block{Bronnen:
* <<tiddler Bibliografie##Wirth>>
* <<tiddler Bibliografie##Swan>>
* https://www.freepascal.org/
}}}
===/%

%/+++(~Startsymbolen_Voorwoord)![Voorwoord &darr;|show][Voorwoord &uarr;|hide]
<<eval [=[Voorwoord is slechts een frivool knutselwerkje van mijn door Lisp geïnspireerde hand, of om het wat serieuzer te formuleren, een experiment met een metataal die slechts twee meta&shy;symbolen kent en de eigen syntaxis heel aardig kan beschrijven. De expressiviteit is vergelijkbaar met die van BNF, want herhalingen kunnen alleen door middel van recursieve productie&shy;regels worden voorgeschreven. Mijn omzetting naar Welsh Rarebit aan de rechterkant illustreert hoe laatstgenoemde zich uit haar beperkingen wurmt door een andere metataal naar keuze in te bedden.
{{lf w45pct pre{
$($(grammar$)&deg;$($(rules$)&deg;$)$)
}}}{{lf w45pct mlhem pre{
//grammar// $--> $< OBNF: "$(", rules, "$)" $>
}}}{{clear block{Bron: //(voorlopig alleen nog ergens verstopt op Internet)//}}}]=]>>
===
{{h4{@@line-height:1.5em;{{plhem sans f2d{@@line-height:2em;goto tiddler@@}}}<<gotoTiddler search liststyle: "position:fixed; right:0; z-index:2000">>/%
%/<<permaview>>/%
%/<<showPopup tiddler:[[ToggleBreadcrumbs]] label: "toggle breadcrumbs ↘">>/%
%/<script>return readOnly ? "" : "<hr>";</script>/%
%/<<newTiddler>>/%
%/<<newJournal "Journal YYYY-0MM-0DD (DDD)" "journal">>/%
%/<<saveChanges>>/%
%/<<unsavedChanges command "unsaved changes: %0 ↘">>@@}}}
Veel formele talen neigen ertoe onstuitbaar uit te dijen tot voorbij het punt ''{{stix{&#x03e1;}}}''~~0~~ waar zelfs de individuele makers van de taal deze niet meer volledig kunnen overzien.{{ref{&#x200a;[[[1]|##1]]}}} Ik heb hierbij vooral programmeer&shy;talen op het oog. Eigenlijk zouden we in die gevallen niet alleen moeten terug&shy;kijken naar waar het misging, maar ook alvast vooruit&shy;blikken op de volgende mijlpaal: ''{{stix{&#x03e1;}}}''~~1~~. Alleen... wat stellen we ons daarbij voor? Dat de verdere taal&shy;ontwikkeling wordt overgenomen door AI? Dat uitsluitend AI nog in zo'n ultra-''{{stix{&#x03e1;}}}''~~1~~-taal programmeert?

----
|bare|k
|<html><a name="1">[1]</a></html> |Voor de argeloze lezer, de [[sampi|https://en.wikipedia.org/wiki/Sampi]] geheten letter ''{{stix{&#x03e1;}}}'' is die ene letter te veel in het Griekse alfabet. Een fatsoenlijk alfabet houdt het bij 26 letters. Maar ''{{stix{&#x03e1;}}}'' is de 27^^e^^ en bovendien nogal obscuur.|
/***
|Name|NestedSlidersPlugin|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.9|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|show content in nest-able sliding/floating panels, without creating separate tiddlers for each panel's content|
!!!!!Documentation
>see [[NestedSlidersPluginInfo]]
!!!!!Configuration
<<<
<<option chkFloatingSlidersAnimate>> allow floating sliders to animate when opening/closing
>Note: This setting can cause 'clipping' problems in some versions of InternetExplorer.
>In addition, for floating slider animation to occur you must also allow animation in general (see [[AdvancedOptions]]).
<<<
!!!!!Revisions
<<<
2008.11.15 - 2.4.9 in adjustNestedSlider(), don't make adjustments if panel is marked as 'undocked' (CSS class).  In onClickNestedSlider(), SHIFT-CLICK docks panel (see [[MoveablePanelPlugin]])
|please see [[NestedSlidersPluginInfo]] for additional revision details|
2005.11.03 - 1.0.0 initial public release.  Thanks to RodneyGomes, GeoffSlocock, and PaulPetterson for suggestions and experiments.
<<<
!!!!!Code
***/
//{{{
version.extensions.NestedSlidersPlugin= {major: 2, minor: 4, revision: 9, date: new Date(2008,11,15)};

// options for deferred rendering of sliders that are not initially displayed
if (config.options.chkFloatingSlidersAnimate===undefined)
	config.options.chkFloatingSlidersAnimate=false; // avoid clipping problems in IE

// default styles for 'floating' class
setStylesheet(".floatingPanel { position:absolute; z-index:10; padding:0.5em; margin:0em; \
	background-color:#eee; color:#000; border:1px solid #000; text-align:left; }","floatingPanelStylesheet");

// if removeCookie() function is not defined by TW core, define it here.
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}

config.formatters.push( {
	name: "nestedSliders",
	match: "\\n?\\+{3}",
	terminator: "\\s*\\={3}\\n?",
	lookahead: "\\n?\\+{3}(\\+)?(\\([^\\)]*\\))?(\\!*)?(\\^(?:[^\\^\\*\\@\\[\\>]*\\^)?)?(\\*)?(\\@)?(?:\\{\\{([\\w]+[\\s\\w]*)\\{)?(\\[[^\\]]*\\])?(\\[[^\\]]*\\])?(?:\\}{3})?(\\#[^:]*\\:)?(\\>)?(\\.\\.\\.)?\\s*",
	handler: function(w)
		{
			lookaheadRegExp = new RegExp(this.lookahead,"mg");
			lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = lookaheadRegExp.exec(w.source)
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
			{
				var defopen=lookaheadMatch[1];
				var cookiename=lookaheadMatch[2];
				var header=lookaheadMatch[3];
				var panelwidth=lookaheadMatch[4];
				var transient=lookaheadMatch[5];
				var hover=lookaheadMatch[6];
				var buttonClass=lookaheadMatch[7];
				var label=lookaheadMatch[8];
				var openlabel=lookaheadMatch[9];
				var panelID=lookaheadMatch[10];
				var blockquote=lookaheadMatch[11];
				var deferred=lookaheadMatch[12];

				// location for rendering button and panel
				var place=w.output;

				// default to closed, no cookie, no accesskey, no alternate text/tip
				var show="none"; var cookie=""; var key="";
				var closedtext=">"; var closedtip="";
				var openedtext="<"; var openedtip="";

				// extra "+", default to open
				if (defopen) show="block";

				// cookie, use saved open/closed state
				if (cookiename) {
					cookie=cookiename.trim().slice(1,-1);
					cookie="chkSlider"+cookie;
					if (config.options[cookie]==undefined)
						{ config.options[cookie] = (show=="block") }
					show=config.options[cookie]?"block":"none";
				}

				// parse label/tooltip/accesskey: [label=X|tooltip]
				if (label) {
					var parts=label.trim().slice(1,-1).split("|");
					closedtext=parts.shift();
					if (closedtext.substr(closedtext.length-2,1)=="=")	
						{ key=closedtext.substr(closedtext.length-1,1); closedtext=closedtext.slice(0,-2); }
					openedtext=closedtext;
					if (parts.length) closedtip=openedtip=parts.join("|");
					else { closedtip="show "+closedtext; openedtip="hide "+closedtext; }
				}

				// parse alternate label/tooltip: [label|tooltip]
				if (openlabel) {
					var parts=openlabel.trim().slice(1,-1).split("|");
					openedtext=parts.shift();
					if (parts.length) openedtip=parts.join("|");
					else openedtip="hide "+openedtext;
				}

				var title=show=='block'?openedtext:closedtext;
				var tooltip=show=='block'?openedtip:closedtip;

				// create the button
				if (header) { // use "Hn" header format instead of button/link
					var lvl=(header.length>5)?5:header.length;
					var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,buttonClass,title);
					btn.onclick=onClickNestedSlider;
					btn.setAttribute("href","javascript:;");
					btn.setAttribute("title",tooltip);
				}
				else
					var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider,buttonClass);
				btn.innerHTML=title; // enables use of HTML entities in label

				// set extra button attributes
				btn.setAttribute("closedtext",closedtext);
				btn.setAttribute("closedtip",closedtip);
				btn.setAttribute("openedtext",openedtext);
				btn.setAttribute("openedtip",openedtip);
				btn.sliderCookie = cookie; // save the cookiename (if any) in the button object
				btn.defOpen=defopen!=null; // save default open/closed state (boolean)
				btn.keyparam=key; // save the access key letter ("" if none)
				if (key.length) {
					btn.setAttribute("accessKey",key); // init access key
					btn.onfocus=function(){this.setAttribute("accessKey",this.keyparam);}; // **reclaim** access key on focus
				}
				btn.setAttribute("hover",hover?"true":"false");
				btn.onmouseover=function(ev) {
					// optional 'open on hover' handling
					if (this.getAttribute("hover")=="true" && this.sliderPanel.style.display=='none') {
						document.onclick.call(document,ev); // close transients
						onClickNestedSlider(ev); // open this slider
					}
					// mouseover on button aligns floater position with button
					if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this,this.sliderPanel);
				}

				// create slider panel
				var panelClass=panelwidth?"floatingPanel":"sliderPanel";
				if (panelID) panelID=panelID.slice(1,-1); // trim off delimiters
				var panel=createTiddlyElement(place,"div",panelID,panelClass,null);
				panel.button = btn; // so the slider panel know which button it belongs to
				btn.sliderPanel=panel; // so the button knows which slider panel it belongs to
				panel.defaultPanelWidth=(panelwidth && panelwidth.length>2)?panelwidth.slice(1,-1):"";
				panel.setAttribute("transient",transient=="*"?"true":"false");
				panel.style.display = show;
				panel.style.width=panel.defaultPanelWidth;
				panel.onmouseover=function(event) // mouseover on panel aligns floater position with button
					{ if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this.button,this); }

				// render slider (or defer until shown) 
				w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
				if ((show=="block")||!deferred) {
					// render now if panel is supposed to be shown or NOT deferred rendering
					w.subWikify(blockquote?createTiddlyElement(panel,"blockquote"):panel,this.terminator);
					// align floater position with button
					if (window.adjustSliderPos) window.adjustSliderPos(place,btn,panel);
				}
				else {
					var src = w.source.substr(w.nextMatch);
					var endpos=findMatchingDelimiter(src,"+++","===");
					panel.setAttribute("raw",src.substr(0,endpos));
					panel.setAttribute("blockquote",blockquote?"true":"false");
					panel.setAttribute("rendered","false");
					w.nextMatch += endpos+3;
					if (w.source.substr(w.nextMatch,1)=="\n") w.nextMatch++;
				}
			}
		}
	}
)

function findMatchingDelimiter(src,starttext,endtext) {
	var startpos = 0;
	var endpos = src.indexOf(endtext);
	// check for nested delimiters
	while (src.substring(startpos,endpos-1).indexOf(starttext)!=-1) {
		// count number of nested 'starts'
		var startcount=0;
		var temp = src.substring(startpos,endpos-1);
		var pos=temp.indexOf(starttext);
		while (pos!=-1)  { startcount++; pos=temp.indexOf(starttext,pos+starttext.length); }
		// set up to check for additional 'starts' after adjusting endpos
		startpos=endpos+endtext.length;
		// find endpos for corresponding number of matching 'ends'
		while (startcount && endpos!=-1) {
			endpos = src.indexOf(endtext,endpos+endtext.length);
			startcount--;
		}
	}
	return (endpos==-1)?src.length:endpos;
}
//}}}
//{{{
window.onClickNestedSlider=function(e)
{
	if (!e) var e = window.event;
	var theTarget = resolveTarget(e);
	while (theTarget && theTarget.sliderPanel==undefined) theTarget=theTarget.parentNode;
	if (!theTarget) return false;
	var theSlider = theTarget.sliderPanel;
	var isOpen = theSlider.style.display!="none";

	// if SHIFT-CLICK, dock panel first (see [[MoveablePanelPlugin]])
	if (e.shiftKey && config.macros.moveablePanel) config.macros.moveablePanel.dock(theSlider,e);

	// toggle label
	theTarget.innerHTML=isOpen?theTarget.getAttribute("closedText"):theTarget.getAttribute("openedText");
	// toggle tooltip
	theTarget.setAttribute("title",isOpen?theTarget.getAttribute("closedTip"):theTarget.getAttribute("openedTip"));

	// deferred rendering (if needed)
	if (theSlider.getAttribute("rendered")=="false") {
		var place=theSlider;
		if (theSlider.getAttribute("blockquote")=="true")
			place=createTiddlyElement(place,"blockquote");
		wikify(theSlider.getAttribute("raw"),place);
		theSlider.setAttribute("rendered","true");
	}

	// show/hide the slider
	if(config.options.chkAnimate && (!hasClass(theSlider,'floatingPanel') || config.options.chkFloatingSlidersAnimate))
		anim.startAnimating(new Slider(theSlider,!isOpen,e.shiftKey || e.altKey,"none"));
	else
		theSlider.style.display = isOpen ? "none" : "block";

	// reset to default width (might have been changed via plugin code)
	theSlider.style.width=theSlider.defaultPanelWidth;

	// align floater panel position with target button
	if (!isOpen && window.adjustSliderPos) window.adjustSliderPos(theSlider.parentNode,theTarget,theSlider);

	// if showing panel, set focus to first 'focus-able' element in panel
	if (theSlider.style.display!="none") {
		var ctrls=theSlider.getElementsByTagName("*");
		for (var c=0; c<ctrls.length; c++) {
			var t=ctrls[c].tagName.toLowerCase();
			if ((t=="input" && ctrls[c].type!="hidden") || t=="textarea" || t=="select")
				{ try{ ctrls[c].focus(); } catch(err){;} break; }
		}
	}
	var cookie=theTarget.sliderCookie;
	if (cookie && cookie.length) {
		config.options[cookie]=!isOpen;
		if (config.options[cookie]!=theTarget.defOpen) window.saveOptionCookie(cookie);
		else window.removeCookie(cookie); // remove cookie if slider is in default display state
	}

	// prevent SHIFT-CLICK from being processed by browser (opens blank window... yuck!)
	// prevent clicks *within* a slider button from being processed by browser
	// but allow plain click to bubble up to page background (to close transients, if any)
	if (e.shiftKey || theTarget!=resolveTarget(e))
		{ e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); }
	Popup.remove(); // close open popup (if any)
	return false;
}
//}}}
//{{{
// click in document background closes transient panels 
document.nestedSliders_savedOnClick=document.onclick;
document.onclick=function(ev) { if (!ev) var ev=window.event; var target=resolveTarget(ev);

	if (document.nestedSliders_savedOnClick)
		var retval=document.nestedSliders_savedOnClick.apply(this,arguments);
	// if click was inside a popup... leave transient panels alone
	var p=target; while (p) if (hasClass(p,"popup")) break; else p=p.parentNode;
	if (p) return retval;
	// if click was inside transient panel (or something contained by a transient panel), leave it alone
	var p=target; while (p) {
		if ((hasClass(p,"floatingPanel")||hasClass(p,"sliderPanel"))&&p.getAttribute("transient")=="true") break;
		p=p.parentNode;
	}
	if (p) return retval;
	// otherwise, find and close all transient panels...
	var all=document.all?document.all:document.getElementsByTagName("DIV");
	for (var i=0; i<all.length; i++) {
		 // if it is not a transient panel, or the click was on the button that opened this panel, don't close it.
		if (all[i].getAttribute("transient")!="true" || all[i].button==target) continue;
		// otherwise, if the panel is currently visible, close it by clicking it's button
		if (all[i].style.display!="none") window.onClickNestedSlider({target:all[i].button})
		if (!hasClass(all[i],"floatingPanel")&&!hasClass(all[i],"sliderPanel")) all[i].style.display="none";
	}
	return retval;
};
//}}}
//{{{
// adjust floating panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel) {
	if (hasClass(panel,"floatingPanel") && !hasClass(panel,"undocked")) {
		// see [[MoveablePanelPlugin]] for use of 'undocked'
		var rightEdge=document.body.offsetWidth-1;
		var panelWidth=panel.offsetWidth;
		var left=0;
		var top=btn.offsetHeight; 
		if (place.style.position=="relative" && findPosX(btn)+panelWidth>rightEdge) {
			left-=findPosX(btn)+panelWidth-rightEdge; // shift panel relative to button
			if (findPosX(btn)+left<0) left=-findPosX(btn); // stay within left edge
		}
		if (place.style.position!="relative") {
			var left=findPosX(btn);
			var top=findPosY(btn)+btn.offsetHeight;
			var p=place; while (p && !hasClass(p,'floatingPanel')) p=p.parentNode;
			if (p) { left-=findPosX(p); top-=findPosY(p); }
			if (left+panelWidth>rightEdge) left=rightEdge-panelWidth;
			if (left<0) left=0;
		}
		panel.style.left=left+"px"; panel.style.top=top+"px";
	}
}
//}}}
//{{{
// TW2.1 and earlier:
// hijack Slider stop handler so overflow is visible after animation has completed
Slider.prototype.coreStop = Slider.prototype.stop;
Slider.prototype.stop = function()
	{ this.coreStop.apply(this,arguments); this.element.style.overflow = "visible"; }

// TW2.2+
// hijack Morpher stop handler so sliderPanel/floatingPanel overflow is visible after animation has completed
if (version.major+.1*version.minor+.01*version.revision>=2.2) {
	Morpher.prototype.coreStop = Morpher.prototype.stop;
	Morpher.prototype.stop = function() {
		this.coreStop.apply(this,arguments);
		var e=this.element;
		if (hasClass(e,"sliderPanel")||hasClass(e,"floatingPanel")) {
			// adjust panel overflow and position after animation
			e.style.overflow = "visible";
			if (window.adjustSliderPos) window.adjustSliderPos(e.parentNode,e.button,e);
		}
	};
}
//}}}
/***
|Name|NestedSlidersPluginInfo|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.9|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for [[NestedSlidersPlugin]]|
This plugin adds new wiki syntax for embedding 'slider' panels directly into tiddler content.
!!!!!Usage
<<<
Use {{{+++}}} and {{{===}}} to delimit the slider content.  You can also 'nest' these sliders as deep as you like (see complex nesting example below), so that expandable 'tree-like' hierarchical displays can be created.  This is most useful when converting existing in-line text content to create in-line annotations, footnotes, context-sensitive help, or other subordinate information displays.

Additional optional syntax elements let you specify
*default to open
*cookiename
*heading level
*floater (with optional CSS width value)
*transient display (clicking elsewhere closes panel)
*open on hover (without needing to click)
*custom class/label/tooltip/accesskey
*alternate label/tooltip (displayed when panel is open)
*panelID (for later use with {{{<<DOM>>}}} macro.  See [[DOMTweaksPlugin]])
*automatic blockquote style on panel
*deferred rendering of panel content
The complete syntax, using all options, is:
//{{{
++++(cookiename)!!!!!^width^*@{{class{[label=key|tooltip][altlabel|alttooltip]}}}#panelID:>...
content goes here
===
//}}}
where:
* ''"""+++""" (or """++++""") and """==="""''<br>marks the start and end of the slider definition, respectively.  When the extra {{{+}}} is used, the slider will be open when initially displayed.
* ''"""(cookiename)"""''<br>saves the slider opened/closed state, and restores this state whenever the slider is re-rendered.
* ''"""! through !!!!!"""''<br>displays the slider label using a formatted headline (Hn) style instead of a button/link style
* ''"""^width^ (or just ^)"""''<br>makes the slider 'float' on top of other content rather than shifting that content downward.  'width' must be a valid CSS value (e.g., "30em", "180px", "50%", etc.).  If omitted, the default width is "auto" (i.e., fit to content)
* ''"""*"""''<br>denotes "transient display": when a click occurs elsewhere in the document, the slider/floating panel will be automatically closed.  This is useful for creating 'pulldown menus' that automatically go away after they are used.  //Note: using SHIFT-click on a slider label will open/close that slider without triggering the automatic closing of any transient slider panels that are currently displayed, permitting ''temporary'' display of several transient panels at once.//
* ''"""@"""''<br>denotes "open on hover": the slider/floating panel will be automatically opened as soon as the mouse moves over the slider label, without requiring a click.
* ''"""{{class{[label=key|tooltip][altlabel|alttooltip]}}}"""''<br>uses label/tooltip/accesskey.  """{{class{...}}}""", """=key""", """|tooltip""" and """[altlabel|alttooltip]""" are optional.  'class' is any valid CSS class name, used to style the slider label text.  'key' must be a ''single letter only''.  altlabel/alttooltip specify alternative label/tooltip for use when slider/floating panel is displayed.  //Note: you can use HTML syntax within the label text to include HTML entities (e.g., {{{&raquo;}}} (&raquo;) or {{{&#x25ba;}}} (&#x25ba;), or even embedded images (e.g., {{{<img src="images/eric3.gif">}}}).//
* ''"""#panelID:"""''<br>defines a unique DOM element ID that is assigned to the panel element used to display the slider content.  This ID can then be used later to reposition the panel using the {{{<<DOM move id>>}}} macro (see [[DOMTweaksPlugin]]), or to access/modify the panel element through use of {{{document.getElementById(...)}}}) javascript code in a plugin or inline script.
* ''""">"""''<br>automatically adds blockquote formatting to slider content
* ''"""..."""''<br>defers rendering of closed sliders until the first time they are opened.  //Note: deferred rendering may produce unexpected results in some cases.  Use with care.//

//Note: to make slider definitions easier to read and recognize when editing a tiddler, newlines immediately following the {{{+++}}} 'start slider' or preceding the {{{===}}} 'end slider' sequence are automatically supressed so that excess whitespace is eliminated from the output.//
<<<
!!!!!Examples
<<<
simple in-line slider: 
{{{
+++
   content
===
}}}
+++
   content
===
----
use a custom label and tooltip: 
{{{
+++[label|tooltip]
   content
===
}}}
+++[label|tooltip]
   content
===
----
content automatically blockquoted: 
{{{
+++>
   content
===
}}}
+++>
   content
===
----
all options (except cookie) //(default open, heading, sized floater, transient, open on hover, class, label/tooltip/key, blockquoted, deferred)//
{{{
++++!!!^30em^*@{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
}}}
++++!!!^30em^*@{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
----
complex nesting example:
{{{
+++[get info...=I|click for information or press Alt-I]
	put some general information here,
	plus a floating panel with more specific info:
	+++^10em^[view details...|click for details]
		put some detail here, which could in turn contain a transient panel,
		perhaps with a +++^25em^*[glossary definition]explaining technical terms===
	===
===
}}}
+++[get info...=I|click for information or press Alt-I]
	put some general information here,
	plus a floating panel with more specific info:
	+++^10em^[view details...|click for details]
		put some detail here, which could in turn contain a transient panel,
		perhaps with a +++^25em^*[glossary definition]explaining technical terms===
	===
===
----
embedded image as slider button
{{{
+++[<img src=images/eric3.gif>|click me!]>
	{{big{OUCH!}}}
===
}}}
+++[<img src=images/eric3.gif>|click me!]>
	{{big{OUCH!}}}
===
<<<
!!!!!Revisions
<<<
2008.11.15 - 2.4.9 in adjustNestedSlider(), don't make adjustments if panel is marked as 'undocked' (CSS class).  In onClickNestedSlider(), SHIFT-CLICK docks panel (see [[MoveablePanelPlugin]])
2008.11.13 - 2.4.8 in document.onclick(), if transient panel is not a sliderPanel or floatingPanel, hide it via CSS
2008.10.05 - 2.4.7 in onClickNestedSlider(), added try/catch around focus() call to prevent IE error if input field being focused on is currently not visible.
2008.09.07 - 2.4.6 added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.06.07 - 2.4.5 in 'onmouseover' handler for 'open on hover' slider buttons, use call() method when invoking document.onclick function (avoids error in IE)
2008.06.07 - 2.4.4 changed default for chkFloatingSlidersAnimate to FALSE to avoid clipping problem on some browsers (IE).  Updated Morpher hijack (again) to adjust regular sliderPanel styles as well as floatingPanel styles.
2008.05.07 - 2.4.3 updated Morpher hijack to adjust floatingPanel styles after animation without affecting other animated elements (i.e. popups).  Also, updated adjustSliderPos() to account for scrollwidth and use core findWindowWidth().
2008.04.02 - 2.4.2 in onClickNestedSlider, handle clicks on elements contained //within// slider buttons (e.g., when using HTML to display an image as a slider button).
2008.04.01 - 2.4.1 open on hover also triggers document.onclick to close other transient sliders
2008.04.01 - 2.4.0 re-introduced 'open on hover' feature using "@" symbol
2008.03.26 - 2.3.5 in document.onclick(), if click is in popup, don't dismiss transient panel (if any)
2008.01.08 - [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 - 2.3.4 added hijack for Animator.prototype.startAnimating().  Previously, the plugin code simply set the overflow to "visible" after animation.  This code tweak corrects handling of elements that were styled with overflow=hidden/auto/scroll before animation by saving the overflow style and then restoring it after animation has completed.
2007.12.17 - 2.3.3 use hasClass() instead of direct comparison to test for "floatingPanel" class.  Allows floating panels to have additional classes assigned to them (i.e., by AnimationEffectsPlugin).
2007.11.14 - 2.3.2 in onClickNestedSlider(), prevent SHIFT-click events from opening a new, empty browser window by setting "cancelBubble=true" and calling "stopPropagation()".  Note: SHIFT-click is still processed as a normal click (i.e., it toggles the slider panel display).  Also, using SHIFT-click will prevent 'transient' sliders from being automatically closed when another slider is opened, allowing you to *temporarily* display several transient sliders at once.
2007.07.26 - 2.3.1 in document.onclick(), propagate return value from hijacked core click handler to consume OR bubble up click as needed.  Fixes "IE click disease", whereby nearly every mouse click causes a page transition.
2007.07.20 - 2.3.0 added syntax for setting panel ID (#panelID:).  This allows individual slider panels to be repositioned within tiddler content simply by giving them a unique ID and then moving them to the desired location using the {{{<<DOM move id>>}}} macro.
2007.07.19 - 2.2.0 added syntax for alttext and alttip (button label and tooltip to be displayed when panel is open)
2007.07.14 - 2.1.2 corrected use of 'transient' attribute in IE to prevent (non-recursive) infinite loop
2007.07.12 - 2.1.0 replaced use of "*" for 'open/close on rollover' (which didn't work too well).  "*" now indicates 'transient' panels that are automatically closed if a click occurs somewhere else in the document.  This permits use of nested sliders to create nested "pulldown menus" that automatically disappear after interaction with them has been completed.  Also, in onClickNestedSlider(), use "theTarget.sliderCookie", instead of "this.sliderCookie" to correct cookie state tracking when automatically dismissing transient panels.
2007.06.10 - 2.0.5 add check to ensure that window.adjustSliderPanel() is defined before calling it (prevents error on shutdown when mouse event handlers are still defined)
2007.05.31 - 2.0.4 add handling to invoke adjustSliderPanel() for onmouseover events on slider button and panel.  This allows the panel position to be re-synced when the button position shifts due to changes in unrelated content above it on the page.  (thanks to Harsha for bug report)
2007.03.30 - 2.0.3 added chkFloatingSlidersAnimate (default to FALSE), so that slider animation can be disabled independent of the overall document animation setting (avoids strange rendering and focus problems in floating panels)
2007.03.01 - 2.0.2 for TW2.2+, hijack Morpher.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
2007.03.01 - 2.0.1 in hijack for Slider.prototype.stop, use apply() to pass params to core function
2006.07.28 - 2.0.0 added custom class syntax around label/tip/key syntax: {{{{{classname{[label=key|tip]}}}}}}
2006.07.25 - 1.9.3 when parsing slider, save default open/closed state in button element, then in onClickNestedSlider(), if slider state matches saved default, instead of saving cookie, delete it.  Significantly reduces the 'cookie overhead' when default slider states are used.
2006.06.29 - 1.9.2 in onClickNestedSlider(), when setting focus to first control, skip over type="hidden"
2006.06.22 - 1.9.1 added panel.defaultPanelWidth to save requested panel width, even after resizing has changed the style value
2006.05.11 - 1.9.0 added optional '^width^' syntax for floating sliders and '=key' syntax for setting an access key on a slider label
2006.05.09 - 1.8.0 in onClickNestedSlider(), when showing panel, set focus to first child input/textarea/select element
2006.04.24 - 1.7.8 in adjustSliderPos(), if floating panel is contained inside another floating panel, subtract offset of containing panel to find correct position
2006.02.16 - 1.7.7 corrected deferred rendering to account for use-case where show/hide state is tracked in a cookie
2006.02.15 - 1.7.6 in adjustSliderPos(), ensure that floating panel is positioned completely within the browser window (i.e., does not go beyond the right edge of the browser window)
2006.02.04 - 1.7.5 add 'var' to unintended global variable declarations to avoid FireFox 1.5.0.1 crash bug when assigning to globals
2006.01.18 - 1.7.4 only define adjustSliderPos() function if it has not already been provided by another plugin.  This lets other plugins 'hijack' the function even when they are loaded first.
2006.01.16 - 1.7.3 added adjustSliderPos(place,btn,panel,panelClass) function to permit specialized logic for placement of floating panels.  While it provides improved placement for many uses of floating panels, it exhibits a relative offset positioning error when used within *nested* floating panels.  Short-term workaround is to only adjust the position for 'top-level' floaters.
2006.01.16 - 1.7.2 added button property to slider panel elements so that slider panel can tell which button it belongs to.  Also, re-activated and corrected animation handling so that nested sliders aren't clipped by hijacking Slider.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
2006.01.14 - 1.7.1 added optional "^" syntax for floating panels.  Defines new CSS class, ".floatingPanel", as an alternative for standard in-line ".sliderPanel" styles.
2006.01.14 - 1.7.0 added optional "*" syntax for rollover handling to show/hide slider without requiring a click (Based on a suggestion by tw4efl)
2006.01.03 - 1.6.2 When using optional "!" heading style, instead of creating a clickable "Hn" element, create an "A" element inside the "Hn" element.  (allows click-through in SlideShowPlugin, which captures nearly all click events, except for hyperlinks)
2005.12.15 - 1.6.1 added optional "..." syntax to invoke deferred ('lazy') rendering for initially hidden sliders
removed checkbox option for 'global' application of lazy sliders
2005.11.25 - 1.6.0 added optional handling for 'lazy sliders' (deferred rendering for initially hidden sliders)
2005.11.21 - 1.5.1 revised regular expressions: if present, a single newline //preceding// and/or //following// a slider definition will be suppressed so start/end syntax can be place on separate lines in the tiddler 'source' for improved readability.  Similarly, any whitespace (newlines, tabs, spaces, etc.) trailing the 'start slider' syntax or preceding the 'end slider' syntax is also suppressed.
2005.11.20 - 1.5.0 added (cookiename) syntax for optional tracking and restoring of slider open/close state
2005.11.11 - 1.4.0 added !!!!! syntax to render slider label as a header (Hn) style instead of a button/link style
2005.11.07 - 1.3.0 removed alternative syntax {{{(((}}} and {{{)))}}} (so they can be used by other formatting extensions) and simplified/improved regular expressions to trim multiple excess newlines
2005.11.05 - 1.2.1 changed name to NestedSlidersPlugin
2005.11.04 - 1.2.0 added alternative character-mode syntax {{{(((}}} and {{{)))}}}
tweaked "eat newlines" logic for line-mode {{{+++}}} and {{{===}}} syntax
2005.11.03 - 1.1.1 fixed toggling of default tooltips ("more..." and "less...") when a non-default button label is used.  code cleanup, added documentation
2005.11.03 - 1.1.0 changed delimiter syntax from {{{(((}}} and {{{)))}}} to {{{+++}}} and {{{===}}}.  changed name to EasySlidersPlugin
2005.11.03 - 1.0.0 initial public release
<<<
/%
!info
|Name|NextTiddler|
|Source|http://www.TiddlyTools.com/#NextTiddler|
|Version|2.0.0//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|create a link to close the current tiddler and open another in its place|
Usage:
<<<
{{{
<<tiddler NextTiddler with: NextTiddlerTitle linktext>>
}}}
<<<
Example
<<<
{{{<<tiddler NextTiddler with: About "About TiddlyTools">>}}}
<<tiddler NextTiddler with: About "About TiddlyTools">>
<<<
!end
!show
[[$2|$1]]<<tiddler {{
	place.lastChild.onclick=function() {
		var here=story.findContainingTiddler(this);
		story.displayTiddler(here,"$1"); // open next
		story.closeTiddler(here.getAttribute('tiddler')); // close self
		story.displayTiddler(here,"$1"); // open new one again (making it scroll to its top) <-- 2021-02-02: Statement added
	}
'';}}>>
!end
%/<<tiddler {{'NextTiddler##'+("$1"=='$'+'1'?'info':'show')}} with: [[$1]] [[$2]]>>/%  <-- 2021-01-23: Replaced single quotes with double quotes %/
Er zijn vele benamingen voor arrays (sequences) en associatieve arrays (maps) in omloop. Hier een niet geheel uitputtende inventarisatie van waar ik zelf zoal mee te maken heb gehad. Het superscript '1' bij een statisch getypeerde programmeertaal betekent dat alle elementen van de collectie van hetzelfde type moeten zijn, terwijl dat bij het superscript '+' niet het geval hoeft te zijn.

|!Immutable<br>sequence |!Static mutable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>sequence |!Dynamic mutable<br>sequence |!Static<br>map&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |!Dynamic<br>map |
|''{{sans{(Anonymous):}}}''<br>&nbsp; Lua //(succession of elements)// ''{{u3 d3 rr tt f3{1}}}'' /%|
%/<br>''{{sans{List:}}}''<br>&nbsp; Scala^^{{z{1}}}^^ //(linked list)// /%|
%/<br>''{{sans{Tuple:}}}''<br>&nbsp; Julia<br>&nbsp; Python<br>&nbsp; Scala^^+^^ /%|

%/|''{{sans{Array:}}}''<br>&nbsp; C^^{{z{1}}}^^<br>&nbsp; C#^^{{z{1}}}^^<br>&nbsp; Go^^{{z{1}}}^^<br>&nbsp; Java^^{{z{1}}}^^<br>&nbsp; Nim^^{{z{1}}}^^<br>&nbsp; Pascal^^{{z{1}}}^^<br>&nbsp; SAS/Base^^{{z{1}}}^^<br>&nbsp; SAS/SCL^^{{z{1}}}^^<br>&nbsp; Scala^^{{z{1}}}^^<br>&nbsp; V^^{{z{1}}}^^<br>&nbsp; VBScript /%|
%/<br>''{{sans{Vector:}}}''<br>&nbsp; Lisp /%|

%/|''{{sans{Array:}}}''<br>&nbsp; JavaScript<br>&nbsp; Julia<br>&nbsp; Perl<br>&nbsp; Ruby<br>&nbsp; SAS/SCL^^{{z{1}}}^^ <br>&nbsp; VBScript /%|
%/<br>''{{sans{ArrayList:}}}''<br>&nbsp; C#^^+^^<br>&nbsp; Java^^{{z{1}}}^^ /%|
%/<br>''{{sans{Compound:}}}''<br>&nbsp; Rexx //('array')// ''{{u3 d3 rr tt f3{2}}}'' /%|
%/<br>''{{sans{LinkedList:}}}''<br>&nbsp; C#^^{{z{1}}}^^//(linked list)// <br>&nbsp; Java^^{{z{1}}}^^ //(linked list)// /%|
%/<br>''{{sans{List:}}}''<br>&nbsp; C#^^{{z{1}}}^^<br>&nbsp; Lisp //(linked list)//<br>&nbsp; Python<br>&nbsp; SAS/SCL^^+^^ ''{{u3 d3 rr tt f3{3}}}'' /%|
%/<br>''{{sans{Seq(uence):}}}''<br>&nbsp; Nim^^{{z{1}}}^^<br>&nbsp; OCL^^{{z{1}}}^^ /%|
%/<br>''{{sans{Slice:}}}''<br>&nbsp; Go^^{{z{1}}}^^<br>&nbsp; V^^{{z{1}}}^^ /%|
%/<br>''{{sans{Table:}}}''<br>&nbsp; Lua //('sequence')// ''{{u3 d3 rr tt f3{4}}}'' /%|

%/|''{{sans{Anonymous type:}}}''<br>&nbsp; C#^^+^^ /%|
%/<br>''{{sans{Object:}}}''<br>&nbsp; Nim^^+^^ /%|
%/<br>''{{sans{Record:}}}''<br>&nbsp; Pascal^^+^^ /%|
%/<br>''{{sans{Struct(ure):}}}''<br>&nbsp; C^^+^^<br>&nbsp; C#^^+^^<br>&nbsp; Go^^+^^<br>&nbsp; Julia //(mutable & immutable)//<br>&nbsp; Ruby<br>&nbsp; V^^{{z{+}}}^^ /%|
%/<br>''{{sans{Tuple:}}}''<br>&nbsp; C#^^+^^<br>&nbsp; Nim^^+^^ ''{{u3 d3 rr tt f3{5}}}''<br>&nbsp; OCL^^+^^ /%/

%/|''{{sans{Compound:}}}''<br>&nbsp; Rexx //('table')// ''{{u3 d3 rr tt f3{2}}}'' /%|
%/<br>''{{sans{Dictionary:}}}''<br>&nbsp; C#^^{{z{1}}}^^<br>&nbsp; Julia<br>&nbsp; Python<br>&nbsp; VBScript /%|
%/<br>''{{sans{Directory:}}}''<br>&nbsp; Object REXX, ooRexx ''{{u3 d3 rr tt f3{6}}}'' /%|
%/<br>''{{sans{Hash:}}}''<br>&nbsp; Perl<br>&nbsp; Ruby<br>&nbsp; SAS/Base^^+^^ /%|
%/<br>''{{sans{HashMap:}}}''<br>&nbsp; Java^^+^^<br>&nbsp; Scala^^+^^ //(mutable & immutable)// /%|
%/<br>''{{sans{List:}}}''<br>&nbsp; SAS/SCL^^+^^ //('named list')// ''{{u3 d3 rr tt f3{3}}}'' /%|
%/<br>''{{sans{Map:}}}''<br>&nbsp; Go^^{{z{1}}}^^<br>&nbsp; V^^{{z{1}}}^^ /%|
%/<br>''{{sans{Object:}}}''<br>&nbsp; JavaScript /%|
%/<br>''{{sans{Table:}}}''<br>&nbsp; Lua //('record')// ''{{u3 d3 rr tt f3{4}}}''<br>&nbsp; Nim{{f3{.tables}}}^^{{z{1}}}^^<br>&nbsp; Object REXX, ooRexx ''{{u3 d3 rr tt f3{6}}}'' /%|
%/|

''{{u3 d3 rr tt f3{1}}}''&nbsp; Een zelfgeschreven komma-gescheiden opsomming van elementen of de uitkomst van een functie die meer dan één waarde retourneert, zoals {{pref hitt{''table.unpack(''//tab//'')''}}} in Lua 5.2+. Als geheel is deze opeenvolging van waarden geen zelfstandige samengestelde waarde van een bepaald Lua-gegevenstype. Zie het maar als een al dan niet gegenereerd scriptsegmentje. Ierusalimschy spreekt zelf van "a second class data structure hidden inside the language". Er kan in bepaalde gevallen wel naar de opeenvolging als geheel worden verwezen met de //vararg//-expressie ''{{hitt z{...}}}''.

''{{u3 d3 rr tt f3{2}}}''&nbsp; Alle Rexx-dialecten voorzien in een associatieve arrayvorm waarmee een sequence kan worden nagebootst door een reeks van aaneensluitende gehele getallen als sleutel te gebruiken. Daarbij moet de programmeur zelf wel bijhouden waar de grenzen liggen. Gebruikelijk is om de nummering bij ''{{{1}}}'' te laten beginnen en de hoogste indexwaarde op te slaan in het element met index ''{{{0}}}''.

''{{u3 d3 rr tt f3{3}}}''&nbsp; In SAS/SCL is een list feitelijk een sequentie van elementen die naar believen van een naam kunnen worden voorzien. Die naam behoeft binnen de list niet per se uniek te zijn. De eventuele naam kan aan de hand van het indexnummer (de telling begint bij ''{{{1}}}'') worden opgehaald, en anderzijds kan het indexnummer van een element worden verkregen door op (het zoveelste voorkomen van) de naam te zoeken.

''{{u3 d3 rr tt f3{4}}}''&nbsp; Een Lua-table is een map die ook als sequence kan worden gebruikt. De reeks elementen met een sleutel liggend op een aaneengesloten interval ''{{{1}}}'' t/m ''//{{{n}}}//'' van gehele getallen wordt automatisch opgevat als het sequencedeel van de table waarop de sequencefuncties van toepassing zijn.

''{{u3 d3 rr tt f3{5}}}''&nbsp; Mogen we een Nim-tuple tevens opvatten als een statische sequence? Het lijkt er wel op.

''{{u3 d3 rr tt f3{6}}}''&nbsp; Ik heb de 'directory' in de tabel opgenomen vanwege de afwijkende benaming. //Object REXX// en de opvolger //Open Object Rexx// bieden de volgende collection classes:
* Sequence-achtig: {{{Array}}}, {{{List}}}, {{{Queue}}}
* Map-achtig: {{{Directory}}}, {{{Table}}}
* Overig: {{{Bag}}}, {{{Relation}}}, {{{Set}}}
<<tiddler [[{}::togglesliders]]>>
+++(~ArchiMateOverview)![Overview &darr;|show overview][Overview &uarr;|hide overview]
References to documentation can be found in [[Introduction to ArchiMate]]. The aspects of ~ArchiMate's core framework are:
[img[core framework aspects|data/images/ArchiMate/ArchiMate-FrameworkAspects.png]]
The full framework looks like this:
[img[full framework|data/images/ArchiMate/ArchiMate-Framework.png]]
The //Motivation// aspect and the //Implementation & Migration// layer were added in ~ArchiMate 2.0. The //Strategy// and //Physical// layers are new since version 3.0. An ~ArchiMate model is built up from [[hierarchically classified concepts|ArchiMate: Specializations of Concept]] as displayed below.
===/%


%/+++(~ArchiMateCoreElements)![Core elements &darr;|show elements][Core elements &uarr;|hide elements]
*+++(~ArchiMateComposite)[<b>Composite elements</b> &darr;|show elements][<b>Composite elements</b> &uarr;|hide elements]
@@position:relative;top:4px;padding:20px;[img[Composite elements|data/images/ArchiMate/ArchiMateCore-Composite.png]]@@
&nbsp;
===

*+++(~ArchiMateActStruct)[<b>Active structural elements</b> &darr;|show elements][<b>Active structural elements</b> &uarr;|hide elements]
{{hup{&nbsp;
@@padding:20px;[img[Active structural elements|data/images/ArchiMate/ArchiMateCore-ActiveStructural.png]]@@ {{mib{''//@@bgcolor:#ffffaf;{{hws{B}}}@@//''usiness layer
''//@@bgcolor:#afffff;{{hws{A}}}@@//''pplication layer
''//@@bgcolor:#afffaf;{{hws{T}}}@@//''echnology layer
''//@@bgcolor:#77dd77;{{hws{P}}}@@//''hysical layer}}}}}}
&nbsp;
===

*+++(~ArchiMateBehav)[<b>Behavior elements</b> &darr;|show elements][<b>Behavior elements</b> &uarr;|hide elements]
{{hup{&nbsp;
@@padding:20px;[img[Behavior elements|data/images/ArchiMate/ArchiMateCore-Behavior.png]]@@ {{mib{''//@@bgcolor:#ffffaf;{{hws{B}}}@@//''usiness layer
''//@@bgcolor:#afffff;{{hws{A}}}@@//''pplication layer
''//@@bgcolor:#afffaf;{{hws{T}}}@@//''echnology layer}}}}}}
&nbsp;

===

*+++(~ArchiMatePassStruct)[<b>Passive structural elements</b> &darr;|show elements][<b>Passive structural elements</b> &uarr;|hide elements]
{{hup{&nbsp;
@@padding:20px;[img[Passive structural elements|data/images/ArchiMate/ArchiMateCore-PassiveStructural.png]]@@ {{mib{''//@@bgcolor:#ffffaf;{{hws{B}}}@@//''usiness layer
''//@@bgcolor:#afffff;{{hws{A}}}@@//''pplication layer
''//@@bgcolor:#afffaf;{{hws{T}}}@@//''echnology layer
''//@@bgcolor:#77dd77;{{hws{P}}}@@//''hysical layer}}}}}}
&nbsp;
===

===/%


%/+++(~ArchiMateMElements)![Motivation elements &darr;|show motivation elements][Motivation elements &uarr;|hide motivation elements]
*+++(~ArchiMateMActStruct)[<b>Active structural element</b> &darr;|show element][<b>Active structural element</b> &uarr;|hide element]
{{hup{&nbsp;
@@padding:20px;[img[Active structural element|data/images/ArchiMate/ArchiMateMotivation-Hybrid.png]]@@ {{mib{''//@@bgcolor:#ccccff;{{hws{M}}}@@//''otivation aspect}}}}}}
&nbsp;
===

*+++(~ArchiMateMotivation)[<b>Motivation elements</b> &darr;|show elements][<b>Motivation elements</b> &uarr;|hide elements]
{{hup{&nbsp;
@@padding:20px;[img[Active structural element|data/images/ArchiMate/ArchiMateMotivation-Pure.png]]@@ {{mib{''//@@bgcolor:#ccccff;{{hws{M}}}@@//''otivation aspect}}}}}}
&nbsp;
===

===/%


%/+++(~ArchiMateSElements)![Strategy elements &darr;|show strategy elements][Strategy elements &uarr;|hide strategy elements]
*+++(~ArchiMateResource)[<b>Resource</b> (structural element) &darr;|show element][<b>Resource</b> (structural element) &uarr;|hide element]
{{hup{&nbsp;
@@padding:20px;[img[Resource|data/images/ArchiMate/ArchiMateStrategy-Resource.png]]@@ {{mib{''//@@bgcolor:#f5deaa;{{hws{S}}}@@//''trategy layer}}}}}}
&nbsp;
===

*+++(~ArchiMateSBehav)[<b>Behavior elements</b> &darr;|show elements][<b>Behavior elements</b> &uarr;|hide elements]
{{hup{&nbsp;
@@padding:20px;[img[Passive structural elements|data/images/ArchiMate/ArchiMateStrategy-Behavior.png]]@@ {{mib{''//@@bgcolor:#f5deaa;{{hws{S}}}@@//''trategy layer}}}}}}
&nbsp;
===

===/%

%/+++(~ArchiMateIElements)![Implementation & migration elements &darr;|show implementation & migration elements][Implementation & migration elements &uarr;|hide implementation & migration elements]
*+++(~ArchiMateIComposite)[<b>Composite elements</b> &darr;|show elements][<b>Composite elements</b> &uarr;|hide elements]
{{hup{&nbsp;
@@padding:20px;[img[Composite elements|data/images/ArchiMate/ArchiMateImpleMig-Composite.png]]@@ {{mib{''//@@bgcolor:#e0ffe0;{{hws{T}}}@@//''echnology layer}}}}}}
&nbsp;
===

*+++(~ArchiMateIBehav)[<b>Behavior elements</b> &darr;|show elements][<b>Behavior elements</b> &uarr;|hide elements]
{{hup{&nbsp;
@@padding:20px;[img[Passive structural elements|data/images/ArchiMate/ArchiMateImpleMig-Behavior.png]]@@ {{mib{''//@@bgcolor:#ffe0e0;{{hws{I}}}@@//''mplementation & Migration layer}}}}}}
&nbsp;
===

*+++(~ArchiMateIPassStruct)[<b>Passive structural elements</b> &darr;|show elements][<b>Passive structural elements</b> &uarr;|hide elements]
{{hup{&nbsp;
@@padding:20px;[img[Passive structural elements|data/images/ArchiMate/ArchiMateImpleMig-PassiveStructural.png]]@@ {{mib{''//@@bgcolor:#ffe0e0;{{hws{I}}}@@//''mplementation & Migration layer
''//@@bgcolor:#e0ffe0;{{hws{T}}}@@//''echnology layer}}}}}}
&nbsp;
===

===/%


%/+++(~ArchiMateRelationships)![Relationships &darr;|show relationships][Relationships &uarr;|hide relationships]
A chain of relationships can be replaced by a derived (aka indirect) relationship. The type of this derived relationship equals the type of the weakest link in the chain. The order from //strong// to //weak// is:
{{hmib ws{
{{pre6{''{{high1 sans{c}}}''omposition &ndash; a''{{high1 sans{g}}}''gregation &ndash; ass''{{high1 sans{i}}}''gnment &ndash; ''{{high1 sans{r}}}''ealization}}} &ndash; {{pre6{ser''{{high1 sans{v}}}''ing &ndash; ''{{high1 sans{a}}}''ccess &ndash; i''{{high1 sans{n}}}''fluence}}} &ndash; {{pre6{''{{high1 sans{f}}}''low or ass''{{high1 sans{o}}}''ciation}}}
}}}
*+++(~ArchiMateStructRel)[<b>Structural relationships</b> &darr;|show relationships][<b>Structural relationships</b> &uarr;|hide relationships]
{{ml1em ib hup high0 ws sh{
@@padding:20px;[img[Structural relationships|data/images/ArchiMate/ArchiMateRel-Structural.png]]@@
}}} {{ml2em ib{The assignment relationship points from active structure to behavior, or from behavior to passive structure.
The old assignment symbol with dots at both sides (@@letter-spacing:-1.5pt;&bull;&mdash;&mdash;@@&bull;) is still valid, but deprecated.}}}
===

*+++(~ArchiMateDependRel)[<b>Dependency relationships</b> &darr;|show relationships][<b>Dependency relationships</b> &uarr;|hide relationships]
{{ml1em ib hup high0 ws sh{
@@padding:20px;[img[Dependency relationships|data/images/ArchiMate/ArchiMateRel-Dependency.png]]@@
}}} {{ml2em ib{The direction of the access relationship is always from active structure or behavior to passive structure.
The arrowheads don't denote the direction of the relationship, but the direction of the information flow
(so the diagram of the core framework aspects above seems to be wrong in this respect).}}}
===

*+++(~ArchiMateDynRel)[<b>Dynamic relationships</b> &darr;|show relationships][<b>Dynamic relationships</b> &uarr;|hide relationships]
{{ml1em ib hup high0 ws sh{
@@padding:20px;[img[Dynamic relationships|data/images/ArchiMate/ArchiMateRel-Dynamic.png]]@@
}}}
===

*+++(~ArchiMateOtherRel)[<b>Other relationships</b> &darr;|show relationships][<b>Other relationships</b> &uarr;|hide relationships]
{{ml1em ib hup high0 ws sh{
@@padding:20px;[img[Other relationships|data/images/ArchiMate/ArchiMateRel-Other.png]]@@
}}}
===

===/%


%/+++(~ArchiMateRConnectors)![Relationship connectors &darr;|show relationship connectors][Relationship connectors &uarr;|hide relationship connectors]
{{ml1em ib{{{mib hup high0 ws sh{
@@padding:20px;[img[Junctions|data/images/ArchiMate/ArchiMateRel-Junctions.png]]@@
}}}}}}
===
~VBScript cannot cope with null characters in strings. The methods {{{ReadLine()}}} and {{{ReadAll()}}} fail too. The best way to neutralize null characters in an input file is: read the file blockwise (blue) and replace the null characters as soon as possible (red):

<html><pre>
Const BLOCK_SIZE = 1048576  '= 1 megabyte
Dim goTextStream, gsBlock, gasSegments, gsRemainder, n, i, gsSegment

Set goTextStream = CreateObject("Scripting.FileSystemObject") _
                   .OpenTextFile(WScript.Arguments.Unnamed(0), 1)
gsRemainder = ""

<font color=green>'---- Read blocks ----'</font>
While Not goTextStream.AtEndOfStream
  gsBlock = <font color=red>Replace(<font color=blue><b>goTextStream.Read(BLOCK_SIZE)</b></font>, vbNullChar, "?")</font>
  gasSegments = Split(gsBlock, vbLf)

  <font color=green>'---- Process block segments ----'</font>
  n = UBound(gasSegments) - 1

  For i = 0 To n
    gsSegment = gsRemainder & gasSegments(i)
    If Right(gsSegment, 1) = vbCr Then
      gsSegment = Left(gsSegment, Len(gsSegment) - 1)
    End If
    WScript.Echo "«" & gsSegment & "»"
    gsRemainder = ""
  Next

  gsRemainder = gasSegments(n + 1)
Wend

If Len(gsRemainder) > 0 Then
  WScript.Echo "«" & gsRemainder & "»"
End If
goTextStream.Close</pre></html>
De [[YAML]]-boodschappenlijstjes in [[Ordered Graph Data Language|http://ogdl.org/]] (''OGDL'') van Rolf Veen (zie ook [[OGDL for Go|https://github.com/rveen/ogdl]]):
{{{
naam
  "mw. Donkersloot"
boodschappen
  "2 kilo peren"
  "1 perforator"
  "1 piano"
  "half pond nougat"
  "3 pakken Brinta"
opmerking
  "tussen de middag bezorgen"
}}}
{{{
naam "dhr. Vliegenthart"
boodschappen
  overgordijnen
  "3 kilo Engelse drop (zonder blauwe)"
  "65 g uien"
  dakpannen
  "1 waterpomptang"
  varkenshaasje
  boek auteur "W.F. Hermans"
       titel  "Ik heb altijd gelijk"
  "2 NCRV-gidsen"  # moeten waarschijnlijk wel actueel zijn!
}}}
{{{
naam
  "mw. De Wit"
boodschappen 
  "2 ons katenspek"
  "1 stuks Nieuwe Revu"
  luiwagen
  "1 ossetong"
}}}

Er is tevens in een padnavigatietaal en een schemataal voorzien. De padnavigatietaal is extreem eenvoudig:
{{pre{
''a.b.c''  = Wandel van ''a'' naar de eerste ''b'' en selecteer daar de eerste ''c''
''a.b{''//n//''}'' = Selecteer de (//n//+1)^^e^^ directe subknoop van ''a'' die ''b'' heet
''a.b{}''  = Selecteer alle directe subknopen van ''a'' die ''b'' heten
''a[''//n//'']''   = Selecteer de (//n//+1)^^e^^ directe subknoop van ''a''
}}}
{{shand tight{Onderstaande tekst uit 2010 vertelt iets over het fenomeen ''ontwerppatronen'', dat ik een rol wilde toekennen bij de aanpak van informatieverzoeken die zouden resulteren in ad hoc queries op diverse bestanden en databases op verschillende platforms. Doordat zich korte tijd later een veel interessantere aangelegenheid voordeed, is mijn initiatief na een eerste aanzetje nooit tot substantiële ontwikkeling gekomen. Desalniettemin hebben we er een niet onaardig inleidinkje in het principe van ontwerppatronen aan overgehouden, dat ik hier dan maar aan de wereld voorhoud.}}}

Deze Klikker {{shand tight{[de TiddlyWiki "SAS-klikker"]}}} beschrijft het gebruik van SAS en andere middelen bij de uitvoering van informatieverzoeken in de vorm van //ontwerppatronen//, of beter gezegd een //samenhangend stelsel// van ontwerppatronen. Het idee voor zo'n patronenstelsel -- men spreekt ook wel van patronen//taal// -- is afkomstig van de architect Christopher Alexander,{{ref{[[[1]|##1]]}}} en later door 'the Gang of Four' toegepast op het terrein van objectgeoriënteerd ontwerpen.{{ref{[[[2]|##2]]}}}

Essentieel in een patroon zijn de volgende elementen:
* Een //naam//.
* De //context// waarin het patroon kan optreden.
* Het //probleem// dat aanleiding is om het patroon te volgen.
* De //oplossing//.
* De //consequenties// van dit patroon. Nieuwe kwesties die na toepassing van het patroon rijzen, en zo de context vormen voor weer andere patronen.
Met dat laatste worden de patronen aaneengeregen tot een groter geheel. Er ontstaat op die manier een zekere gelaagdheid: van patronen op hoog niveau die de grote lijnen beschrijven naar patronen voor het kleinschaliger werk, de details. Je vindt dat terug in de titel van Alexanders boek, waarin hij van globale stedebouwkundige concepten voor de inrichting van regio's (pattern #1: 'Independent regions') afdaalt tot wat je thuis als wandversiering aan de muur hangt (pattern #253: 'Things from your life'). Zijn ambitie was om tijdloze patronen te onderkennen, patronen die zich in de praktijk bewezen hebben. Daarin slaagde hij naar eigen gevoelen maar ten dele, en eerlijkheidshalve classificeerde hij zijn patronen met respectievelijk 'waar en onveranderlijk' (84&times;), 'een goed eind op weg naar zo'n invariant maar het kan beter' (115&times;) en 'een stevig gefundeerd vermoeden' (54&times;).

Laten we hier niet al te veel pretenties hebben. Er is geen sprake geweest van enig methodologisch verantwoord onderzoek, zodat we het simpelweg houden bij 'gebaseerd op de intuïtie van mensen met enige ervaring'. Omdat de ontwerpfase er bij de ad hoc behandeling van informatieverzoeken nogal bekaaid van afkomt, met name waar het om architectonische aspecten gaat, moeten we in dit verband trouwens misschien maar liever de minder hoogdravende aanduiding //opvraag//patronen bezigen. Niettemin zijn deze patronen, al hebben ze dan betrekking op het uitvoeren van queries, toch wel wat breder inzetbaar, dus ook bij het ontwerpen van applicaties of onderdelen daarvan de moeite waard om er kennis van te nemen. Een query is tenslotte als een speciaal geval van gegevensverwerking op te vatten. En ofschoon de nadruk bij dit alles op de inzet van SAS ligt, kan men met wat erover wordt gezegd bij andere technieken eveneens zijn voordeel doen.

----
<html><a name="1">[1]</a></html> <<tiddler "Bibliografie##Alexander">>
<html><a name="2">[2]</a></html> <<tiddler "Bibliografie##GoF">>
<!--{{{-->
<div id='wwLeft' class='sy' refresh='content' tiddler='LeftControls'></div>
<div id='wwCurtain'>&nbsp;</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='wwMain'>
  <div id='sidebar'>
    <div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
    <div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
  </div>
  <div id='header' class='header'>
    <div class='headerForeground'>
      <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span><br>
      <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
    </div>
  </div>
  <div id='displayArea' role='main'>
    <div id='messageArea' class='messageArea'></div>
    <div id='tiddlerDisplay'></div>
  </div>
  <div style="line-height:20px;}">&nbsp;</div>
</div>
<div id='wwRight' class='sy' refresh='content' tiddler='RightControls'></div>
<!--}}}-->
/***
Originally, macro parameters could be quoted with ''{{hi{{{{"}}}...{{{"}}}}}}, {{hi{{{{'}}}...{{{'}}}}}}, {{hi{{{{[[}}}...{{{]]}}}}}}, {{hi{{{{{{}}}...{{tt{"""}}"""}}}}}}'' or left unquoted (and therefore space-separated). Double braces resulted in an //evaluated// parameter: e.g. {{hitt{"""{{config.options.txtUserName + '!'}}"""}}} would result in the current user's name followed by an exclamation mark.

The revised version of the {{{String.prototype.parseParams}}} function adds two alternative ways of quoting with brackets or braces, ''{{hi{{{{[=[}}}...{{{]=]}}}}}}'' and ''{{hi{{{{{={}}}...{{tt{"""}=}"""}}}}}}'', so that included double brackets or double braces don't have to be escaped with a preceding backslash anymore. Besides that, the standard double-bracket quoting generates unwanted registrations of 'missing tiddlers', which can be easily avoided now./%

%/
!!parseParams
***/
//{{{
// Parse a space-separated string of name:value parameters
// The result is an array of objects:
//   result[0] = object with a member for each parameter name, value of that member being an array of values
//   result[1..n] = one object for each parameter, with 'name' and 'value' members
String.prototype.parseParams = function(defaultName,defaultValue,allowEval,noNames,cascadeDefaults)
{
	var parseToken = function(match,p) {
		var n;
		if(match[p]) // Double quoted
			n = match[p].replace(/\\"/g,'"');
		else if(match[p+1]) // Single quoted
			n = match[p+1].replace(/\\'/g,"'");
		else if(match[p+2]) // Double-square-bracket quoted
			n = match[p+2];
		else if(match[p+3]) // Alternate-double-square-bracket quoted
			n = match[p+3];
		else if(match[p+4]) // Double-brace quoted
			try {
				n = match[p+4];
				if(allowEval && config.evaluateMacroParameters != "none") {
					if(config.evaluateMacroParameters == "restricted") {
						if(window.restrictedEval) {
							n = window.restrictedEval(n);
						}
					} else {
						n = window.eval(n);
					}
				}
			} catch(ex) {
				throw "Unable to evaluate {{" + match[p+4] + "}}: " + exceptionText(ex);
			}
		else if(match[p+5]) // Alternate-double-brace quoted
			try {
				n = match[p+5];
				if(allowEval && config.evaluateMacroParameters != "none") {
					if(config.evaluateMacroParameters == "restricted") {
						if(window.restrictedEval) {
							n = window.restrictedEval(n);
						}
					} else {
						n = window.eval(n);
					}
				}
			} catch(ex) {
				throw "Unable to evaluate {{" + match[p+5] + "}}: " + exceptionText(ex);
			}
		else if(match[p+6]) // Unquoted
			n = match[p+6];
		else if(match[p+7]) // empty quote
			n = "";
		return n;
	};
	var r = [{}];
	var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])+)\")";
	var sngQuote = "(?:'((?:(?:\\\\\')|[^'])+)')";
	var dblSquare = "(?:\\[\\[((?:\\s|\\S)*?)\\]\\])";
	var altSquare = "(?:\\[=\\[((?:\\s|\\S)*?)\\]=\\])";
	var dblBrace = "(?:\\{\\{((?:\\s|\\S)*?)\\}\\})";
	var altBrace = "(?:\\{=\\{((?:\\s|\\S)*?)\\}=\\})";
	var unQuoted = noNames ? "([^\"'\\s]\\S*)" : "([^\"':\\s][^\\s:]*)";
	var emptyQuote = "((?:\"\")|(?:''))";
	var skipSpace = "(?:\\s*)";
	var token = "(?:" + dblQuote + "|" + sngQuote + "|" + dblSquare + "|" + altSquare + "|" + dblBrace + "|" + altBrace + "|" + unQuoted + "|" + emptyQuote + ")";
	var re = noNames ? new RegExp(token,"mg") : new RegExp(skipSpace + token + skipSpace + "(?:(\\:)" + skipSpace + token + ")?","mg");
	var match;
	do {
		match = re.exec(this);
		if(match) {
			var n = parseToken(match,1);
			if(noNames) {
				r.push({name:"",value:n});
			} else {
				var v = parseToken(match,10);
				if(v == null && defaultName) {
					v = n;
					n = defaultName;
				} else if(v == null && defaultValue) {
					v = defaultValue;
				}
				r.push({name:n,value:v});
				if(cascadeDefaults) {
					defaultName = n;
					defaultValue = v;
				}
			}
		}
	} while(match);
	// Summarise parameters into first element
	var t;
	for(t=1; t<r.length; t++) {
		if(r[0][r[t].name])
			r[0][r[t].name].push(r[t].value);
		else
			r[0][r[t].name] = [r[t].value];
	}
	return r;
};
//}}}
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Vervolg van [[Iteratiemechanismen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''

''{{fred sans{~!~ Deze tiddler moet nog geschreven worden. ~!~}}}''

De Python-functie {{tt t{enumerate}}} is vergelijkbaar met de deliverers {{tt t{ipairs}}} en {{tt t{pairs}}} in Lua, maar verschilt wel. Voor array-achtige collecties doen {{tt t{enumerate}}} en {{tt t{ipairs}}} hetzelfde. Voor dictionary-achtige collecties levert {{tt t{enumerate}}} de index en de sleutel, terwijl {{tt t{pairs}}} de sleutel en de waarde levert. Met de combinatie
{{pre{
for i, (k, v) in ''enumerate''({'A': 10, 'B': 11, 'C': 12}.''items''()):
    print(i, k, v)
}}}/%
%/komen alle drie de iteratievariabelen beschikbaar.
{{lift{
!!Line width
@@line-height:32px;{{sans{
|plain |k
| 1 | 1.5 | 2 | 3 | 4 | 6 | 8 | 11 | 16 | 22 |px |
| <html><img src="core/black.png" width=20 height=1></html> | <html><img src="core/black.png" width=20 height=1.5></html> | <html><img src="core/black.png" width=20 height=2></html> | <html><img src="core/black.png" width=20 height=3></html> | <html><img src="core/black.png" width=20 height=4></html> | <html><img src="core/black.png" width=20 height=6></html> | <html><img src="core/black.png" width=20 height=8></html> | <html><img src="core/black.png" width=20 height=11></html> | <html><img src="core/black.png" width=20 height=16></html> | <html><img src="core/black.png" width=20 height=22></html> |
}}}@@{{_{
!!Line length
{{sans{
|plain |k
| 1, 2, 5, 10 px|<html><img src="core/black.png" width=1 height=2><html><html><img src="core/transparent.png" width=1 height=1><img src="core/black.png" width=2 height=2><img src="core/transparent.png" width=1 height=1><html><img src="core/black.png" width=5 height=2><img src="core/transparent.png" width=1 height=1><html><img src="core/black.png" width=10 height=2></html> |
|          10 px|<html><img src="core/black.png"   width=10 height=2></html> |
|          20 px|<html><img src="core/black.png"   width=20 height=2></html> |
|          50 px|<html><img src="core/black.png"   width=50 height=2></html> |
|         100 px|<html><img src="core/black.png"  width=100 height=2></html> |
|         200 px|<html><img src="core/black.png"  width=200 height=2></html> |
|         500 px|<html><img src="core/black.png"  width=500 height=2></html> |
|        1000 px|<html><img src="core/black.png" width=1000 height=2></html> |
}}}
}}}
{{{XXXXXXXXXXXXXXXXXXXXXXXX}}} -- 24 letters
{{tt{@@font-size:10pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 10 pt
{{tt{@@font-size:11pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 11 pt
{{tt{@@font-size:11.2pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 11.2 pt
{{tt{@@font-size:11.5pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 11.5 pt
{{tt{@@font-size:11.75pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 11.75 pt
{{tt{@@font-size:11.76pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 11.76 pt
{{tt{@@font-size:11.8pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 11.8 pt
{{tt{@@font-size:12pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 12 pt
{{tt{@@font-size:16px;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 16 px
{{tt{@@font-size:12.5pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 12.5 pt
{{tt{@@font-size:12.93pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 12.93 pt
{{tt{@@font-size:13pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 13 pt
{{tt{@@font-size:14pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 14 pt
{{tt{@@font-size:15pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 15 pt
{{tt{@@font-size:16pt;XXXXXXXXXXXXXXXXXXXXXXXX@@}}} -- font-size 16 pt
<html><img src="core/black.png"  width=100 height=2></html> -- 100 px
<html><img src="core/black.png"  width=200 height=2></html> -- 200 px
<html><img src="core/black.png"  width=240 height=2></html> -- 240 px
<html><img src="core/black.png"  width=300 height=2></html> -- 300 px
<html><img src="core/black.png"  width=320 height=2></html> -- 320 px
<html><img src="core/black.png"  width=500 height=2></html> -- 500 px

<html><div style="float:left; background-color:#cccccc; width:96px; font-family:IBM Plex Mono; font-size:12pt;">XXXXXXXXXX</div><div>&nbsp;&mdash; 96 px</div></html>
<html><div style="float:left; background-color:#cccccc; width:72pt; font-family:IBM Plex Mono; font-size:12pt;">XXXXXXXXXX</div><div>&nbsp;&mdash; 72 pt</div></html>
<html><div style="float:left; background-color:#cccccc; width:6pc;  font-family:IBM Plex Mono; font-size:12pt;">XXXXXXXXXX</div><div>&nbsp;&mdash;  6 pc</div></html>
<html><div style="float:left; background-color:#cccccc; width:6rem; font-family:IBM Plex Mono; font-size:12pt;">XXXXXXXXXX</div><div>&nbsp;&mdash; 6 rem, depends on browser settings</div></html>
<html><div style="float:left; background-color:#cccccc; width:1in;  font-family:IBM Plex Mono; font-size:12pt;">XXXXXXXXXX</div><div>&nbsp;&mdash;  1 in</div></html>
{{{
* Get-ExecutionPolicy -List  => list of policies, like:

          Scope ExecutionPolicy
          ----- ---------------
  MachinePolicy       Undefined
     UserPolicy       Undefined
        Process       Undefined
    CurrentUser    RemoteSigned
   LocalMachine       AllSigned

* Set-ExecutionPolicy -ExecutionPolicy <PolicyName>                 => new policy for LocalMachine
  Set-ExecutionPolicy -ExecutionPolicy <PolicyName> -Scope <scope>  => new policy for <scope>

* <PolicyName>  Consequences
  ------------  ------------------------------------------------------------------------------------------
  Restricted    Prevents running of all scripts
  AllSigned     Allows running of scripts signed by a trusted publisher, prompts when no trusted publisher
  RemoteSigned  Allows running of unsigned scripts on local computer or I-downloaded but unblocked scripts
  Unrestricted  Allows running of unsigned scripts, but warns when I-downloaded 
  Bypass        Nothing is blocked, no warnings or prompts
  Undefined     No execution policy

  (I-downloaded = downloaded from the Internet; unblocked = unblocked by Unblock-File cmdlet)
}}}
See https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-6&viewFallbackFrom=powershell-Microsoft.PowerShell.Core
/***
|Name|PreviewPlugin|
|Source|http://www.TiddlyTools.com/#PreviewPlugin|
|Documentation|http://www.TiddlyTools.com/#PreviewPluginInfo|
|Version|1.8.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|add key-by-key wikified preview to any textarea input field|
Provides key-by-key ''LIVE PREVIEW'' of //formatted// tiddler content as you type input into a textarea (multi-line) edit field.
!!!!!Documentation
>see [[PreviewPluginInfo]]
!!!!!Configuration
<<<
Automatically freeze preview updates when a tiddler takes more than <<option txtPreviewAutoFreeze>> milliseconds to render.
<<<
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.11.18 [1.8.1] in config.commands.previewTiddler, changed alt command text to use character-based "psuedo-checkbox" instead of embedded html fragment
2007.09.27 [1.8.0] split TidIDE preview functionality into separate stand-alone plugin (see [[TidIDEPlugin]]).  
|please see [[TidIDEPluginInfo]] for additional revision details|
2006.04.15 [0.5.0] Initial ALPHA release. Converted from inline script.
<<<
!!!!!Code
***/
// // version info
//{{{
version.extensions.PreviewPlugin= {major: 1, minor: 8, revision: 1, date: new Date(2007,11,18)};
//}}}

// //  macro definition
//{{{
if (config.options.txtPreviewAutoFreeze==undefined)
	config.options.txtPreviewAutoFreeze=250; // limit (in milliseconds) for auto-freezing preview display

config.macros.preview = {
	renderMsg: "rendering preview...",
	timeoutMsg: " (> %0ms)",
	freezeMsg: " - preview is frozen.  Press [refresh] to re-display.",
	handler: function(place,macroName,params) {
		var hide=params[0]=="hide"; if (hide) params.shift();
		var field=params[0];
		var height=params[1]; if (!height) height=15;
		var here=this.findContainingForm(place);
		if (!here) here=story.findContainingTiddler(place);
		if (!here) here=place.parentNode;
		if (!here) here=place;
		var elems=here.getElementsByTagName("textarea");
		if (field) for (var e=0; e<elems.length; e++)  // find matching textarea (by fieldname)
			if (elems[e].getAttribute("edit")==field) var ta=elems[e];
		else
			if (elems.length) var ta=elems[elems.length-1]; // default to last rendered text area
		if (!ta) {
			var elems=here.getElementsByTagName("input");
			if (field) for (var e=0; e<elems.length; e++)  // find matching input field (by fieldname)
				if (elems[e].getAttribute("edit")==field) var ta=elems[e];
			else
				if (elems.length) var ta=elems[elems.length-1]; // default to last rendered input field
		}
		if (!ta) return false; // no textarea or input field found... do nothing...
		var id=(new Date().getTime()).toString()+Math.random(); // unique instance ID
		ta.id=id+"_edit";
		ta.setAttribute("previewid",id+"_preview");
		ta.saved_onkeyup=ta.onkeyup;
		ta.onkeyup=function(ev) {
			if (this.saved_onkeyup) this.saved_onkeyup.apply(this,arguments);
			config.macros.preview.render(this.id,this.getAttribute("previewid"));
		}
		var html=this.html.replace(/%previd%/g,id+"_preview")
		html=html.replace(/%srcid%/g,id+"_edit");
		html=html.replace(/%hide%/g,hide?"none":"block");
		html=html.replace(/%limit%/g,config.options.txtPreviewAutoFreeze);
		html=html.replace(/%frozen%/g,hide?"checked":"");
		html=html.replace(/%height%/g,height);
		html=html.replace(/%halfheight%/g,height/2);
		createTiddlyElement(place,"span").innerHTML=html;
		this.render(id+"_edit",id+"_preview");
	},
	findContainingForm: function(e) {
		while (e && e.nodeName.toLowerCase()!="form") e=e.parentNode;
		return e;
	},
	render: function(srcid,previd,force) {
		var value=document.getElementById(srcid).value;
		var panel=document.getElementById(previd);
		var f=this.findContainingForm(panel);
		if (!f || (f.freeze.checked && !force)) return;
		var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
		p.innerHTML="";
		f.status.value=this.renderMsg;
		var start=new Date();
		wikify(value.replace(/\r/g,''),p);
		var end=new Date();
		this.renderDOM(previd);
		this.renderHTML(previd);
		f.status.value="elapsed: "+(end-start+1)+"ms";
		// automatically suspend preview updates for slow rendering tiddlers
		if (end-start+1>config.options.txtPreviewAutoFreeze) {
			f.freeze.checked=true;
			f.status.value+=this.timeoutMsg.format([config.options.txtPreviewAutoFreeze]);
		}
		if (f.freeze.checked) f.status.value+=this.freezeMsg;
	},
	renderDOM: function(id) {
		var panel=document.getElementById(id);
		var f=this.findContainingForm(panel); if (!f) return;
		var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
		var height=p.getAttribute("height");
		p.style.height=((f.dom.checked||f.html.checked)?height/2:height)+"em";
		if (f.dom.checked) d.value=this.getNodeTree(p,"|  ");
		if (!d.style||!h.style) return;
		d.style.height=height/2+"em";
		d.style.display=f.dom.checked?"inline":"none";
		d.style.width=f.html.checked?"49.5%":"100%";
		h.style.width=f.dom.checked?"49.5%":"100%";
	},
	renderHTML: function(id) {
		var panel=document.getElementById(id);
		var f=this.findContainingForm(panel); if (!f) return;
		var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
		var height=p.getAttribute("height");
		p.style.height=((f.dom.checked||f.html.checked)?height/2:height)+"em";
		if (f.html.checked) h.value=this.formatHTML(p.innerHTML);
		if (!h.style||!d.style) return;
		h.style.height=height/2+"em";
		h.style.display=f.html.checked?"inline":"none";
		h.style.width=f.dom.checked?"49.5%":"100%";
		d.style.width=f.html.checked?"49.5%":"100%";
	},
	formatHTML: function(txt) {
		if (config.browser.isIE) return txt; // BYPASS - 4/24/2006 due to IE hang problem.  Will fix later...
		var out="";
		var indent="";
		var level=0;
		for (var i=0;i<txt.length;i++) {
			var c=txt.substr(i,1);
			if (c=="<") {
					if (txt.substr(i+1,1)=="/")  indent=indent.substr(0,indent.length-2);
				out+="\n"+indent;
				if (txt.substr(i+1,1)!="/" && txt.substr(i+1,3)!="br>" && txt.substr(i+1,2)!="p>" && txt.substr(i+1,3)!="hr>")  indent+="  ";
			}
			out+=c;
				if (c=="\n")
				out+=indent;
			if (c==">" && txt.substr(i+1,1)!="<")
				out+="\n"+indent;
		}
		return out;
	},
	getNodeTree: function(theNode,theIndent,showPath,inline,thePrefix,thePath)
	{
		if (!theNode) return "";
		if (!thePrefix) thePrefix="";
		if (!thePath) thePath="";
		var mquote='"'+(inline?"{{{":"");
		var endmquote=(inline?"}}}":"")+'"';
		// generate output for this node
		var out = thePrefix;
		if (showPath && thePath.length)
				out += (inline?"//":"")+thePath.substr(1)+":"+(inline?"//":"")+"\r\n"+thePrefix;
		if (theNode.className=="DOMViewer")
			return out+'[DOMViewer]\r\n'; // avoid self-referential recursion
		out += (inline?"''":"")+theNode.nodeName.toUpperCase()+(inline?"''":"");
		if (theNode.nodeName=="#text")
			out += ' '+mquote+theNode.nodeValue.replace(/\n/g,'\\n')+endmquote;
		if (theNode.className)
			out += ' class='+mquote+theNode.className+endmquote;
		if (theNode.type)
			out += ' type='+mquote+theNode.type+endmquote;
		if (theNode.id)
			out += ' id='+mquote+theNode.id+endmquote;
		if (theNode.name)
			out += " "+theNode.name+(theNode.value?"="+mquote+theNode.value+endmquote:"");
		if (theNode.href)
			out += ' href='+mquote+theNode.href+endmquote;
		if (theNode.src)
			out += ' src='+mquote+theNode.src+endmquote;
		if (theNode.attributes && theNode.getAttribute("tiddlyLink")!=undefined)
			out += ' tiddler='+mquote+theNode.getAttribute("tiddlyLink")+endmquote;
		out += "\r\n";
		// recursively generate output for child nodes
		thePath=thePath+"."+theNode.nodeName.toLowerCase();
		thePrefix=theIndent+thePrefix;
		for (var i=0;i<theNode.childNodes.length;i++)
		{
			var thisChild=theNode.childNodes.item(i);
			var theNum=(inline?"~~":"(")+(i+1)+(inline?"~~":")");
			out += this.getNodeTree(thisChild,theIndent,showPath,inline,thePrefix,thePath+theNum);
		}
		return out;
	},
	html: " <form style='width:100%'><span id='%previd%' editID='%srcid%' style='display:%hide%'><div class='viewer' \
			height='%height%' style='margin:0;margin-top:.5em;height:%height%em;overflow:auto;white-space:normal'> \
			&nbsp; \
			</div> \
		<!-- DOM and HTML viewers --> \
		<textarea name=domview cols=60 rows=12 wrap=off \
			onfocus='this.select()' style='display:none;width:100%;height:%halfheight%em;'></textarea><!-- \
		--><textarea name=htmlview cols=60 rows=12 wrap=off \
			onfocus='this.select()' style='display:none;width:100%;height:%halfheight%em;'></textarea> \
		<!-- status line, preview option checkboxes, run/refresh buttons --> \
		<table width='100%' style='border:0;padding:0;margin:0'><tr style='border:0;padding:0;margin:0'> \
		<td style='border:0;padding:0;margin:0'><!-- \
			--><input type=text name=status style='padding:0;width:100%;' \
				title='ELAPSED: time (in milliseconds) used to render tiddler content in preview display'><!-- \
		--></td><td style='width:1%;border:0;padding:0;margin:0;'><!-- \
			--><input type=text name=limit size='6' maxlength='6' style='padding:0;width:5em;text-align:center' \
				value='%limit%ms' title='TIME LIMIT: maximum rendering time (in milliseconds) before auto-freezing preview' \
				onfocus='this.select()' \
				onchange='var val=this.value.replace(/[^0-9]/g,\"\"); if (!val.length) val=this.defaultValue; \
					this.value=val+\"ms\"; config.options.txtPreviewAutoFreeze=val; saveOptionCookie(\"txtPreviewAutoFreeze\"); \
					this.form.freeze.checked=false; config.macros.preview.render(\"%srcid%\",\"%previd%\",true);'><!-- \
		--></td><td style='width:1%;border:0;padding:0;margin:0;'><!-- \
			--><input type=text name=height size='4' maxlength='4' style='padding:0;width:4em;text-align:center' \
				value='%height%em' title='HEIGHT: size (in \"ems\") of preview area, including controls' \
				onfocus='this.select()' \
				onchange='var val=this.value.replace(/[^0-9]/g,\"\");  if (!val.length) val=this.defaultValue; \
					this.value=val+\"em\"; document.getElementById(\"%previd%\").firstChild.setAttribute(\"height\",val); \
					config.macros.preview.render(\"%srcid%\",\"%previd%\",true)'><!-- \
		--></td><td style='width:1%;border:0;padding:0;margin:0;text-align:right;white-space:nowrap'> \
			<input type=checkbox name=dom style='display:inline;width:auto;margin:1px;' \
				title='show Document Object Model (DOM) information' \
				onclick='config.macros.preview.renderDOM(\"%previd%\");'>DOM \
			<input type=checkbox name=html style='display:inline;width:auto;margin:1px;' \
				title='show rendered HTML' \
				onclick='config.macros.preview.renderHTML(\"%previd%\");'>HTML \
			<input type=checkbox name=freeze style='display:inline;width:auto;margin:1px;' %frozen% \
				title='do not update preview display as changes are made' \
				onclick='var p=document.getElementById(\"%previd%\");  \
					if (this.checked) this.form.status.value+=config.macros.preview.freezeMsg; \
					else config.macros.preview.render(\"%srcid%\",\"%previd%\",true);'>freeze \
			<input type=button style='display:inline;width:auto;' value='refresh' \
				title='update preview display' \
				onclick='config.macros.preview.render(\"%srcid%\",\"%previd%\",true)'> \
		</td></tr></table> \
		</span></form>"
}
//}}}

// // toolbar definition
//{{{
config.commands.previewTiddler = {
	text: 'preview',
	tooltip: 'show key-by-key preview',
	text_alt: '\u221Apreview',
	handler: function(event,src,title) {
		var here=story.findContainingTiddler(src); if (!here) return;
		var elems=here.getElementsByTagName("span");
		for (var e=0; e<elems.length; e++) {
			if (elems[e].getAttribute("editid")) {
				var show=elems[e].style.display=="none";
				src.innerHTML=show?this.text_alt:this.text;
				elems[e].style.display=show?"block":"none";
				config.macros.preview.findContainingForm(elems[e]).freeze.checked=!show;
				if (show) config.macros.preview.render(elems[e].getAttribute("editid"),elems[e].id);
			}
		}
		return false;
	}
};
//}}}
/***
|Name|PreviewPluginInfo|
|Source|http://www.TiddlyTools.com/#PreviewPlugin|
|Documentation|http://www.TiddlyTools.com/#PreviewPluginInfo|
|Version|1.8.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for [[PreviewPlugin]]|
Provides key-by-key ''LIVE PREVIEW'' of //formatted// tiddler content as you type input into a textarea (multi-line) edit field.
!!!!!Usage
<<<
Syntax: (in tiddler content)
{{{
<<preview hide fieldname height>>
}}}
//OR// (in [[EditTemplate]])
{{{
<span macro='preview hide fieldname height'></span>
}}}
where:
* 'hide' (optional)<br>is a keyword that causes the preview display to be initially hidden when created.  This is typically used in an [[EditTemplate]] definition, in conjunction with the 'previewTiddler' toolbar syntax (see below).
* fieldname (optional)<br>specifies the name of the tiddler field that is being previewed.  It corresponds to the fieldname specified in the {{{<span class='editor' macro='edit fieldname height'></span>}}} syntax used to define the textarea edit field, and is used to locate and access the source content that is to be previewed.  When omitted, the previewer will automatically associate itself with the last textarea control that precedes it in the rendered tiddler editor display.
* height (optional)<br>defines the total height of the previewer display (including the status line and controls), using CSS "em" (line height) measurements.  The default height value is "15em" (i.e., approximately 15 lines of standard-sized text)

In addition to the preview macro itself, you can place the following in your [[EditTemplate]] to add a tiddler toolbar command that enables you to toggle the preview display once it has been created:
{{{
<span class='toolbar' macro='toolbar previewTiddler'></span>
}}}
when clicked, this command will show/hide ALL preview controls that are displayed in the current tiddler.  Note that, when desired, you can also embed this toolbar command directly into a tiddler by entering the "{{{<<toolbar previewTiddler>>}}}" syntax in the tiddler source.
<<<
!!!!!Examples
<<<
in [[EditTemplate]]:
{{{
<div class='editor' macro='edit foobar 5'></div>
<div class='editor' macro='preview hide foobar 10'></div>
}}}
OR, embedded in tiddler content:
{{{
<<edit foobar 5>><<preview foobar 10>>
}}}
{{smallform{
<<edit foobar 5>><<preview foobar 10>>}}}
By default, the preview display is automatically rendered each time a key is typed into the tiddler content edit field.  As soon as changes are entered, they will be instantly visible within the preview display.  Unfortunately, the partial tiddler source definitions that occur //during// editing may somtimes cause rendering problems, and some exceptionally complex tiddlers make take an unusually long amount of time to completely render their content.   In such cases, key-by-key display updates are undesirable or impractical.

You can select the ''freeze'' checkbox to suspend automatic key-by-key preview display updates.  The preview display will not be re-rendered again until you press the ''refresh'' button or clear the 'freeze' checkbox.  The preview display will also automatically freeze whenever the //rendering time// exceeds a pre-determined time limit (see configuration section), specified in milliseconds.  Note: the ''actual elapsed time'' used to process and render any given content is reported in the preview "status bar" whenever that content is previewed.

In addition to a 'wikified' preview, the previewer display can show a ''DOM viewer'' and/or an ''HTML viewer'' that are also updated with each keystroke.  These text-based displays can be helpful while attempting to correct or enhance the formatting of tiddler content, especially when complex combinations of wiki-syntax produce unexpected or undesired results.
<<<
Met onderstaande query heb ik destijds vanuit SAS de primaire sleutels van alle tabellen in een rapportagedatabase (die allang niet meer bestaat) opgevraagd:
{{{
proc sql;
  create table msm.keys_20151023 as
    select * from connection to db2 (
      select k.ixname
           , k.ixcreator
           , i.tbname
           , i.tbcreator
           , i.colcount
           , k.colname
           , k.colseq
        from sysibm.sysindexes i
           , sysibm.syskeys    k
        where i.uniquerule = 'P'
          and i.name       = k.ixname
          and i.creator    = k.ixcreator
        order by i.tbcreator
               , i.tbname
               , k.colseq
               , k.colname
    );
quit;
}}}
De libref {{{msm}}} verwijst naar mijn (evenmin nog bestaande) SAS-library, dus men kon {{{msm.keys_20151023}}} zelf raadplegen. Helaas waren niet voor alle tabellen expliciet primaire sleutels gedefinieerd. Overigens staan primaire sleutels ook aangegeven in de kolom {{{KEYSEQ}}} van {{{SYSIBM.SYSCOLUMNS}}}. Na vier maanden was deze query achterhaald door mijn ~SAS-macro {{{DB2TSTRU}}}, die per tabel alle kolommen, sleutels en indexen met hun eigenschappen uitlijstte. Voor elke tabel werd zo uiteindelijk een worksheet in een Excel-bestand geproduceerd. In zo'n bestand was het wat gemakkelijker bladeren dan rechtstreeks in de database op het mainframe.
The running script's own process ID can be determined this way:
{{{
Function GetOwnPID()
  GetOwnPID = GetObject("winmgmts:root\cimv2") _
              .Get("Win32_Process.Handle='" & _
                   CreateObject("WScript.Shell").Exec("mshta.exe").ProcessID & _
                   "'") _
              .ParentProcessID
End Function
}}}
(Based on http://www.webmasterkb.com/Uwe/Forum.aspx/vbscript/752/Process-id-How-do-I-determine-my-own-in-VBScript)
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Vervolg van [[Iteratiemechanismen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''

{{ml3em mr3em{[img[data/images/SC iterator-a-la-Python.png]]}}} [[Legenda|Structuurdiagrammen à la Constantine]]

<<tiddler [[{}::togglesliders]]>> In dit model wordt de providerrol vervuld door een {{sans t{iterator}}}, waar ook de statusadministratie is opgeslagen. De delivery wordt verzorgd door {{sans t{next}}}, een method van de {{sans t{iterator}}}. Het linker structuurdiagram toont hoe het er in Python aan toegaat. Wanneer {{sans t{next}}} vaststelt dat er genoeg is geïtereerd, grijpt deze method in door onder afkondiging van een uitzonderingstoestand het bijltje erbij neer te gooien. Dit wordt door de {{sans t{for loop}}} opgevangen en afgehandeld. Omdat deze signalering niet via de returnwaarde van {{sans t{next}}} loopt, is er in het schema een aparte pijl voor getekend met een zwart bolletje bij het vertrekpunt, om aan te geven dat de //verdere besturing onvoorwaardelijk aan de aanroeper wordt overgelaten//.

In Ruby en Lua heb ik dit model wat vereenvoudigd volgens het rechter schema. Hier geeft {{sans t{next}}} zonder veel ophef via de returnwaarde {{tt t{nil}}} door dat de provider door zijn materiaal heen is. De returnwaarde dient dus mede als stuurgegeven, vandaar het hybride geleidepijltje bij de aanroep door de {{sans t{while loop}}}. Het kan in deze twee talen best met wat meer vuurwerk, maar ik wilde de betreffende scripts geconcentreerd houden op de provider. Wie toch in zulk vuurwerk geïnteresseerd is, kan het bezichtigen in de Ruby- en Lua-scripts bij [[Geïntegreerde provider/deliverer/pilot à la Ruby]]. Ik heb nog wel meer gestroomlijnd. Dat betreft aspecten die niet in de schema's tot uitdrukking zijn gebracht./%

%/
!!Python
De kerngedachte bij Python's iteratorconcept is, dat de provider steeds één element van een achterliggende collectie op afroep beschikbaar stelt aan een afnemer. Dat hoeft niet per se steeds dezelfde afnemer te zijn. De achterliggende collectie kan reëel of virtueel zijn. Zo zijn {{tt t{list}}}- of {{tt t{dict}}}-objecten reële collecties. In een virtuele collectie worden de elementen pas aangemaakt op het moment dat erom gevraagd wordt, zoals bij een {{tt t{range}}}-object. In deze drie voorbeelden is de voorraad eindig. Er zijn standaard al iteratoren in Python ingebouwd voor deze collecties, zoals {{tt t{list_iterator}}}, {{tt t{dict-keyiterator}}} en {{tt t{range_iterator}}}, om de drie meest voor de hand liggende te noemen. Ze leveren elk element slechts één keer. Na het laatste element is de desbetreffende iterator uitgeput en heb je er niets meer aan. Maar je kunt voor dezelfde list, dictionary of range wel weer een nieuwe iterator instantiëren.

Er schuilt nog ander belangrijk idee achter het iterator&shy;concept. Hierboven heb ik drie typen iterators opgesomd. Drie classes dus, die geen drieën afstammen van een class {{tt t{iterator}}} of iets dergelijks. In Python is een iterator niet zozeer een class, als wel een {{pref{//ontwerppatroon//{{ref{&#x200a;[[[1]|##1]]}}},}}} een //interface// of, zoals de documentatie het treffend noemt, een [[iteratieprotocol|'Iterabiliteit' in Python]], dat indien goed gevolgd een object vanzelf tot een iteratorobject maakt. Ga dus niet louter op de naam van een class of object af, maar kijk wat erin zit.

Als je zelf een iteratorclass gaat bouwen, zijn de mogelijkheden schier onbeperkt. Je kunt bijvoorbeeld een oneindige sequentie van natuurlijke getallen in natuurlijke volgorde maken. Dan raakt de iterator in theorie nooit door zijn voorraad heen. In de praktijk wel, want op zeker moment is een geproduceerd getal te groot om nog in het computer&shy;geheugen te passen. Een cyclische iterator dan. Bijvoorbeeld eentje die de modulo-16 van alle natuurlijke getallen levert. Die gaat tenminste door totdat je computer versleten is. Het hoeven trouwens geen getallen in een vaste volgorde te zijn. Een dobbelsteen is ook goed uit te voeren als een iterator. Ik heb me in onderstaande scripts beperkt tot een zelfgebouwde teller {{tt t{1}}}, {{tt t{2}}}, {{tt t{3}}}, {{tt t{4}}} die er vervolgens de brui aan geeft.

|plain |k
|Bij zelfbouw weet je precies wat je erin stopt. Maar hoe zit het met de ingebouwde iteratoren ten behoeve van eveneens ingebouwde collecties? Om te beginnen kunnen we onderscheid maken tussen een ingebouwde collectie-iterator (in de vorm van een method van die collectie) en een externe collectie-iterator (in de vorm van een apart object). Ruby heeft alle iterabele collecties van [[ingebouwde iteratoren|Geïntegreerde provider/deliverer/pilot à la Ruby]] voorzien, volgens het patroon in nevenstaand schema. |[img[data/images/SC internal iterator.png]] |

Python gooit het juist over een andere boeg en werkt vooral met externe collectie-iteratoren. Omdat het {{tt t{for}}}-statement ze zelfs automatisch aanmaakt, zijn alle ingebouwde iterabele objecten uitgerust met een {{tt t{[[__iter__|'Iterabiliteit' in Python]]}}}-method die aangeeft van welke ingebouwde class er zo'n iterator&shy;object moet worden geinstantieerd. De vraag is: hoe werkt zo'n ingebouwde iterator dan wel? Theoretisch zijn er op het eerste gezicht twee mogelijkheden:
* Schema ''A'': De iterator heeft alle relevante informatie uit de achterliggende collectie gekopieerd en kan vervolgens geheel onafhankelijk van die collectie opereren. Dat houdt in, dat tussentijdse veranderingen in de oorspronkelijke collectie geen invloed hebben op de iteratiewaarden die de {{tt t{"""__next__"""}}}-method van de iterator afgeeft.
* Schema ''B'': In de iterator is een referentie naar de achterliggende collectie opgenomen. De iterator levert via {{tt t{"""__next__"""}}} iteratiewaarden die gebaseerd zijn op de //actuele// waarden in die collectie. Tussentijdse mutaties in die collectie werken tijdens het itereren dus door in het resultaat.

{{ml3em mr3em{[img[data/images/SC external iterator.png]]}}}

Er kan zich tussen de iterator en de iterabele collectie echter nog een tussenobject ophouden, of zelfs een hele keten van tussenobjecten. Ik heb hier twee van de vele mogelijke gevallen in kaart gebracht:
* In schema ''C'' wordt het intermediair alleen maar even bij de instantiëring van de iterator gebruikt om de weg naar collectie te vinden en deze route op te slaan. Het inter&shy;mediair doet tijdens het itereren geen dienst meer.
* In schema ''D'' maakt de iterator gebruik van de keten van referenties naar inter&shy;mediair en vervolgens collectie./%
%/
Even genoeg theorie zo en eerst maar eens heel concreet aandringen: wat heeft Python aan externe iteratoren te bieden? Terechte vraag, moeilijk te beantwoorden helaas. Ik heb tot nu toe [[ruim meer dan twintig verschillende ingebouwde iterator-classes|'Iterabiliteit' in Python]] gevonden, en ze zijn allemaal ongedocumenteerd. Een keur aan mooie bestemmingen voor avontuurlijke ontdekkings&shy;reizigers. Ik heb zelf alvast enkele expedities ondernomen:/%
%/
|!Collectietype |!Intermediairtype                               |!Iteratortype                                                                    |!Iteratormodel  |
|''{{{list}}}'' |                                                |//{{{L}}}//{{pref tt{."""__iter__"""() }}} &rarr; ''{{{list_iterator}}}''        | ''B''          |
|''{{{list}}}'' |                                                |{{{reverse(}}}//{{{L}}}//{{pref tt{)   }}} &rarr; ''{{{list_reverseiterator}}}'' | ''B''          |
|''{{{dict}}}'' |                                                |//{{{D}}}//{{pref tt{."""__iter__"""() }}} &rarr; ''{{{dict_keyiterator}}}''     | ''B''          |
|''{{{dict}}}'' |//{{{D}}}//{{pref tt{.keys()  }}} &rarr; ''{{{dict_keys}}}''  |//{{{DK}}}//{{{.__iter__()}}} &rarr; ''{{{dict_keyiterator}}}''  | ''C'' of ''D'' ? |
|''{{{dict}}}'' |//{{{D}}}//{{pref tt{.items() }}} &rarr; ''{{{dict_items}}}'' |//{{{DI}}}//{{{.__iter__()}}} &rarr; ''{{{dict_itemiterator}}}'' | ''C'' of ''D'' ? |
|''{{{dict}}}'' |//{{{D}}}//{{{.values()}}} &rarr; ''{{{dict_values}}}'' |//{{{DV}}}//{{{.__iter__()}}} &rarr; ''{{{dict_valueiterator}}}''      | ''C'' of ''D'' ? |
Over de intermediairs merkt de 3.11-documentatie op:
>The objects returned by {{tt t{dict.keys()}}}, {{tt t{dict.values()}}} and {{tt t{dict.items()}}} are //view objects//. They provide a dynamic view on the dictionary’s entries, which means that when the dictionary changes, the view reflects these changes.{{ref{&#x200a;[[[2]|##2]]}}}
In de verdere uitleg duikt weer een andere class op: het view-attribuut ''{{{mapping}}}'' verwijst naar een instance van de class ''{{tt{[[mappingproxy|MappingProxyType]]}}}'', waarvan de {{tt t{"""__iter__"""}}}-method een {{tt t{dict_keyiterator}}} oplevert en de methods {{tt t{keys}}}, {{tt t{items}}} en {{tt t{values}}} net zo werken als bij de dictionary zelf. Het is dus mogelijk vanuit een dictionary een eindeloze sliert van views en mapping&shy;proxies aan te leggen. De module ''{{{types}}}'' voorziet in een identifier {{tt t{types.MappingProxyType}}}, maar laat de drie views in de kou staan.

{{lf ml3em mr3em{[img[data/images/SC iterator-a-la-Python-from-iterable.png]]}}}{{clear{Inmiddels zijn we in zulke diepe Python-regionen beland dat de functionaliteit van de iterator een beetje uit het zicht dreigt te raken. Maakt het voor het resultaat wat uit of we met model ''B'', ''C'' of ''D'' te maken hebben? Nee, zolang maar duidelijk is dat het niet ''A'' is. Voor lists en dictionaries kunnen we het model vereenvoudigen tot wat hier links is afgebeeld.

Daarmee laat de figuur nog steeds mijn onzekerheid zien over de wijze waarop {{tt t{"""__next__"""}}} aan de benodigde informatie komt. Heeft deze method genoeg aan wat de iterator zelf aan attributen en methods beschikbaar stelt of moet er op basis van die informatie toch ook nog materiaal rechtstreeks uit de achterliggende collectie en/of eventuele inter&shy;mediairs worden opgediept? Bij ingebouwde methods kom je het pas te weten als je bereid bent de onderliggende C-code te bestuderen. Bij emulaties in Ruby en Lua kunnen we ons vrij voelen om zelf de beste oplossing te vinden, d.w.z. een oplossing die qua zichtbare details overeen&shy;komt met het Python-voorbeeld en uiteindelijk hetzelfde gedrag vertoont.

Ik zal in alle talen steeds twee scripts presenteren, een script voor een eenvoudige teller volgens de schema's helemaal aan het begin van dit stuk, en een script voor een dictionary volgens het laatste schema. Daarbij zal de dictionary tijdens het itereren worden gemuteerd, om te zien hoe de iterator zich in dergelijke omstandigheden houdt.}}}/%
%/
+++(~Iterator_PythonTeller)!!![Python-script voor een teller &darr;|show][Python-script voor een teller &uarr;|hide]
{{lf w80pct pre{
{{fgre{"""# Script: Provider-a-la-Python-iterator.py
# Date  : 2023-03-15, Meindert Meindertsma
#
#   Role       Python term  Name in this script  Variant state
#   ---------  -----------  -------------------  -------------
#   provider   iterator     Iterator, iterator   x
#   deliverer  -            __next__
#   pilot      -            for
#   ---------  -----------  -------------------  -------------


#---- Provider ----#"""}}}
"""class Iterator:
    def __init__(self, increment = 1):
        self.value     = 0
        self.increment = increment

    def __iter__(self):
        return self

    def __next__(self):  """{{fgre{# the delivery method}}}
"""        if self.value < 4 * self.increment:
            self.value += self.increment
            return self.value
        raise StopIteration()
"""
{{fgre{"""# The delivery function:
#     next(<<object>>)
# calls the delivery method:
#     <<object>>.__next__()

#---- Iterate manually ----#"""}}}
"""iterator = Iterator()
print(next(iterator))
print(next(iterator))
print(next(iterator))

print('---')
"""
{{fgre{"""#---- Fly on autopilot ----#"""}}}
for n in Iterator(2): print(n)
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pre{
''Uitvoer''
"""
1
2
3
---
2
4
6
8"""
}}}{{clear block{De iteratie wordt hier afgebroken door een exception van het type {{tt t{StopIteration}}} te genereren. In theorie zou er niet in alle omstandig&shy;heden naar het middel van een exception hoeven te worden gegrepen, maar in combinatie met {{tt t{for&mdash;in}}} is het echt noodzakelijk, omdat dit het enige stopsignal is dat {{tt t{for&mdash;in}}} verstaat. Doe het dus altijd op deze manier, want {{tt t{StopIteration}}} is net zo goed een onderdeel van het iteratieprotocol.}}}/%
%/
Met name het linker diagram aan het begin van dit iterator&shy;verhaal laat eigenlijk alleen de hoofdlijnen van Python's iteratieproces zien. In [['Iterabiliteit' in Python]] zijn de details van het protocol, waaronder de zin van de {{tt t{"""__iter__"""}}}-method, ook helemaal uitgetekend./%

%/
===
+++(~Iterator_PythonDictionary)!!![Python-script voor een dictionary &darr;|show][Python-script voor een dictionary &uarr;|hide]
{{lf w60pct pre{
{{fgre{"""# Script: Provider-a-la-Python-iterator-off-the-road.py
# Date  : 2023-04-01, Meindert Meindertsma
#
#   Role       Python term  Name in this script  Variant state
#   ---------  -----------  -------------------  -------------
#   provider   iterator     iter(provider)       x
#   deliverer  -            __next__
#   pilot      -            for
#   ---------  -----------  -------------------  -------------


#---- Provider ----#"""}}}
D = {'A': 10, 'B': 11, 'C':12}

{{fgre{"""#---- Fly on for pilot ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('01:', i, k, provider[k], provider)
        if i == 0:
            provider.pop('C')
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)
print('---')
"""
{{fgre{"""#---- Second flight ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('02:', i, k, provider[k], provider)
        if i == 0:
            provider['D'] = 13
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)
print('---')
"""
{{fgre{"""#---- Third flight ----#"""}}}
"""i, provider = 0, D.copy()
for k in provider:
    print('03:', i, k, provider[k], provider)
    if i == 0:
        provider['B'] = -1
        provider.pop('C')
        provider['D'] = 13
    i += 1
print('---')
"""
{{fgre{"""#---- Fourth flight ----#"""}}}
"""i, provider = 0, D.copy()
for k in provider:
    print('04:', i, k, provider[k], provider)
    if i == 0:
        provider.pop('B')
        provider['D'] = 13
    i += 1
print('---')
"""
{{fgre{"""#---- Fifth flight ----#"""}}}
"""i, provider = 0, D.copy()
for k in provider:
    print('05:', i, k, provider[k], provider)
    if i == 0:
        provider.pop('B')
        provider.pop('C')
        provider['D'] = 13
        provider['E'] = 14
    i += 1
print('---')
"""
{{fgre{"""#---- Sixth flight ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('06:', i, k, provider[k], provider)
        if i == 0:
            provider.pop('A')
            provider['D'] = 13
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)
print('---')
"""
{{fgre{"""#---- Seventh flight ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('07:', i, k, provider[k], provider)
        if i == 0:
            provider.pop('A')
            provider.pop('B')
            provider['D'] = 13
            provider['E'] = 14
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)
print('---')
"""
{{fgre{"""#---- Eighth flight ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('08:', i, k, provider[k], provider)
        if i == 0:
            provider.pop('A')
            provider.pop('B')
            provider.pop('C')
            provider['D'] = 13
            provider['E'] = 14
            provider['F'] = 15
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)
print('---')
"""
{{fgre{"""#---- Ninth flight ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('09:', i, k, provider[k], provider)
        if i == 0:
            provider.pop('A')
            provider.pop('B')
            provider.pop('C')
            provider['D'] = 13
            provider.pop('D')
            provider['E'] = 14
            provider['F'] = 15
            provider['A'] = 10
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)
print('---')
"""
{{fgre{"""#---- Tenth flight ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('10:', i, k, provider[k], provider)
        if i == 0:
            provider.pop('A')
            provider.pop('B')
            provider.pop('C')
            provider['D'] = 13
            provider['E'] = 14
            provider.pop('D')
            provider['F'] = 15
            provider['A'] = 10
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)
print('---')
"""
{{fgre{"""#---- Eleventh flight ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('11:', i, k, provider[k], provider)
        if i == 0:
            provider.pop('A')
            provider.pop('B')
            provider.pop('C')
            provider['D'] = 13
            provider['E'] = 14
            provider['F'] = 15
            provider.pop('D')
            provider['A'] = 10
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)
print('---')
"""
{{fgre{"""#---- Twelfth flight ----#"""}}}
"""i, provider = 0, D.copy()
try:
    for k in provider:
        print('12:', i, k, provider[k], provider)
        if i == 0:
            provider.pop('A')
            provider.pop('B')
            provider.pop('C')
            provider['D'] = 13
            provider['E'] = 14
            provider['F'] = 15
            provider['A'] = 10
            provider.pop('D')
        i += 1
except RuntimeError as e:
    print('RuntimeError:', e)"""
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w35pct{{{pre{
''Uitvoer''
"""
01: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
RuntimeError: dictionary changed size during iteration
---
02: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
RuntimeError: dictionary changed size during iteration
---
03: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
03: 1 B -1 {'A': 10, 'B': -1, 'D': 13}
03: 2 D 13 {'A': 10, 'B': -1, 'D': 13}
---
04: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
04: 1 C 12 {'A': 10, 'C': 12, 'D': 13}
04: 2 D 13 {'A': 10, 'C': 12, 'D': 13}
---
05: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
05: 1 D 13 {'A': 10, 'D': 13, 'E': 14}
05: 2 E 14 {'A': 10, 'D': 13, 'E': 14}
---
06: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
06: 1 B 11 {'B': 11, 'C': 12, 'D': 13}
06: 2 C 12 {'B': 11, 'C': 12, 'D': 13}
RuntimeError: dictionary keys changed during iteration
---
07: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
07: 1 C 12 {'C': 12, 'D': 13, 'E': 14}
07: 2 D 13 {'C': 12, 'D': 13, 'E': 14}
RuntimeError: dictionary keys changed during iteration
---
08: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
08: 1 E 14 {'D': 13, 'E': 14, 'F': 15}
08: 2 F 15 {'D': 13, 'E': 14, 'F': 15}
---
09: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
09: 1 F 15 {'E': 14, 'F': 15, 'A': 10}
09: 2 A 10 {'E': 14, 'F': 15, 'A': 10}
---
10: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
10: 1 F 15 {'E': 14, 'F': 15, 'A': 10}
10: 2 A 10 {'E': 14, 'F': 15, 'A': 10}
---
11: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
11: 1 E 14 {'E': 14, 'F': 15, 'A': 10}
11: 2 F 15 {'E': 14, 'F': 15, 'A': 10}
RuntimeError: dictionary keys changed during iteration
---
12: 0 A 10 {'A': 10, 'B': 11, 'C': 12}
12: 1 E 14 {'E': 14, 'F': 15, 'A': 10}
12: 2 F 15 {'E': 14, 'F': 15, 'A': 10}
RuntimeError: dictionary keys changed during iteration"""
}}}{{clear block{Er worden twaalf 'vluchten' gemaakt en in elke vlucht wordt de dictionary aan het eind van de eerste iteratie gemuteerd:
# Vermindering van het aantal sleutels wordt onmiddellijk gedetecteerd en leidt tot een {{tt t{RuntimeError}}}.
# Vermeerdering van het aantal sleutels wordt onmiddellijk gedetecteerd en leidt tot een {{tt t{RuntimeError}}}.
# Wijziging van waarden is geen enkel probleem. Wijziging van een sleutel die voorlopig nog niet aan de beurt is, blijkt ook acceptabel.
# Verwijdering van een sleutel die bij de volgende iteratie aan de beurt is, is evenmin een probleem, mits er maar een vervangend sleutel/waarde-paar aan de dictionary wordt toegevoegd.
# Alle sleutels die nog niet aan de beurt zijn geweest, kunnen worden vervangen.
# Als alleen de sleutel wordt vervangen die wel aan de beurt is geweest, {{tt t{A}}} dus, stokt het itereren niet meteen. De tweede iteratie grijpt vervolgens naar wat voorheen nog de tweede sleutel was, {{tt t{B}}}, maar in de huidige iteratie de eerste sleutel van de dictionary is. De derde iteratie gaat verder met {{tt t{C}}}, nu de tweede sleutel. Pas bij de vierde iteratie merkt het algoritme dat er iets niet klopt: de iterator had uitgeput moeten zijn. Dus weer een {{tt t{RuntimeError}}}, nu met een iets andere boodschap.
# Verwijdering van niet alleen {{tt t{A}}} maar ook {{tt t{B}}} (in dit script) of {{tt t{C}}} (niet in dit script) maakt het er niet beter op. Zelfde foutmelding als in de vorige vlucht.
# Tot mijn verrassing helpt verwijdering van alle sleutels wel&#x200a;! De tweede iteratie pakt de tweede van de drie nieuwe sleutels ({{tt t{D}}}, {{tt t{E}}}, {{tt t{F}}}) op en alles komt tot een goed einde.
# Een stapje verder: De nieuwe sleutel {{tt t{D}}} wordt meteen weer verwijderd, waarna {{tt t{E}}}, {{tt t{F}}} en {{tt t{A}}} worden toegevoegd. Gaat goed, waarbij ook opvalt dat hergebruik van sleutel {{tt t{A}}} wordt gedoogd. 'Gedogen' is hier eigenlijk niet het goede woord: het algoritme heeft domweg geen herinneringen aan wat er in eerdere iteraties is gepasseerd.
# {{tt t{D}}} wordt pas na de toevoeging van {{tt t{E}}} verwijderd. Daar zit het algoritme niet mee en het doet braaf zijn werk.
# {{tt t{D}}} wordt pas na de toevoeging van {{tt t{E}}} en {{tt t{F}}} verwijderd. Dat valt dan ineens weer verkeerd en we worden geconfronteerd met de bekende {{tt t{RuntimeError}}}.
# {{tt t{D}}} wordt pas na de toevoeging van {{tt t{E}}}, {{tt t{F}}} en {{tt t{A}}} verwijderd. Zelfde ongelukkige afloop./%
%/
Het is een beetje speculeren wat zich onder de moterkap afspeelt, maar het lijkt erop dat {{tt t{"""__next__"""}}} aan het eind van elke uitvoering (maar dus nog vóór de dictionary-mutaties in de betrokken iteratie) een of andere pointer naar het volgende dictionary-element laat wijzen. In de vluchten 6, 7, 11 en 12 is deze pointer door het jongleren met sleutels aan het eind van de eerste iteratie klaarblijkelijk naar het begin van de dictionary verschoven. Het algoritme heeft daarbij niet in de gaten dat het op deze manier niet goed zal uitkomen en komt pas met een foutmelding op de proppen wanneer het aantal iteraties voorbij de lengte van de dictionary is gekomen. Wat precies als veroorzaker van die pointer&shy;verschuiving kan worden aangewezen, is me niet duidelijk. Ik vrees dat het van een niet erg overzichtelijke hoeveelheid omstandigheden afhangt.}}}}}}{{clear block{}}}/%

%/
===
!!Ruby
Bij de uitwerking van de teller in Ruby heb ik alleen de essentie van het iteratie&shy;{{pref{patroon{{ref{&#x200a;[[[1]|##1]]}}}}}} overeind gehouden en de specifieke Python-eigenaardigheden laten schieten. Op de behandeling van de dictionary, een aanmerkelijk grotere uitdaging, heb ik wat meer mijn best gedaan.
+++(~Iterator_RubyTeller)!!![Ruby-script voor een teller &darr;|show][Ruby-script voor een teller &uarr;|hide]
{{lf w80pct pref tt s med ws pred d2p r scroll{
{{fpur{"""# Script: Provider-a-la-Python-iterator.rb
# Date  : 2023-03-15, Meindert Meindertsma
#
#   Role      Python term  Name in this script     Variant state
#   --------  -----------  ----------------------  -------------
#   provider  iterator     Iterator, iterator...   x
#   delivery  -            next
#   pilot     -            while
#   --------  -----------  ----------------------  -------------

#---- Provider ----#"""}}}
"""class Iterator
  def initialize(increment = 1)
    @value     = 0
    @increment = increment
  end

  def next  """{{fpur{# the delivery method}}}
"""    @value += @increment if @value < 4 * @increment
  end
end
"""
{{fpur{"""#---- Iterate manually ----#"""}}}
"""iterator = Iterator.new
puts iterator.next
puts iterator.next
puts iterator.next

puts "---"
"""
{{fpur{"""#---- Fly on autopilot ----#"""}}}
iterator2 = Iterator.new 2
while n = iterator2.next do puts n end
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pref tt s med ws pred d2p r scroll{
''Uitvoer''
"""
1
2
3
---
2
4
6
8"""
}}}{{clear block{Als belangrijkste verschillen met de Python-uitwerking: hier geen {{tt t{iter}}}-method en geen exception. Wanneer 'de koek op is', geeft {{tt t{next}}} domweg {{tt t{nil}}} als returnwaarde af, zodat de {{tt t{while}}}-lus stopt. (Python-programmeurs zullen vermoedelijk gruwen van de constructie {{hitt pred z{n = iterator2.next}}} die ik daar als voorwaarde heb toegepast. Ik gruw zelf ook wel een beetje mee, maar af en toe kan ik het niet laten een doorsteekje te benutten. De returnwaarde van {{tt t{next}}} wordt toegekend aan de variabele {{tt t{n}}} en dat wordt daarmee dan ook de waarde van het hele toekennings&shy;statement. Anders dan in Python is een Ruby-statement tevens een expressie. Ruby vat trouwens alleen de waarden {{tt t{nil}}} en {{tt t{false}}} in booleaanse context op als //false// en alle andere waarden als //true//. Wel zo overzichtelijk. Eigenlijk was het beter -- in de zin van robuuster -- geweest, realiseer ik me nu, als ik de test had aangescherpt tot {{hitt pred z{(n = iterator2.next) == nil}}}. Hier toevallig niet, maar in sommige gevallen zou {{tt t{false}}} ook een positieve returnwaarde van {{tt t{next}}} kunnen zijn. Ik zal straks bij Lua wat zorgvuldiger opereren.)}}}/%

%/
===
+++(~Iterator_RubyDictionary)!!![Ruby-script voor een dictionary &darr;|show][Ruby-script voor een dictionary &uarr;|hide]
Het Ruby-equivalent van een dictionary is een ''{{{Hash}}}''. Ik zie geen mogelijkheden om interne pointers naar individuele sleutel/waardeparen aan te spreken. De iteratie&shy;besturing moet het geheel hebben van bekendheid met de oorspronkelijke en actuele sleutels van de dictionary in combinatie met een iteratieteller.

De in onderstaand script toegepaste method {{hitt pred z{hsh.keys}}} levert geen view zoals in Python op. Wat je krijgt is een doodgewoon op zichzelf staand array van sleutels dat niet 'meebeweegt' met eventuele gedaante&shy;verwisselingen van de hash {{tt t{hsh}}}.
{{lf w60pct pref tt s med ws pred d2p r scroll{
{{fpur{"""# Script: Provider-a-la-Python-iterator-off-the-road.rb
# Date  : 2023-04-04, Meindert Meindertsma
#
#   Role       Python term  Name in this script   Variant state
#   ---------  -----------  --------------------  -------------
#   provider   iterator     HashKeyIterator, hki  x
#   deliverer  -            next
#   pilot      -            while
#   ---------  -----------  --------------------  -------------


#---- Provider ----#"""}}}
h = {"A" => 10, "B" => 11, "C" => 12}

{{fpur{"""#---- Iterator ----#"""}}}
"""class HashKeyIterator
  def initialize(hsh, sizepolicy = 0, keyspolicy = 0)
    @hash    = hsh
    @keys    = hsh.keys
    @size    = hsh.size
    @sizepol = sizepolicy
    @keyspol = keyspolicy
    @index   = 0
    @error   = false
  end

  def next
    raise RuntimeError, "hash keys changed during iteration" if @error

    if @hash.size != @size then
      warn "-> Warning: #{@index}: #{@hash.size} != #{@size}"
      raise RuntimeError, "hash changed size during iteration" if @sizepol > 0
    elsif @keyspol <= 1 and @hash.keys[@index] != @keys[@index] then
      warn "-> Warning: #{@index}: #{@hash.keys.inspect} != #{@keys.inspect}"
      @error = true if @keyspol == 1
    elsif @keyspol > 1 and @hash.keys != @keys then
      warn "-> Warning: #{@index}: #{@hash.keys.inspect} != #{@keys.inspect}"
      raise RuntimeError, "hash keys changed during iteration"
    end

    raise StopIteration if @index >= @hash.size

    key = @hash.keys[@index]
    @index += 1
    return key
  end
end
"""
{{fpur{"""#---- Fly on while pilot ----#"""}}}
"""i, hki = 0, HashKeyIterator.new((provider = h.dup), 1, 2)
while true do
  begin
    k = hki.next
  rescue StopIteration
    break
  end

  puts "01: #{i} #{k} #{provider[k]} #{provider.inspect}"

  if i == 0 then
    provider["B"] = -1
  end

  i += 1
end
puts "---"
"""
{{fpur{"""#---- Second flight ----#"""}}}
"""i, hki = 0, HashKeyIterator.new((provider = h.dup), 1, 2)
begin
  while true do
    begin
      k = hki.next
    rescue StopIteration
      break
    end

    puts "02: #{i} #{k} #{provider[k]} #{provider.inspect}"

    if i == 0 then
      provider.delete "C"
    end

    i += 1
  end
rescue RuntimeError => e
  puts "#{e.class}: #{e}"
end
puts "---"
"""
{{fpur{"""#---- Third flight ----#"""}}}
"""i, hki = 0, HashKeyIterator.new((provider = h.dup), 1, 2)
begin
  while true do
    begin
      k = hki.next
    rescue StopIteration
      break
    end

    puts "03: #{i} #{k} #{provider[k]} #{provider.inspect}"

    if i == 0 then
      provider.delete "C"
      provider["D"] = 13
    end

    i += 1
  end
rescue RuntimeError => e
  puts "#{e.class}: #{e}"
end
puts "---"
"""
{{fpur{"""#---- Fourth flight ----#"""}}}
"""i, hki = 0, HashKeyIterator.new((provider = h.dup), 1, 1)
begin
  while true do
    begin
      k = hki.next
    rescue StopIteration
      break
    end

    puts "04: #{i} #{k} #{provider[k]} #{provider.inspect}"

    if i == 0 then
      provider.delete "C"
      provider["D"] = 13
    end

    i += 1
  end
rescue RuntimeError => e
  puts "#{e.class}: #{e}"
end
puts "---"
"""
{{fpur{"""#---- Fifth flight ----#"""}}}
"""i, hki = 0, HashKeyIterator.new(provider = h.dup)
begin
  while true do
    begin
      k = hki.next
    rescue StopIteration
      break
    end

    puts "05: #{i} #{k} #{provider[k]} #{provider.inspect}"

    if i == 0 then
      provider.delete "A"
      provider["D"] = 13
    end

    i += 1
  end
rescue RuntimeError => e
  puts "#{e.class}: #{e}"
end
puts "---"
"""
{{fpur{"""#---- Sixth flight ----#"""}}}
"""i, hki = 0, HashKeyIterator.new(provider = h.dup)
begin
  while true do
    begin
      k = hki.next
    rescue StopIteration
      break
    end

    puts "06: #{i} #{k} #{provider[k]} #{provider.inspect}"

    if i == 0 then
      provider.delete "A"
      provider["D"] = 13
      provider["A"] = 10
    end

    i += 1
  end
rescue RuntimeError => e
  puts "#{e.class}: #{e}"
end
puts "---"
"""
{{fpur{"""#---- Seventh flight ----#"""}}}
"""i, hki = 0, HashKeyIterator.new(provider = h.dup)
begin
  while true do
    begin
      k = hki.next
    rescue StopIteration
      break
    end

    puts "07: #{i} #{k} #{provider[k]} #{provider.inspect}"

    if i == 0 then
      provider.clear
    end

    i += 1
  end
rescue RuntimeError => e
  puts "#{e.class}: #{e}"
end"""
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w35pct{{{pref tt s med ws pred d2p r scroll{
''Uitvoer met waarschuwingen''
"""
01: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
01: 1 B -1 {"A"=>10, "B"=>-1, "C"=>12}
01: 2 C 12 {"A"=>10, "B"=>-1, "C"=>12}
---
02: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
"""@@color:#ff6666;-> Warning: 1: 2 != 3@@"""
RuntimeError: hash changed size during iteration
---
03: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
"""@@color:#ff6666;-> Warning: 1: ["A", "B", "D"] != ["A", "B", "C"]@@"""
RuntimeError: hash keys changed during iteration
---
04: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
04: 1 B 11 {"A"=>10, "B"=>11, "D"=>13}
"""@@color:#ff6666;-> Warning: 2: ["A", "B", "D"] != ["A", "B", "C"]@@"""
04: 2 D 13 {"A"=>10, "B"=>11, "D"=>13}
RuntimeError: hash keys changed during iteration
---
05: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
"""@@color:#ff6666;-> Warning: 1: ["B", "C", "D"] != ["A", "B", "C"]@@"""
05: 1 C 12 {"B"=>11, "C"=>12, "D"=>13}
"""@@color:#ff6666;-> Warning: 2: ["B", "C", "D"] != ["A", "B", "C"]@@"""
05: 2 D 13 {"B"=>11, "C"=>12, "D"=>13}
---
06: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
"""@@color:#ff6666;-> Warning: 1: 4 != 3@@"""
06: 1 C 12 {"B"=>11, "C"=>12, "D"=>13, "A"=>10}
"""@@color:#ff6666;-> Warning: 2: 4 != 3@@"""
06: 2 D 13 {"B"=>11, "C"=>12, "D"=>13, "A"=>10}
"""@@color:#ff6666;-> Warning: 3: 4 != 3@@"""
06: 3 A 10 {"B"=>11, "C"=>12, "D"=>13, "A"=>10}
"""@@color:#ff6666;-> Warning: 4: 4 != 3@@"""
---
07: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
"""@@color:#ff6666;-> Warning: 1: 0 != 3@@
}}}{{pref tt s med ws pred d2p r scroll{
''Uitvoer zonder waarschuwingen''
"""
01: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
01: 1 B -1 {"A"=>10, "B"=>-1, "C"=>12}
01: 2 C 12 {"A"=>10, "B"=>-1, "C"=>12}
---
02: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
RuntimeError: hash changed size during iteration
---
03: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
RuntimeError: hash keys changed during iteration
---
04: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
04: 1 B 11 {"A"=>10, "B"=>11, "D"=>13}
04: 2 D 13 {"A"=>10, "B"=>11, "D"=>13}
RuntimeError: hash keys changed during iteration
---
05: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
05: 1 C 12 {"B"=>11, "C"=>12, "D"=>13}
05: 2 D 13 {"B"=>11, "C"=>12, "D"=>13}
---
06: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}
06: 1 C 12 {"B"=>11, "C"=>12, "D"=>13, "A"=>10}
06: 2 D 13 {"B"=>11, "C"=>12, "D"=>13, "A"=>10}
06: 3 A 10 {"B"=>11, "C"=>12, "D"=>13, "A"=>10}
---
07: 0 A 10 {"A"=>10, "B"=>11, "C"=>12}"""
}}}{{clear block{Zeven 'vluchten' zijn wel voldoende om een beeld te krijgen van wat er met de beschikbare middelen te realiseren valt:
# Tussentijdse verandering van de waarden zijn geen probleem. Als een sleutel nog niet aan de beurt is geweest, kan de nieuwe waarde die erbij is gaan horen nog worden meegenomen.
# Bij bewaking van het aantal sleutels via de instelling {{hitt pred z{HashKeyIterator.new(provider, ''1'', 2)}}} wordt wijziging van dit aantal meteen afgestraft met een {{tt t{RuntimeError}}}.
# Bij strenge bewaking van de sleutels en hun juiste volgorde via {{hitt pred z{HashKeyIterator.new(provider, 1, ''2'')}}} worden veranderingen hierin onmiddellijk afgestraft met een {{tt t{RuntimeError}}}, ook al blijft het totale aantal sleutels gelijk.
# Bij wat mildere bewaking van de sleutels via {{hitt pred z{HashKeyIterator.new(provider, 1, ''1'')}}} mag het itereren weliswaar doorgaan totdat het einde is bereikt, maar dan volgt alsnog een {{tt t{RuntimeError}}}.
# Laten we alles z'n gang gaan met {{hitt pred z{HashKeyIterator.new(provider, ''0'', ''0'')}}}, dan is toevoeging van een nieuwe sleutel {{tt t{D}}} ten koste van een andere geen probleem. De afgegeven waarschuwing laat de nieuwe en de oorspronkelijke inhoud van de hash zien.
# Deze vlucht verschilt van de vorige in het achteraf toch weer toevoegen van sleutel {{tt t{A}}}. Bij hetzelfde tolerantiebeleid evenmin een probleem, maar nu toont de waarschuwing de nieuwe en de oorspronkelijk omvang van hash.
# Ook het compleet leeghalen van de hash brengt bij dit beleid geen schok teweeg. Het itereren stopt tijdig op een natuurlijke manier met de exception {{tt t{StopIteration}}}, die in de {{tt t{while}}}-lus wordt opgevangen./%
%/
De index schuift bij elke iteratie onverbiddelijk één plaatsje op en kan alleen worden gestuit door een exception. Als imitatie van Python's in dit soort omstandigheden grillige iterator schiet het Ruby-script natuurlijk hopeloos tekort. Anderzijds valt het juist om zijn beheerste gedrag te waarderen. Dat geldt in mijn optiek vooral voor de uiterste en daarmee meest consequente benaderingen: òf een absoluut zero&shy;tolerance&shy;beleid wat betreft tussentijdse veranderingen in de dictionary, òf juist een volkomen meegaan met wat zich maar voordoet, daarbij hooguit een waarschuwing afgevend wanneer het wel erg dynamisch wordt. Die waarschuwingen kunnen overigens op de in Ruby gebruikelijke wijze worden onderdrukt.}}}}}}{{clear block{}}}/%

%/
===
!!Lua
In Lua heb ik dezelfde vereenvoudigingen op de teller toegepast als in het Ruby-script. En omdat Lua niet object­georiënteerd is, ben ik voor deze demonstratie bovendien nog een graadje directer te werk gegaan. Voor de dictionary heb ik gebruik gemaakt van de ingebouwde Lua-functie ''{{{next}}}'', waarmee je over een table van sleutel/waarde-paren kunt itereren. Ook hier heb ik het zo simpel mogelijk gehouden. 
+++(~Iterator_LuaTeller)!!![Lua-script voor een teller &darr;|show][Lua-script voor een teller &uarr;|hide]
{{lf w80pct pre4{
{{fgre{"""-- Script: Provider-a-la-Python-iterator.lua
-- Date  : 2023-03-15, Meindert Meindertsma
--
--   Role       Python term  Name in this script  Variant state
--   ---------  -----------  -------------------  -------------
--   provider   iterator     iterator             x
--   deliverer  -            next
--   pilot      -            while
--   ---------  -----------  -------------------  -------------

----- Provider, implemented as an immediate object -----"""}}}
"""iterator = {}

function iterator:init (increment)
  self.value     = 0
  self.increment = increment or 1
end

function iterator:next ()  """{{fgre{"""-- the delivery function"""}}}
"""  if self.value < 4 * self.increment then
    self.value = self.value + self.increment
    return self.value
  end
end
"""
{{fgre{"""----- Iterate manually -----"""}}}
"""iterator:init()
print(iterator:next())
print(iterator:next())
print(iterator:next())

print "---"
"""
{{fgre{"""----- Fly on autopilot -----"""}}}
"""iterator:init(2)
while true do
  local n = iterator:next()
  if n ~= nil then print(n) else break end
end"""
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pre4{
''Uitvoer''
"""
1
2
3
---
2
4
6
8"""
}}}{{clear block{Geen class en instances ervan zoals in Python en Ruby, maar meteen een instant&shy;dictionary met daarin de benodigde {{tt t{init}}}- en {{tt t{next}}}-functie plus twee andere sleutel/waarde-paren. Te herinitialiseren als ik een volgende iterator nodig heb. 'Refurbished' zogezegd. De waarde {{tt t{nil}}} is in Lua de idiomatische manier om aan te geven dat er niets meer is. Evenals in Ruby kunnen alleen {{tt t{nil}}} en {{tt t{false}}} als //false// worden geïnterpreteerd. In Lua zijn statements geen expressies, dus ik moest hier wat omslachtiger (en minder ondoorgrondelijk) te werk gaan om de {{tt t{while}}}-lus te bewegen er tijdig mee op te houden.}}}/%
%/
<<eval [=[De functiedefinitie {{pref hitt4 z{function iterator:init (increment) $___}}} is syntactische suiker voor {{pref hitt4 z{function iterator.init (self, increment) $___}}}.
Evenzo is de aanroep {{pref hitt4 z{iterator:init(2)}}} syntactische suiker voor {{pref hitt4 z{iterator.init(interator, 2)}}}. Geen magie, gewoon een zoetigheidje.]=] f1m>>/%

%/
===
+++(~Iterator_LuaDictionary)!!![Lua-script voor een dictionary &darr;|show][Lua-script voor een dictionary &uarr;|hide]
In Lua is de volgorde van de table-elementen buiten het sequence-gedeelte onbepaald (zie de toelichting onder het Lua-script in [[Simulaties van for...in...-statement]]). Na een paar keer draaien in Lua 5.4 kreeg ik de elementen in de 'juiste' volgorde afgespeeld, maar dat is louter toeval. Ik laat de uitvoer van drie runs zien.
{{lf w60pct pre4{
{{fgre{"""-- Script: Provider-a-la-Python-iterator-off-the-road.lua
-- Date  : 2023-04-05, Meindert Meindertsma
--
--   Role       Python term  Name in this script  Variant state
--   ---------  -----------  -------------------  -------------
--   provider   iterator     tableKeyiterator     x
--   deliverer  -            next
--   pilot      -            while
--   ---------  -----------  -------------------  -------------


----- Support -----"""}}}
"""function display (t)
  local display = "{"
  for k, v in pairs(t) do
    display = display .. k .. " = " .. v .. ", "
  end
  display = display:sub(1, -3) .. "}"
  return display
end
"""
{{fgre{"""----- Iterator -----"""}}}
"""tableKeyIterator = {}
function tableKeyIterator:next ()
  self.prev = next(self.provider, self.prev)
  return self.prev
end
"""
{{fgre{"""----- Fly on while pilot -----"""}}}
"""i, provider = 0, {A = 10, B = 11, C = 12}
tableKeyIterator.provider = provider
while true do
  local key = tableKeyIterator:next()
  if key == nil then break end
  print(table.concat({"01:", i, key, provider[key], display(provider)}, " "))

  if i == 0 then
    provider.D = 13
  end

  i = i + 1
end
print "---"
"""
{{fgre{"""----- Second flight -----"""}}}
"""i, provider = 0, {A = 10, B = 11, C = 12}
tableKeyIterator.provider = provider
while true do
  local key = tableKeyIterator:next()
  if key == nil then break end
  print(table.concat({"02:", i, key, provider[key], display(provider)}, " "))

  if i == 0 then
    provider.A = nil
  end

  i = i + 1
end
print "---"
"""
{{fgre{"""----- Third flight -----"""}}}
"""i, provider = 0, {A = 10, B = 11, C = 12}
tableKeyIterator.provider = provider
while true do
  local key = tableKeyIterator:next()
  if key == nil then break end
  print(table.concat({"03:", i, key, provider[key], display(provider)}, " "))

  if i == 0 then
    provider.B = nil
  end

  i = i + 1
end
print "---"
"""
{{fgre{"""----- Fourth flight -----"""}}}
"""i, provider = 0, {A = 10, B = 11, C = 12}
tableKeyIterator.provider = provider
while true do
  local key = tableKeyIterator:next()
  if key == nil then break end
  print(table.concat({"04:", i, key, provider[key], display(provider)}, " "))

  if i == 0 then
    provider.C = nil
  end

  i = i + 1
end
print "---"
"""
{{fgre{"""----- Fifth flight -----"""}}}
"""i, provider = 0, {A = 10, B = 11, C = 12}
tableKeyIterator.provider = provider
while true do
  local key = tableKeyIterator:next()
  if key == nil then break end
  print(table.concat({"05:", i, key, provider[key], display(provider)}, " "))

  if i == 0 then
    provider.A = nil
    provider.B = nil
    provider.C = nil
  end

  i = i + 1
end
print "---"
"""
{{fgre{"""----- Double flight -----"""}}}
"""i, provider = 0, {A = 10, B = 11, C = 12}
tableKeyIterator.provider = provider
while true do
  local key = tableKeyIterator:next()
  if key == nil then break end
  print(table.concat({"6a:", i, key, provider[key], display(provider)}, " "))
  i = i + 1
end
while true do
  local key = tableKeyIterator:next()
  if key == nil then break end
  print(table.concat({"6b:", i, key, provider[key], display(provider)}, " "))
  if i == 3 then provider.B = -1 end
  i = i + 1
end"""
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w35pct{{{pre4{
''Uitvoer eerste run''
"""
01: 0 A 10 {A = 10, C = 12, B = 11}
01: 1 D 13 {A = 10, D = 13, C = 12, B = 11}
01: 2 C 12 {A = 10, D = 13, C = 12, B = 11}
01: 3 B 11 {A = 10, D = 13, C = 12, B = 11}
---
02: 0 A 10 {A = 10, C = 12, B = 11}
02: 1 C 12 {C = 12, B = 11}
02: 2 B 11 {C = 12, B = 11}
---
03: 0 A 10 {A = 10, C = 12, B = 11}
03: 1 C 12 {A = 10, C = 12}
---
04: 0 A 10 {A = 10, C = 12, B = 11}
04: 1 B 11 {A = 10, B = 11}
---
05: 0 A 10 {A = 10, C = 12, B = 11}
---
6a: 0 A 10 {A = 10, C = 12, B = 11}
6a: 1 C 12 {A = 10, C = 12, B = 11}
6a: 2 B 11 {A = 10, C = 12, B = 11}
6b: 3 A 10 {A = 10, C = 12, B = 11}
6b: 4 C 12 {A = 10, C = 12, B = -1}
6b: 5 B -1 {A = 10, C = 12, B = -1}"""
}}}{{pre4{
''Uitvoer latere run''
"""
01: 0 A 10 {A = 10, B = 11, C = 12}
01: 1 B 11 {A = 10, B = 11, C = 12, D = 13}
01: 2 C 12 {A = 10, B = 11, C = 12, D = 13}
01: 3 D 13 {A = 10, B = 11, C = 12, D = 13}
---
02: 0 A 10 {A = 10, B = 11, C = 12}
02: 1 B 11 {B = 11, C = 12}
02: 2 C 12 {B = 11, C = 12}
---
03: 0 A 10 {A = 10, B = 11, C = 12}
03: 1 C 12 {A = 10, C = 12}
---
04: 0 A 10 {A = 10, B = 11, C = 12}
04: 1 B 11 {A = 10, B = 11}
---
05: 0 A 10 {A = 10, B = 11, C = 12}
---
6a: 0 A 10 {A = 10, B = 11, C = 12}
6a: 1 B 11 {A = 10, B = 11, C = 12}
6a: 2 C 12 {A = 10, B = 11, C = 12}
6b: 3 A 10 {A = 10, B = 11, C = 12}
6b: 4 B -1 {A = 10, B = -1, C = 12}
6b: 5 C 12 {A = 10, B = -1, C = 12}"""
}}}{{pre4{
''Uitvoer laatste run''
"""
01: 0 A 10 {A = 10, B = 11, C = 12}
01: 1 B 11 {D = 13, A = 10, B = 11, C = 12}
01: 2 C 12 {D = 13, A = 10, B = 11, C = 12}
---
02: 0 A 10 {A = 10, B = 11, C = 12}
02: 1 B 11 {B = 11, C = 12}
02: 2 C 12 {B = 11, C = 12}
---
03: 0 A 10 {A = 10, B = 11, C = 12}
03: 1 C 12 {A = 10, C = 12}
---
04: 0 A 10 {A = 10, B = 11, C = 12}
04: 1 B 11 {A = 10, B = 11}
---
05: 0 A 10 {A = 10, B = 11, C = 12}
---
6a: 0 A 10 {A = 10, B = 11, C = 12}
6a: 1 B 11 {A = 10, B = 11, C = 12}
6a: 2 C 12 {A = 10, B = 11, C = 12}
6b: 3 A 10 {A = 10, B = 11, C = 12}
6b: 4 B -1 {A = 10, B = -1, C = 12}
6b: 5 C 12 {A = 10, B = -1, C = 12}"""
}}}{{clear block{Een liberale iterator was in een handomdraai gebouwd en na zes à zeven vluchten hield ik het voor gezien. Ingeval de table die als provider fungeert onderweg wordt gemuteerd, gebeurt dat aan het eind van de eerste iteratie. Dit zijn de bevindingen:
# Een toegevoegd sleutel/waarde-paar leidt tot een extra iteratie om dat paar ook mee te nemen, of wordt overgeslagen omdat het kennelijk 'vóór de huidige pointer' en daarmee buiten het blikveld is beland.
# In deze en de volgende twee vluchten wordt steeds één ander sleutel/waarde-paar verwijderd. Op deze manier komen alle posities aan de beurt. In deze vlucht is dat de positie waar sleutel {{tt t{A}}} staat. Omdat deze in alle getoonde runs op positie 1 staat, is het betrokken paar al in de eerste iteratie afgehandeld en komen de andere paren gewoon aan de beurt zoals zonder verwijdering van {{tt t{A}}} ook het geval zou zijn geweest.
# Hier is {{tt t{B}}} verwijderd. Er vindt nu alleen nog maar een iteratie met {{tt t{C}}} plaats.
# Hier is {{tt t{C}}} verwijderd. Er vindt nu alleen nog maar een iteratie met {{tt t{B}}} plaats. De vluchten 2 t/m 4 samenvattend, zie ik alleen maar gedrag dat mij het meest logisch voorkomt.
# De table wordt helemaal leeggemaakt. Geen probleem, het itereren stopt.
# Deze iterator is cyclisch: uitputting is tevens herinitialisatie. Hij kan dus zonder verdere poespas worden hergebruikt, voor dezelfde provider of voor een andere. In dit script wordt er twee keer achter elkaar door dezelfde table heengewandeld. In de tweede ronde wordt en passant de waarde bij {{tt t{B}}} aangepast./%
%/
Mijn waarnemingen stemmen overeen met wat de officiële reference manual erover zegt:{{ref{[[[3]|##3]]}}}
>The behavior of {{tt t{next}}} is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may set existing fields to nil.
'Set existing fields to nil' betekent feitelijk verwijdering van die sleutel/waarde-paren uit de table. Zo werkt dat in Lua.
}}}}}}{{clear block{}}}
===

----
|plain |k
|<html><a name="1">[1]</a></html>|Min of meer het 'Iterator Pattern' volgens <<tiddler "Bibliografie##GoF">> |
|<html><a name="2">[2]</a></html>|De drie calls -- of callables? -- zijn hier naar mijn opvatting wat al te losjes gepresenteerd. Zo moet ''{{{dict.keys()}}}'' worden verstaan als een (mogelijkheid tot de) aanroep {{hitt z{//D//.keys()}}} of {{hitt z{dict.keys(//D//)}}}. Beide vormen hebben in de praktijk hetzelfde effect.<br>(In de Ruby-wereld bestaat een heel praktische conventie voor het aanduiden van methods: ''{{{Hash.new}}}'' stelt de class­method {{tt t{new}}} van {{tt t{Hash}}} voor, en ''{{{Hash#keys}}}'' de instance­method {{tt t{keys}}}. Soms hebben class- en instance­methods dezelfde naam, bijvoorbeeld ''{{{Hash.[]}}}'' naast ''{{{Hash#[]}}}''. Het ''{{{#}}}''-symbool is in deze positie geen geldige syntax. In een programma behoort ook bij instance­methods de puntnotatie te worden gebruikt, dus {{hitt pred z{//h//.keys}}}, met daarnaast voor een aantal specifieke methods liever een zodanige schrijfwijze dat het helemaal niet meer op de aanroep van een method lijkt, zoals {{pref hitt pred z{Hash''[''"A" => 10, "B" => 11, "C" => 12'']''}}} en {{hitt pred z{//h//''[''"A"'']''}}} i.p.v. {{pref hitt pred z{Hash''.[]''("A" => 10, "B" => 11, "C" => 12)}}} resp. {{hitt pred z{//h//''.[]''("A")}}}.) |
|<html><a name="3">[3]</a></html>|<<tiddler "Bibliografie##Ierusalimschy-2019">> |
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Bijlagen bij [[Zichtbaarheid van Python-variabelen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Zichtbaarheid van Python-variabelen]] label: "Bundel ↘">>}}}''

|plain |k
|''&bull;''|{{sans t{[[Python-scopes(variables)-20230712.zip|data/zip/Python-scopes(variables)-20230712.zip]]}}} | &rarr; |[[Zichtbaarheid van Python-variabelen]]     |
|~|~| &rarr; |[[Een niet zo geweldige introspectie van Python]] |
|''&bull;''|{{sans t{[[Python-scopes(modules)-20230709.zip|data/zip/Python-scopes(modules)-20230709.zip]]}}} | &rarr; |[[Geneste Python-modules]]                      |
|''&bull;''|{{sans t{[[Python-scopes(classes)-20230709.zip|data/zip/Python-scopes(classes)-20230709.zip]]}}} | &rarr; |[[Zichtbaarheid van classattributen in Python]] |
|pref sans |k
|bgcolor:black;!Common color name|bgcolor:black; !Initial background |bgcolor:black; !Improved background |bgcolor:black; !Initial foreground |bgcolor:black; !Improved foreground |
|''Red''        |bgcolor:red;           {{{bred FF-00-00}}} |bgcolor:#ff0000; {{{bred FF-00-00}}} |color:red;        {{tt{fred FF-00-00}}} | {{tt fred{fred FF-00-00}}} |
|''Darkorange'' |bgcolor:darkorange;    {{{bora FF-8C-00}}} |bgcolor:#ff8c00; {{{bora FF-8C-00}}} |color:darkorange; {{tt{fora FF-8C-00}}} | {{tt fora{fora FF-8C-00}}} |
|''Yellow''     |bgcolor:yellow;        {{{     FF-FF-00}}} |bgcolor:#ffee00; {{{byel FF-EE-00}}} |color:yellow;     {{tt{     FF-FF-00}}} | {{tt fyel{fyel FF-EE-00}}} |
|''Green''      |bgcolor:green; {{fwhi tt {     00-80-00}}} |bgcolor:#009900; {{{bgre 00-99-00}}} |color:green;      {{tt{     00-80-00}}} | {{tt fgre{fgre 00-99-00}}} |
|''DarkCyan''   |bgcolor:darkcyan;      {{{bkya 00-8B-8B}}} |bgcolor:#00aaaa; {{{bcya 00-AA-AA}}} |color:darkcyan;   {{tt{fkya 00-8B-8B}}} | {{tt fcya{fcya 00-AA-AA}}} |
|''Blue''       |bgcolor:blue;   {{fwhi tt{bblu 00-00-FF}}} |bgcolor:#0000ff; {{{bblu 00-00-FF}}} |color:blue;       {{tt{fblu 00-00-FF}}} | {{tt fblu{fblu 00-00-FF}}} |
|''Purple''     |bgcolor:purple; {{fwhi tt{     80-00-80}}} |bgcolor:#bb00bb; {{{bpur BB-00-BB}}} |color:purple;     {{tt{     80-00-80}}} | {{tt fpur{fpur BB-00-BB}}} |
Het adres waar elektronische missiven mij kunnen bereiken is hier &rarr; <html><a id="anotherRoad" title="Town" onmouseover="sameTown.src='core/town-a1.png'" onmouseout="sameTown.src='core/town-a0.png'" onmousedown="sameTown.src='core/town-a2.png'" onmousup="sameTown.src='core/town-a0.png'" target=_new href="../index.html"><img id="sameTown" src="core/town-a0.png" style="position:relative; top:6px;"></a></html> &larr; vermeld.
/%
!info
|Name|RefreshPageDisplay|
|Source|http://www.TiddlyTools.com/#RefreshPageDisplay|
|Version|2.0.0//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|create a link to redraw all page elements without restarting|
Usage
<<<
{{pre{
&#x003c;<tiddler RefreshPageDisplay>>
&#x003c;<tiddler RefreshPageDisplay with: label>>
&#x003c;<tiddler RefreshPageDisplay with: label tooltip>>    /&#x0025; extra &#x0025;/
}}}
<<<
Example
<<<
{{{<<tiddler RefreshPageDisplay with: "click me">>}}}
<<tiddler RefreshPageDisplay##show with: "click me" "Redisplay current page content WITHOUT RESTARTING!">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	story.forEachTiddler(function(t,e){story.refreshTiddler(t,null,true)});
	refreshDisplay();
 	return false;"
>$1</a></html>
!end
%/<<tiddler {{var src='RefreshPageDisplay'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'=='$'+'1'?'refresh page display':'$1'}} {{'$2'=='$'+'2'?'Redisplay current page content WITHOUT RESTARTING!':'$2'}}>>
Een reguliere expressie (//regular expression//  of simpelweg //regex//) is een speciale, geformaliseerde wijze om een tekstpatroon uit te drukken. Een (nogal vergevingsgezind) patroon voor postcodes is bijvoorbeeld:
{{{
[1-9]\d{3} ?[A-Za-z]{2}
}}}
Hiermee zijn de volgende mogelijkheden aangegeven: een cijfer anders dan nul (''{{{[1-9]}}}''), gevolgd door drie willekeurige cijfers (''<html><code>\d{3}</code></html>''), gevolgd door een eventuele spatie (''{{{ ?}}}'', let op de spatie voor het vraagteken!), en tot besluit twee letters (''<html><code>[A-Za-z]{2}</code></html>''). Een patroon dat de drie schrijfwijzen "Händel", "Handel" en "Haendel" van de naam van de barokcomponist dekt, is:
{{{
H(ä|ae?)ndel
}}}
Reguliere expressies zijn vooral bekend geworden via Unix-editors en -tools als {{{ed}}}, {{{vi}}}, {{{grep}}}, {{{sed}}} en [[Perl]], en worden door steeds meer script- en programmeertalen ondersteund. De keerzijde hiervan is, dat het aantal verschillende dialecten eveneens toeneemt. Hoewel deze sterk op elkaar lijken, is het bij het wisselen van omgeving dus oppassen geblazen.

Hieronder vind je een bruikbare subset die [[Perl]] en [[Ruby]] gemeen hebben. Beide talen kennen nog instellingen voor hoofdlettergevoeligheid en meerregeligheid, maar het voert hier te ver om daar verder op in te gaan./%
%/
!Tekens
Alle tekens behalve de //metasymbolen//{{{ $ ( ) * + . ? [ \ ] ^ { | }}}<html><code>} </code></html>(in Perl bovendien {{{@}}}, en in Ruby {{{#{}}}...<html><code>}</code></html>) representeren zichzelf. Om de letterlijke betekenis van een metasymbool te krijgen, moet dit worden geëscapet door er een backslash voor te plaatsen (''{{{\* }}}''is geen quantifier maar betekent gewoon 'het asteriskteken'). Voor sommige tekens bestaat een speciale backslashrepresentatie:
;@@bgcolor(#ddf):{{{\a}}}@@
:Alarm //(beep)//, ASCII 7.
;@@bgcolor(#ddf):{{{\t}}}@@
:(Horizontal) tab, ASCII 9.
;@@bgcolor(#ddf):{{{\n}}}@@
:Newline //(linefeed)//, ASCII 10.
;@@bgcolor(#ddf):{{{\f}}}@@
:Formfeed, ASCII 12.
;@@bgcolor(#ddf):{{{\r}}}@@
:Carriage return, ASCII 13.
;@@bgcolor(#ddf):{{{\e}}}@@
:Escape, ASCII 27.
;@@bgcolor(#ddf):{{{\}}}//{{{«nnn»}}}//@@
:Octale waarde //«nnn»//.
;@@bgcolor(#ddf):{{{\x}}}//{{{«nn»}}}//@@
:Hexadecimale waarde //«nn»//.
;@@bgcolor(#ddf):{{{\c}}}//{{{«x»}}}//@@
:Control-//«x»//./%
%/
!Tekenklassen
;@@bgcolor(#ddf):{{{.}}}@@
:Matcht met elk willekeurig teken (behalve {{{\n}}} in bepaalde gevallen).
;@@bgcolor(#ddf):{{{[}}}@@//{{{«characters»}}}//@@bgcolor(#ddf):{{{]}}}@@
:Matcht met elk van de in //«characters»// opgesomde tekens. Naast letterlijke opsommingen mogen ook bereiken worden opgegeven:''{{{ [a-fklmx-z] }}}''is hetzelfde als''{{{ [abcdefklmxyz]}}}''. De speciale betekenis van de meeste metasymbolen komt tussen de teksthaakjes te vervallen. Wil je echter een {{{-}}}, {{{\}}}, {{{^}}} of {{{]}}} in de opsomming opnemen, dan moet dit worden geëscapet.
;@@bgcolor(#ddf):{{{[^}}}@@//{{{«characters»}}}//@@bgcolor(#ddf):{{{]}}}@@
:Matcht met alles wat //niet// voorkomt in de opsomming //«characters»//.
;@@bgcolor(#ddf):{{{\d}}}@@
:Een cijfer //(digit)//, hetzelfde als''{{{ [0-9]}}}''.
;@@bgcolor(#ddf):{{{\D}}}@@
:Geen cijfer, hetzelfde als''{{{ [^0-9]}}}''.
;@@bgcolor(#ddf):{{{\s}}}@@
:Witruimte, hetzelfde als''{{{ [ \t\r\n\f] }}}''(let op de spatie na de openingsteksthaak).
;@@bgcolor(#ddf):{{{\S}}}@@
:Geen witruimte, hetzelfde als''{{{ [^ \t\r\n\f] }}}''(let op de spatie na de circumflex).
;@@bgcolor(#ddf):{{{\w}}}@@
:Een woordteken, hetzelfde als''{{{ [A-Za-z_0-9]}}}''.
;@@bgcolor(#ddf):{{{\W}}}@@
:Geen woordteken, hetzelfde als''{{{ [^A-Za-z_0-9]}}}''./%
%/
!Ankers
Aan bovenstaande postcode- en barokcomponistvoorbeelden hadden eigenlijk nog //anchors// moeten worden toegevoegd. Hiermee kan worden afgedwongen dat op een bijzondere plaats naar een patroon wordt gezocht:
;@@bgcolor(#ddf):{{{^}}}@@//{{{«expression»}}}//
:De //«expression»// staat aan het begin van de string of regel.
;//{{{«expression»}}}//@@bgcolor(#ddf):{{{$}}}@@
:De //«expression»// staat aan het einde van de string of regel, eventueel vóór de {{{\n}}} waar deze mee eindigt.
;@@bgcolor(#ddf):{{{\A}}}@@//{{{«expression»}}}//
:De //«expression»// staat aan het begin van de string.
;//{{{«expression»}}}//@@bgcolor(#ddf):{{{\Z}}}@@
:De //«expression»// staat aan het einde van de string of voor de {{{\n}}} waar deze mee eindigt.
;//{{{«expression»}}}//@@bgcolor(#ddf):{{{\z}}}@@
:De //«expression»// staat aan het einde van de string.
;@@bgcolor(#ddf):{{{\b}}}@@
:De rand //(boundary)// van een woord (tussen {{{\W}}} en {{{\w}}}, tussen {{{\w}}} en {{{\W}}}, of aan het begin dan wel eind van de hele string).
;@@bgcolor(#ddf):{{{\B}}}@@
:Niet de rand van een woord./%
%/
!Herhaling
Onderstaande //quantifiers// hebben een hoge prioriteit, d.w.z. zij grijpen direct aan op het voorafgaande teken of op de voorafgaande groep.
;{{{X}}}@@bgcolor(#ddf):{{{{}}}//{{{«n»}}}//{{{,}}}//{{{«m»}}}//<html><code>}</code></html>@@
:{{{X}}} komt ten minste //«n»// keer maar niet meer dan //«m»// keer voor.
;{{{X}}}@@bgcolor(#ddf):{{{{}}}//{{{«n»}}}//<html><code>,}</code></html>@@
:{{{X}}} komt //«n»// of meer keer voor.
;{{{X}}}@@bgcolor(#ddf):{{{{}}}//{{{«n»}}}//<html><code>}</code></html>@@
:{{{X}}} komt precies //«n»// keer voor.
;{{{X}}}@@bgcolor(#ddf):{{{*}}}@@
:Hetzelfde als ''<html><code>X{0,}</code></html>''.
;{{{X}}}@@bgcolor(#ddf):{{{+}}}@@
:Hetzelfde als ''<html><code>X{1,}</code></html>''.
;{{{X}}}@@bgcolor(#ddf):{{{?}}}@@
:Hetzelfde als ''<html><code>X{0,1}</code></html>''.
;{{{X}}}//{{{«quantifier»}}}//@@bgcolor(#ddf):{{{?}}}@@
:Zet de van nature gulzige //(greedy)// quantifier, die een zo groot mogelijke match probeert te bereiken, aan tot matigheid, zodat deze juist een zo klein mogelijke match probeert te bereiken (gerekend vanaf de plaats waar het zoekproces beet krijgt). In de string{{{ Monty Python's Flying Circus }}}komt het patroon''{{{ P.*y }}}''overeen met de sequentie{{{ Python's Fly}}}, terwijl''{{{ P.*?y }}}''al tevreden is met {{{Py}}}./%
%/
!Alternatieven
;//{{{«expression1»}}}//@@bgcolor(#ddf):{{{|}}}@@//{{{«expression2»}}}//
:Matcht met //«expression1»// of met //«expression2»//; de ''{{{|}}}''-operator heeft lage prioriteit./%
%/
!Groepering
;@@bgcolor(#ddf):{{{(}}}@@//{{{«expression»}}}//@@bgcolor(#ddf):{{{)}}}@@
:{{_{Groepeert uitdrukkingen en kent de resulterende inhoud toe aan de variabelen {{{\1}}} t/m {{{\9}}}. Toepassingen:
* ''{{{XYZ+ }}}''matcht met een {{{XY}}} direct gevolgd door één of meer letters {{{Z}}};''{{{ (XYZ)+ }}}''matcht met één of meer keer de sequentie {{{XYZ}}} pal achter elkaar.
* ''{{{XX|YY }}}''matcht met de sequentie {{{XX}}} of {{{YY}}};''{{{ X(X|Y)Y }}}''matcht pas als er een {{{XXY}}} of {{{XYY}}} wordt gevonden.
* ''{{{(['"])tiddler\1 }}}''matcht met {{{'tiddler'}}} en met {{{"tiddler"}}}, maar niet met {{{'tiddler"}}} of {{{"tiddler'}}}.
}}}
;@@bgcolor(#ddf):{{{(?:}}}@@//{{{«expression»}}}//@@bgcolor(#ddf):{{{)}}}@@
:Groepeert eveneens uitdrukkingen, maar zonder de variabelen {{{\1}}} t/m {{{\9}}} te vullen, wat de performance van de zoekmachine ten goede komt.
Als uitvloeisel van de Python-cursus 2023/2024 binnen [[HCC!programmeren|https://programmeren.hcc.nl/]] -- aan de hand van het boek //De programmeursleerling//{{ref{&#x200a;[[[1]|##1]]}}} -- heb ik enige geschriften over reguliere expressies geproduceerd. Een Word-document en een PowerPoint-presentatie. Laatstgenoemde heb ik tijdens de cursus in tweeën geknipt, en er even later nog een derde deel aan toegevoegd. Hieronder stel ik ze alle vier in PDF-formaat beschikbaar en licht ik ze nog wat toe./%

%/
!!De {{{re}}}-module van Python -- Een beknopte inventarisatie
{{sans t{[[Inventarisatie Python re.pdf|data/documents/Inventarisatie Python re.pdf]]}}}, //gepubliceerd op 6 maart 2024// -- Een overzicht van wat de {{tt t{re}}}-module en de reguliere-expressietaal te bieden hebben. Iets om bij de hand te hebben om je weg te vinden in hoofdstuk 25 van //De programmeursleerling//, de officiële Python-documentatie en wat er verder wereldwijd zoal over reguliere expressies geschreven is. De literatuur&shy;opgave aan het eind van het document verwijst trouwens onder meer naar een [[introductie die ik in 2009 heb gepubliceerd|Reguliere expressies]]./%

%/
!!Reguliere expressies behapbaar maken -- "Verdeel en heers"
{{sans t{[[Spronck-H25.pdf|data/documents/Spronck-H25.pdf]]}}}, //gepresenteerd op 28 maart 2024// -- In de vorige ronde waarin een aantal mensen gezamenlijk aan de hand van //De programmeursleerling// deze stof bestudeerden (voorjaar 2023), wist een van de deelnemers een reguliere expressie van 290 tekens te produceren. Heel knap, maar niet erg leesbaar. Daar is gelukkig wel iets aan te doen. De presentatie laat stapsgewijs zien hoe je door gebruik te maken van de 'extended syntax' toch tot een formulering kunt komen die best goed te volgen is. In de praktijk zul je niet gauw op zulke buitensporig lange constructies uitkomen. Maar goed om te weten welke voorzieningen er zijn, mocht jouw reguliere expressie wat fors uitpakken./%

%/
!!Reguliere expressies behapbaar maken -- "Vermenigvuldigt u!"
{{sans t{[[Spronck-H25-nongreedy.pdf|data/documents/Spronck-H25-nongreedy.pdf]]}}}, //gepresenteerd op 18 april en 16 mei 2024// -- In deze slides wilde ik het nut van non-greedy kwantoren zoals ''{{hitt{*?}}}'' nog eens onderstrepen. Ik heb deze ooit toegepast in een voorziening om scripts te genereren, volgens het principe //scriptsjabloon// &times; //gegevensbestand// <<eval "{{tt{$-->}}}">> //verzameling van specifieke scripts//, bekend van de faciliteiten voor mail merging in tekst&shy;verwerkers en database&shy;pakketten.
&para; Omdat ik deze voorziening destijds in Ruby heb gebouwd, bevatten de {{shaded{slides 2 en 3}}} een flitscursusje Ruby waarin enkele Ruby-statements zijn vertaald naar Python. Een wat grondiger uitleg is te vinden in [[Ruby voor Python-programmeurs]].
&para; Daarna volgt wat mij motiveerde om daadwerkelijk een vermenig&shy;vuldigings&shy;script {{sans t{multiply.rb}}} te bouwen, waarin ik ook zo hier en daar non-greedy kwantoren toepaste. In 2011 betrof het een logistiek systeem voor bestands&shy;uitwisseling tussen verschillende applicaties van verschillende partijen op verschillende platforms. Op het mainframe waren er zo'n duizend of meer JCL-scripts van slechts twaalf typen nodig. Ik had geen zin om die allemaal met de hand te schrijven. Dus fluks dat Ruby-script gebouwd om met behulp van reguliere expressies sjablonen te laten invullen. Er speelden nogal wat verschillende dimensies mee: omgevingen volgens de OTAP-opzet (ontwikkel/test/acceptatie/productie), transport&shy;lijnen, standaard&shy;arrangementen, jobtypes en user-ID's. Daarom moest {{sans t{multiply.rb}}} herhaald worden uitgevoerd. {{shaded{Slide 4}}} laat het stroomschema daarvan zien.
&para; Voor de inhoud van een scriptsjabloon en een bijbehorend gegevens&shy;bestand heb ik een eenvoudiger voorbeeld gekozen. {{shaded{Slide 5}}} toont een sjabloon voor een batch file waarmee een task (taak) voor de Windows Task Scheduler (Windows Taakplanner) wordt gedefineerd. Van het bijbehorende gegevens&shy;bestand, dat in [[YAML]]-formaat is opgemaakt, is een knipseltje in {{shaded{slide 6}}} gezet.
&para; Dan duiken we de programmacode van {{sans t{multiply.rb}}} in. De {{shaded{slides 7 en 8}}} gaan over het samenvoeg&shy;proces, dat wil zeggen het substitueren en formatteren van de juiste waarden uit een gevens&shy;bestand voor alle sjabloon&shy;variabelen. Voor elke regel in het sjabloon&shy;bestand wordt de methode {{tt t{expand_line}}} aangeroepen. Binnen die methode wordt de eigenlijke vervangings&shy;operatie in tien regels (de lege regels niet meegeteld) door middel van vier reguliere expressies uitgevoerd. Daarbij bevat de instance&shy;variabele {{tt t{@context}}} alle benodigde informatie uit het gegevens&shy;bestand en retourneert de bijbehorende methode {{tt t{find_scalar}}} de juiste waarde voor de sjabloon&shy;variabele waarvan de naam in groep 1 is terechtgekomen.
&para; In 2013 heb ik voor een ander project de mogelijkheid toegevoegd om aparte bestanden als subsjabloon in te sluiten in een hoofdsjabloon. Dat is een bewerking die voorafgaat aan het samen&shy;voegen met een gegevens&shy;bestand. Zo'n subsjabloon kan zowel sjabloon&shy;variabelen als subsjabloon&shy;variabelen bevatten. Voor gewone sjabloon&shy;variabelen worden uiteindelijk in de samenvoeg&shy;fase de waarden uit het gegevens&shy;bestand ingevuld. Subsjabloon&shy;variabelen daarentegen worden reeds tijdens het voorafgaande insluiten in het hoofd&shy;sjabloon vervangen. In het laatste geval specifeert het hoofd&shy;sjabloon per insluiting welke waarden daarbij moeten worden gebruikt. {{shaded{Slide 9}}} behandelt het principe vanuit het sjabloon&shy;perspectief, terwijl de {{shaded{laatste slide}}} het bijbehorende algoritme laat zien. Ook hier worden vier reguliere expressies toegepast, maar zijn er 21 regels code nodig. Een aantal elementen verdient wel nadere toelichting:
* De  constante {{tt t{INCLUDE}}} bevat een hash (het Ruby-equivalent van wat in Python een dictionary wordt genoemd) van alle subsjablonen. De methode {{tt t{each}}} itereert over alle sleutel/waarde-paren, waarbij {{tt t{key}}} een {{sans{//<fileref>//}}} volgens slide 9 is, en {{tt t{text}}} de volledige inhoud van het desbetreffende subsjabloon.
* De variabele {{tt t{template_text}}} bevat de volledige tekst van het hoofd&shy;sjabloon. Via de methode {{tt t{gsub!}}} worden alle als sjabloonvariabele afgebakende voorkomens van de {{sans t{//<fileref>//}}} die in de huidige iteratie aan de beurt is (bijvoorbeeld {{tt t{PLACE}}} in slide 9) vervangen.
* De variabele {{tt t{$2}}} bevat de waarde van groep 2 (zoals de string {{tt t{"''{:x =>'' {{sans n{//<xValue>//}}}'', :y =>'' {{sans n{//<yValue>//}}}''}''}}}" in slide 9). Via de methode {{tt t{eval}}} wordt de string geïnterpreteerd als een echte hash. Daarna vindt nog enige nabewerking plaats om alle eventueel voorkomende symbols (bijvoorbeeld {{tt{'':x''}}}), te converteren naar een string ({{tt{"'':x''"}}}). In mijn eigen toepassingen van subsjablonen heb ik gewone sjabloon&shy;variabelen altijd geïdentificeerd door middel van een string, en subsjabloon&shy;variabelen door middel van een symbol. Kan ik tenminste meteen zien wat wat is.
* (Nu ik de code teruglees, zie ik dat de laatste toewijzing aan de variabele {{tt t{duplicate}}} overbodig was. Ik had op deze regel alleen de uitdrukking ''{{pref hitt z{"%#{format_directive}" % duplicate}}}'' hoeven plaatsen.)/%

%/
!!Reguliere expressies behapbaar maken -- "Kijk //dieper// en //verder//"
{{sans t{[[Spronck-H25-spinoff.pdf|data/documents/Spronck-H25-spinoff.pdf]]}}}, //gepresenteerd op 20 april 2024// -- Dit gaat feitelijk niet meer over reguliere expressies. De behandeling ervan was echter wel de aanleiding. Een van de opgaven in hoofdstuk 25 van //De programmeursleerling// blijkt namelijk, als je er wat langer naar kijkt, vatbaar voor zeven verschillende interpretaties. Ik vond dit zevental als zodanig eigenlijk interessanter dan de uitdaging om het met reguliere expressies te doen, want reguliere expressies zijn niet in staat om echt //alle// denkbare substrings te vinden die aan een bepaald patroon voldoen.
&para; Wat me intrigeerde, was het volgende. Een string kan volgens elk van de zeven interpretaties wel of niet zodanige substrings bevatten dat die string aan het gestelde patroon voldoet. In theorie zijn er dus 2^^7^^ = 128 verschillende combinaties van die zeven wel/niet-uitkomsten mogelijk, mits alle interpretaties geen logische consequenties voor een of meer van de andere interpretaties hebben. Het was me echter al snel duidelijk dat er wel degelijk onderlinge afhankelijk&shy;heden waren. Ik kon een heel stel combinaties via een beetje nadenken afstrepen. Anderzijds kon ik een aardig stel combinaties als een mogelijkheid aanmerken door gewoon wat testgevallen uit te proberen. Maar uiteindelijk kon ik niet via puur logisch redeneren tot onweerlegbare uitspraken over het volledige 128-tal komen. Wat ik wèl kon, was wat velen doen als de denkkracht tekort&shy;schiet, namelijk simuleren.
&para; Om dieper te onderzoeken wat een string aan substrings herbergt en wat de gevolgen daarvan zijn, heb ik zelf een algoritme geschreven dat uitputtend alle mogelijke substrings inventariseert. Vervolgens wordt voor de gehele verzameling van oorspronkelijke string plus alle substrings ervan vastgesteld aan welke van de zeven interpretaties deze verzameling voldoet. 
&para; Om verder te gaan met het opstellen van testgevallen waar het me te veel wordt om ze zelf te verzinnen, heb ik een generator van teststrings toegevoegd. Ik hoef nu alleen nog maar op te geven tot welke lengte er strings moeten worden beproefd.
&para; +++(~ReguliereExpressiesInPython)[Het resulterende Python-programma &darr;|show][Het resulterende Python-programma &uarr;|hide]
{{{
# Script: 2510_Analysis-2024.py
# Datum : 2024-03-26, Meindert Meindertsma

#---- Exercise ----#
#     EN: Can you change the regular expression so that it checks
#         whether it contains at least two characters twice?
#         The two repeated characters must be different.
#     NL: Kun je de reguliere expressie wijzigen zodat het een
#         patroon beschrijft waarbij twee tekens twee keer voorkomen?
#         De twee tekens moeten verschillend zijn.
#     Interpretations:
#     1. Exactly two characters exactly two times within entire string
#     2. Exactly two characters exactly two times within found substring
#     3. Exactly two characters at least two times within entire string
#     4. Exactly two characters at least two times within found substring
#     5. At least two characters exactly two times within entire string
#     6. At least two characters exactly two times within found substring
#     7. At least two characters at least two times

import sys
import re

#---- Initial settings ----#
REQ1       = " 1" 
REQ2       = " 2" 
REQ3       = " 3" 
REQ4       = " 4" 
REQ5       = " 5" 
REQ6       = " 6" 
REQ7       = " 7" 
MAXLEN     = 9
BASE       = 3
SUMMARIZED = False
CSV        = False
STRING     = ""

#---- Arguments ----#
for arg in sys.argv[1:]:
    if m := re.match("[LM](\d+)", arg, re.I):
        MAXLEN     = max(int(m[1]), 4)
    if m := re.match("b(\d+)", arg, re.I):
        BASE       = max(int(m[1]), 2)
    if re.match("sum", arg, re.I):
        SUMMARIZED = True
    if re.match("csV", arg, re.I):
        CSV        = True
    if m := re.match("'(\w+)", arg):
        STRING     = m[1]

if STRING:
    STRING = (STRING + "****")[:max(len(STRING), 4)]
    MAXLEN = len(STRING)
else:
    print("MAXLEN     =", MAXLEN    , file=sys.stderr)
    print("BASE       =", BASE      , file=sys.stderr)
    print("SUMMARIZED =", SUMMARIZED, file=sys.stderr)
    print("CSV        =", CSV       , "\n", file=sys.stderr)

#---- Predefined foundation ----#
FOUNDATION = { (0,0,0,0): 0
             , (0,0,0,1): 1
             , (0,0,1,0): 1
             , (0,0,1,1): 1
             , (0,1,0,0): 1
             , (0,1,0,1): 1
             , (0,1,1,0): 1
             , (0,1,1,1): 1
             }
if BASE >= 3:
    FOUNDATION |= { (0,0,1,2): 2
                  , (0,1,0,2): 2
                  , (0,1,1,2): 2
                  , (0,1,2,0): 2
                  , (0,1,2,1): 2
                  , (0,1,2,2): 2
                  }
elif BASE > 3:
    FOUNDATION[(0,1,2,3)] = 3

#---- Incrementer ----#
class Incrementer:
    def __init__(self, integers, base=BASE, highest=0):
        self.integers = integers         # a list of valid natural numbers
        self.len      = len(integers)
        self.maxvalue = base - 1
        self.highest  = highest

    def inc(self):
        i = len(self.integers) - 1
        while True:
            if self.integers[i] < self.maxvalue:
                self.integers[i] += 1
                return self.integers, self.assess()
            else:
                self.integers[i] = 0
                if i == 0:
                    return [0] * self.len, self.assess()
                i -= 1

    def assess(self):
        worthwhile = True
        maxi       = self.highest
        for i in self.integers:
            if i > maxi + 1: worthwhile = False
            maxi = max(i, maxi)
        return worthwhile

#---- String analyzer ----#
def analyze(string):
    compliance  = [" --"] + [" ."] * 7
    full_string = True

    #---- Too short ----#
    if len(string) < 4:
        return f"{string:{MAXLEN}s}{''.join(compliance)} (too short)"

    #---- Analysis ----#
    for first in range(len(string) - 3):
        for last in range(len(string), first + 3, -1):
            substring = string[first:last]
            #---- Different characters and their quantities ----#
            chars = {}
            for ch in substring:
                if chars.get(ch): chars[ch] += 1
                else            : chars[ch]  = 1

            #---- Number of characters occurring twice or even more ----#
            n_occ_ge_2 = 0
            n_occ_eq_2 = 0
            for qty in chars.values():
                if qty >= 2:
                    n_occ_ge_2 += 1
                    if qty == 2:
                        n_occ_eq_2 += 1

            #---- Compliance to different interpretations ----#
            if n_occ_ge_2 >= 2:
                compliance[7] = REQ7
                if n_occ_ge_2 == 2:
                    compliance[4] = REQ4
                    if full_string:
                        compliance[3] = REQ3
                if n_occ_eq_2 >= 2:
                    compliance[6] = REQ6
                    if full_string:
                        compliance[5] = REQ5
                    if n_occ_eq_2 == 2:
                        compliance[2] = REQ2
                        if full_string:
                            compliance[1] = REQ1

            full_string = False

    return f"{string:{MAXLEN}s}{''.join(compliance)}"

#----- MAIN PROGRAM ----#
if STRING:
    #---- Just one received string to be analyzed ----#
    print(analyze(STRING))

else:
    #---- Generation of strings to be analyzed ----#
    results = {}
    for seq, highest in FOUNDATION.items():
        string = "".join([chr(i+97) for i in seq])

        for size in range(MAXLEN - 3):
            maximum = 2
            for i in range(3, size+2):
                maximum *= min(i, BASE, size+1)

            incrementer = Incrementer([BASE] * size, highest=highest)
            for i in range(BASE ** size):
                if size == 0:
                    extension  = ""
                    worthwhile = True
                else:
                    inc, worthwhile = incrementer.inc()
                    extension = ''.join([chr(i+97) for i in inc])
                if worthwhile:
                    finding = analyze(string + extension)
                    results[finding[:MAXLEN]] = finding[MAXLEN:]

    if SUMMARIZED:
        compliance_patterns = {}
        sum = 0
        if CSV:
            print('"Compliance";"Quantity"')
        for compliance in results.values():
            compliance = compliance[4:]
            if compliance_patterns.get(compliance):
                compliance_patterns[compliance] += 1
            else:
                compliance_patterns[compliance] = 1
        for compliance, qty in sorted(compliance_patterns.items()):
            if CSV:
                print(f'"{compliance}";{qty}')
            else:
                print(f"{compliance} {qty:9}")
            sum += qty
        if CSV:
            print(f'"";{sum}')
        else:
            print(" " * 13, "-"* 9) 
            print(f"{sum:23}")
    else:
        if CSV:
            print('"String";"Compliance"')
        for string, compliance in results.items():
            if CSV:
                print(f'"{string.rstrip(" ")}";"{compliance[4:]}"')
            else:
                print(string + compliance)
}}}
{{lift{}}}
===


----
|bare|k
|<html><a name="1">[1]</a></html> |<<tiddler Bibliografie##Spronck>> |
/%
!info
|Name|ReplaceTiddlerTitle|
|Source|http://www.TiddlyTools.com/#ReplaceTiddlerTitle|
|Version|2.0.0//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|replace tiddler's title text with other content - may include wiki syntax|
Usage:
<<<
{{{
<<tiddler ReplaceTiddlerTitle with: [[new title text]]>>
}}}
*text can include wiki-syntax formatting (even links and macros!)
*all double-quotes must be preceded by backslash (e.g., {{{[[He said, \"like this\"]]}}})
*if the text contains any macros that use //evaluated parameters//, the closing {{{}} }}}sequence in those parameters must be backslash-quoted (e.g., {{{[[<<someMacro {{...eval param...}\}>>]]}}})
<<<
!end
!show
<<tiddler {{
	var here=story.findContainingTiddler(place); if (here) {
		var nodes=here.getElementsByTagName("*");
		for (var i=0; i<nodes.length; i++) if (hasClass(nodes[i],"title"))
			{ removeChildren(nodes[i]); wikify("$1",nodes[i]); break; }
	}
'';}}>>
!end
%/<<tiddler {{'ReplaceTiddlerTitle##'+("$1"=='$'+'1'?'info':'show')}} with: [[$1]]>>/%  <-- 2021-01-23: Replaced single quotes with double quotes %/
!Single-level flows
Workflows are usually depicted by a directed graph, such as the //UML activity diagram// below.{{ref{[[[1]|##1]]}}} This example contains the basic components: processes (round cornered nodes), their sequence (arrows), concurrency (from «fork» to correponding «join»), and choice (from «decision» to corresponding «merge»).

[img[Activity diagram Alpha-Hotel|data/images/AD Alpha-Hotel.png]]

This graph can be converted to the hierarchical structure below.{{ref{[[[2]|##2]]}}} The left side shows the most common rendering of the resulting tree, with the root at the top and the branches hanging down. At the right side, the tree is transposed so that the logical top-down direction goes from left to right.

[img[Structure diagram Alpha-Hotel|data/images/StruD Alpha-Hotel.png]]

It's a small step from the right side graph to a representation by pure ASCII text:
{{{
<<sequence>>
   01 Alpha
   02 Bravo
   03 <<fork>>
      -= <<sequence>>
         01 Charlie
         02 <<decision>>
            <> Delta
            <> Echo
         03 Foxtrot
      -= Golf
   04 Hotel
}}}
The sequence numbers {{hitt{01}}}, {{hitt{02}}}, ..., fork symbols {{hitt{-=}}}, and radio buttons {{hitt{<>}}} indicate the nature of the branches, making the stereotype labels redundant. Therefore they may be omitted. Doing so results in a more condensed image:
{{{
<<sequence>>
   01 Alpha
   02 Bravo
   03 -= 01 Charlie
         02 <> Delta
            <> Echo
         03 Foxtrot
      -= Golf
   04 Hotel
}}}
Choices can be more elaborated, in different ways{{ref{[[[3]|##3]]}}}:
{{{
         ...                      |          ...
         02 <<completed?>>        |          02 <[completed]> Delta
            <[yes]> Delta         |             <[stranded]> Echo
            <[no]>  Echo          |          ...
         ...                      |
}}}
It won't probably be very practical in most cases, but it is even possible to replace the two-dimensional text layout of the tree with a one-dimensional formula:
{{pre{
Alpha, Bravo, ((Charlie, (Delta | Echo), Foxtrot) & Golf), Hotel
}}}/%


%/<html><h1>Multi-level flows</h1></html>/%

%/
[img[Activity diagram Superalpha-Hotel|data/images/AD Superalpha-Hotel.png]]

Constructs of nested processes on different levels can be treated the same way. The workflow above can be represented by the tree structures below:
{{pre{
''Superalpha''                        | ''Superalpha''
   01 Alpha                       |    01 Alpha
   02 Bravo                       |    02 Bravo
   03 """<<fork>>"""                    |    03 -= ''Supercharlie''
      -= ''Supercharlie''             |          01 Charlie
         01 Charlie               |          02 <> Delta
         02 """<<decision>>"""          |             <> Echo
            <> Delta              |          03 Foxtrot
            <> Echo               |       -= Golf
         03 Foxtrot               |    04 Hotel
      -= Golf                     |
   04 Hotel                       |
}}}/%
%/And by this one-liner, if you really want:
{{pre{
Superalpha = (Alpha, Bravo, ((Supercharlie = (Charlie, (Delta | Echo), Foxtrot)) & Golf), Hotel)
}}}
Now we can distinguish two kinds of levels: //branching levels// in the tree representation and //nesting levels// of modules in the flow. Pseudo-processes like «sequence», «fork», and «decision» are not regarded as a module. Making the nesting levels explicit in the tree representation can be done by putting them as annotation in the left margin of the tree:
{{pre{
@@color:darkorange;0  @@''Superalpha''
@@color:darkorange;1  ·  @@01 Alpha
@@color:darkorange;1  ·  @@02 Bravo
@@color:darkorange;1  ·  @@03 -= ''Supercharlie''
@@color:darkorange;2  ·  ·  ·  @@01 Charlie
@@color:darkorange;2  ·  ·  ·  @@02 <> Delta
@@color:darkorange;2  ·  ·  ·  ·  @@<> Echo
@@color:darkorange;2  ·  ·  ·  @@03 Foxtrot
@@color:darkorange;2  ·  ·  @@-= Golf
@@color:darkorange;1  ·  @@04 Hotel
}}}/%
%/The number of dots in this example indicate the branching level (as far as they are not covered by other elements due to the omission of the stereotypes: Supercharlie deserves two dots like Golf, and Delta deserves four dots like Echo). In bigger trees, they are helpful as a guideline for the eye. That is actually their only function./%


%/<html><h1>Multipliers (optionality/cardinality), conditions, and comments</h1></html>/%
%/{{pre{
"""<<sequence>>              // double slashes mark the beginning of an end-of-line comment
   01 {?} India           // performance of India is optional         (same as {0..1})
   02 {*} Juliett         // Juliett is performed zero or more times  (same as {0..*})
   03 {+} Kilo            // Kilo is performed one or more times      (same as {1..*})
   04 {3} Lima            // Lima is performed three times            (same as {3..3})
   05 {2..*} Mike         // Mike is performed two or more times
   06 {1..24} November    // November is performed 1 to 24 times
   07 [workday] Oscar     // Oscar is only performed on workdays, otherwise skipped
   08 [completed] Papa    //""" Papa is only performed if Oscar has been completed, otherwise skipped
}}}/%
%/Multipliers can be extended with intervals: {{hitt s{{6/0:30"""}"""}}} means six times with an interval of 30 minutes; if an iteration is still running when it's time for the next iteration to start, that next iteration is skipped.

The condition {{hitt s{[completed]}}} refers to all immediate predecessors.

Time conditions can also be formulated:
{{{
<<fork>>
   -= [01:00] Un             // If it's 1:00, Un is executed, otherwise Un is skipped
   -= [02:00~] Deux          // If it's 2:00 or later, Deux is executed, otherwise Deux is skipped
   -= [03:00~03:30] Trois    // If it's 3:00 or later but earlier than 3:30, Trois is executed, otherwise Trois is skipped 
   -= [~4:00] Quatre         // If it's earlier than 4:00, Quatre is executed, otherwise Quatre is skipped
}}}

Conditions can be combined with {{hitt s{&}}} (AND) and {{hitt s{|}}} (OR) operators, e.g. {{hitt s{[workday & completed]}}}. Conditions can also be combined with multipliers. The order of these elements is relevant:
{{pre{
"""<<sequence>>
   01 Long-preparation-of-fluctuating-duration
   02 -= [~12:00] {10} Morning-routine-with-start-criterion    // procedure starts iterating ten times if it isn't 12:00 yet, otherwise all ten iterations are skipped
      -= {10} [~12:00] Morning-routine-with-stop-criterion     // procedure iterates ten times, but iterations starting at 12:00 or later are skipped
"""}}}/%


%/<html><h1>Timing, reacting on events</h1>
<h3>Time triggers</h3></html>/%
%/{{pre{
Breviary
   -= @[00:00] Matins
   -= @[03:00] Lauds
   -= @[06:00] Prime
   -= @[09:00] Terce
   -= @[12:00] Sext
   -= @[15:00] None
   -= @[18:00] Vespers
   -= 01 @[21:00] Compline
      02 @[wait 0:05] Sleep
}}}/%

%/<html><h3>Other triggers</h3></html>/%
%/{{pre{
"""<<sequence>>
   01 Quebec
   02 -= @[completed] Romeo         // default trigger: Romeo is started after Quebec has been completed   (solid line in Opswise)
      -= @[stranded] Sierra         // Siera is started after Quebec is stranded                           (dotted line in Opswise)
      -= @[terminated] Tango        // Tango is started after Quebec has reached an arbitrary final state  (dotted line in Opswise)
      -= @[exitcode = ...] Uniform  // Uniform is started after Quebec has ended with exit code = ...      (dotted line in Opswise)
      -= 01 Victor
         02 <1>                     // pseudo-process, indicating a milestone in the flow
      -= 01 Whiskey
         02 <2>                     // pseudo-process, indicating another milestone in the flow
      -= @<1> X-ray                 // X-ray is started after milestone <1> has been reached               (shorthand for @[<1>])
      -= @<1 & 2> Yankee            // Yankee is started after milestones <1> and <2> have been reached    (shorthand for @[<1> & <2>])
      -= @<1 | 2> Zulu              // Zulu is started after milestone <1> or <2> has been reached         (shorthand for @[<1> | <2>])
"""}}}/%
%/The usual comparison operators ''='', ''<>'', ''<'', ''<='', ''>'', ''>='', and ''{{{in}}}'' may be used for exitcode checks, and constructions like {{hitt s{@[exitcode in (1, 5, 22..30)]}}} are allowed.

A milestone has only two states: reached or not reached. It does not count as immediate predecessor of its immediate successors, and therefore its immediate predecessors are taken as immediate predecessors of its immediate successors.

Triggers referring to the state of a process, refer to all immediate predecessors in a specific way:
*  {{hitt s{@[completed]}}} means {{hitt s{@[''all'' completed]}}}, it requires that all immediate predecessors have been completed.
*  {{hitt s{@[stranded]}}} means {{hitt s{@[''some'' stranded]}}}, it requires that at least one of all immediate predecessors are stranded.
*  {{hitt s{@[terminated]}}} means {{hitt s{@[''all'' terminated]}}}, it requires that all immediate predecessors are terminated.
*  {{hitt s{@[exitcode ...]}}} means {{hitt s{@[''max'' exitcode ...]}}}, it requires that the maximum of the exitcodes of all immediate predecessors meets the condition./%
%/
The quantifiers ''{{{all}}}'', ''{{{some}}}'', ''{{{max}}}'', and ''{{{min}}}'' may be applied explicitly at will. Milestones can be added to indicate specific immediate predecessors, e.g. {{hitt s{@[<3> stranded]}}} or {{hitt s{@[exitcode <3> = ...]}}}. As a consequence, milestone //<3>// must be made reachable for its failing predecessor by {{hitt s{[terminated] <3>}}}. 

Trigger conditions can be combined with {{hitt s{&}}} (AND) and {{hitt s{|}}} (OR) operators. So {{hitt s{[terminated]}}} could be reformulated more circumlocutory as {{hitt s{[completed | stranded]}}}.

Triggers may be combined with conditions for executing/skipping and multipliers:
{{pre{
"""Breviary
   -= @[00:00] [awake] Matins             // the Matins start at 0:00 if awake, or are skipped otherwise
   -= @[03:00~ & awake] Lauds             // the Lauds start at 3:00 if awake, or are postponed until awake
   -= @[06:00~ & awake] [~08:30] Prime    // the Prime starts at 6:00 if awake, or is postponed until awake,
                                          // but will be skipped when the awake event happens at 8:30 or later
   -= @[09:00] Terce                      // the Terce starts anyway at 9:00
   -= 01 @[12:00] {12} Bong               // clock strikes twelve at 12:00 ...
      02 Sext                             // ... followed by the Sext
   -= @[15:00] None
   -= @[18:00] Vespers
   -= 01 @[21:00] Compline
      02 @[wait 0:05] [~23:45] Sleep      // Sleep starts 5 minutes after completion of Compline,
                                          // but will be skipped if it hasn't been started before 23:45
"""}}}/%


%/<html><h1>Taking control</h1></html>/%
%/{{pre{
"""Aleph
   01 Beth
   02 -= 01 @[exitcode = 0] Gimel
         02 <return success>           // pseudo-process: Aleph is completed successfully when none of its subprocesses are running anymore
      -= 01 @[exitcode = 1..4] Daleth
         02 <return held>              // pseudo-process: Aleph is put on hold when none of its subprocesses are running anymore
      -= 01 @[exitcode > 4] He
         02 <return failed>            // pseudo-process: Aleph has ended as a failure when none of its subprocesses are running anymore
"""}}}/%
%/When ''Beth'' ends with exitcode {{{0}}}, ''Daleth'' and ''He'' will keep on waiting, and so will their immediate successors //<return held>// and //<return failed>//. After completion of ''Beth'', the directive //<return success>// is needed to force the completion of ''Aleph''. Since the conditions in this example are mutually exclusive, a better representation would have been to make ''Aleph''-step {{{02}}} a decision point:
{{pre{
"""Aleph
   01 Beth
   02 <[exitcode = 0]> Gimel  // no pseudo-process needed here, since the other two options are skipped
      <[exitcode = 1..4]>
         01 Daleth
         02 <return held>     // pseudo-process: Aleph is held when none of its subprocesses are running anymore
      <[else]>
         01 He
         02 <return failed>   // pseudo-process: Aleph has ended as a failure when none of its subprocesses are running anymore
"""}}}/%
%/Another valid model, with three ''Aleph''-steps that are executed or skipped conditionally one by one:
{{pre{
"""Aleph
   01 Beth
   02 [exitcode = 0] Gimel    // no pseudo-process needed in this Aleph-step, since the processes of the next two steps 03 and 04 will be skipped
   03 [exitcode = 1..4]
         01 Daleth
         02 <return held>     // pseudo-process: Aleph is put on hold when none of its subprocesses are running anymore
   04 [exitcode > 4]
         01 He
         02 <return failed>   // pseudo-process: Aleph is ended as a failure when none of its subprocesses are running anymore
"""}}}/%


%/<html><h1>Dealing with N-structures</h1></html>/%
%/If a diagram is completely free of N-structures, it can be converted to a tree, and otherwise it is impossible.{{ref{[[[4]|##4]]}}} So the flowchart below cannot be represented in a purely hierarchical format.

[img[Activity diagram N-structure|data/images/AD N-structure.png]]

When cheating is acceptable however, one can create a tree decorated with a web of references. The ingredients for this were presented in the previous sections. So you could put up this construction:
{{{
<<fork>>
   -= 01 A
      02 <1>       // milestone <1> waits for the completion of process A
      03 B         // process B waits for milestone <1> being reached
   -= 01 C         // process C runs concurrently with the sequence of processes A and B
      02 @<1> D    // process D waits for the completion of process C and milestone <1> being reached, and then runs concurrently with process B
}}}
It is recommended to define milestones //before// referring to them. So if there is some reason to mention //C// before //A//, the tree should be build up like this:
{{pre{
"""<<fork>>
   -= 01 C
      02 <1>          // milestone <1> waits for the completion of process C
   -= 01 A            // process A runs concurrently with process C
      02 -= B         // process B waits for the completion of process A, and then runs concurrently with process C
         -= @<1> D    // process D waits for the completion of process A and milestone <1> being reached, and then runs concurrently with process B
"""}}}/%

%/Sometimes a process being part of an N-structure acts just as a time or event trigger, and that N-structure would vanish if that trigger could be dropped. In such cases you can ignore it as a process and model it as a trigger {{pref hitt s{@[...]}}}./%

%/
!!!How to recognise an N-structure
Four processes //A//, //B//, //C//, //D// constitute an N-structure if and only if all of the following conditions are met:
#//A// &#x227a; //B//
#//A// &#x227a; //D//
#//C// &#x227a; //D//
#//A// &#x2280; //C//
#//C// &#x2280; //A//
#//B// &#x2280; //C//
#//C// &#x2280; //B//
#//B// &#x2280; //D//
#//D// &#x2280; //B//
The ''&#x227a;'' operator means 'precedes'. That doesn't mean that //A// has to be the //immediate// predecessor of //B//. An long sequence of other processes may take place between the end of //A// and the beginning of //B//. Consequently, the ''&#x2280;'' operator means the opposite: 'does not precede'. Realize that //X// &#x227a; //Y// implies //Y// &#x2280; //X//, but that //Y// &#x2280; //X// does not imply //X// &#x227a; //Y//. The third possible relation between //X// and //Y// is that they are concurrent.

The flow at the left side below does not contain an N-structure. You might see two mirrored Ns in the apparent diabolo structure, but that's misleading: the diabolo can be reduced to the simple X-structure in the diagram at the right side. A more exact way to determine that it does not contain an N-structure, is checking the conditions. The 7th condition //C// &#x2280; //B// is not met in this case.

[img[Activity diagram AD non-N-structure|data/images/AD non-N-structure.png]]

----
|bare|k
|<html><a name="1">[1]</a></html> |The so-called //initial nodes// and //final nodes// are left out in the given examples. In fact I omit them structurally when drawing scheduling diagrams, see:<br>Meindert Meindertsma, //~OPC-schema's -- Gecondenseerde tekentechniek//. Getronics ~PinkRoccade, 2007. |
|<html><a name="2">[2]</a></html> |The symbols applied here are inspired by the decomposition diagrams in:<br><<tiddler "Bibliografie##Martin (EN)">> |
|<html><a name="3">[3]</a></html> |The designation of process states are inspired by the [[status names in Opswise|State transitions in Opswise]]. But I was not so happy with the aggregate states as employed in the Condition property of the Opswise connectors. That's why I've used three other terms, as a substitute for the red terms used in Opswise. 'Completed' @@color:red;//(Success)//@@ means //Success// ({{{200}}}), //Finished// ({{{190}}}), or //Skipped// ({{{180}}}). 'Stranded' @@color:red;//(Failure)//@@ means //Failed// ({{{140)}}}, //Cancelled//({{{130}}}), or //Start Failure// ({{{120}}}). 'Terminated' @@color:red;//(Success/Failure)//@@ means 'completed or stranded', which comprehends all final statuses in Opswise. Other schedulers may have other classifications. |
|<html><a name="4">[4]</a></html> |<<tiddler Bibliografie##Błażewicz>> |
<script>console.devlog = "----\nDevelopment log: " + new Date().toString() + "\n"; return "{{{\n" + console.devlog + "\n}}}"</script>
!![[Scheme standards|https://standards.scheme.org/]]
@@position:relative;left:0.9em;0. [[R0RS|https://standards.scheme.org/official/r0rs.pdf]] //Scheme -- An interpreter for extended lambda calculus// (1975)@@
# [[R1RS|https://standards.scheme.org/official/r1rs.pdf]] //The Revised Report on Scheme -- A dialect of Lisp// (1978)
# {{_{[[R2RS|https://standards.scheme.org/official/r2rs.pdf]] //The Revised Revised Report on Scheme -- An Uncommon Lisp// (1985)
[[HTML-versie|https://github.com/schemedoc/r2rs]] om tekst te kunnen doorzoeken en kopiëren}}}
# [[R3RS|https://standards.scheme.org/official/r3rs.pdf]] //Revised^^&#x200a;3^^ Report on the algorithmic language Scheme// (1986)
# [[R4RS|https://standards.scheme.org/official/r4rs.pdf]] //Revised^^&#x200a;4^^ Report on the algorithmic language Scheme// (1991)
# {{_{[[R5RS|https://standards.scheme.org/official/r5rs.pdf]] //Revised^^&#x200a;5^^ Report on the algorithmic language Scheme// (1998)
[[Gecorrigeerde versie (HTML)|https://standards.scheme.org/corrected-r5rs/r5rs.html]]
[[Errata (HTML)|https://mumble.net/~kelsey/r5rs-errata.html]]}}} 
# [[r6rs.org|https://www.r6rs.org/]]:
** [[R6RS|https://www.r6rs.org/final/r6rs.pdf]] //Revised^^&#x200a;6^^ Report on the algorithmic language Scheme// (2007)
** [[R6RS-lib|http://www.r6rs.org/final/r6rs-lib.pdf]] //Revised^^&#x200a;6^^ Report on the algorithmic language Scheme -- Standard libraries// (2007)
** [[R6RS-app|http://www.r6rs.org/final/r6rs-app.pdf]] //Revised^^&#x200a;6^^ Report on the algorithmic language Scheme -- Non-normative appendices// (2007)
** [[R6RS-rationale|http://www.r6rs.org/final/r6rs-rationale.pdf]] //Revised^^&#x200a;6^^ Report on the algorithmic language Scheme -- Rationale// (2007)
** Gecorrigeerde versies (2019) en errata: zie https://standards.scheme.org/.
# [[small.r7rs.org|https://small.r7rs.org/]]
**[[R7RS-small|https://small.r7rs.org/attachment/r7rs.pdf]] //Revised^^&#x200a;7^^ Report on the algorithmic language Scheme// (2013)
**[[Errata|https://small.r7rs.org/wiki/R7RSSmallErrata/]]/%

%/
!!Alternatieve links en [[Scheme Requests for Implementation (SRFI)|https://speechcode.com/blog/growing-schemes]]
* [[R0RS|https://dspace.mit.edu/bitstream/handle/1721.1/5794/AIM-349.pdf]]
* [[R1RS|https://dspace.mit.edu/bitstream/handle/1721.1/6283/AIM-452.pdf]]
* [[R2RS|https://dspace.mit.edu/bitstream/handle/1721.1/5600/AIM-848.pdf]]
* [[R3RS|https://dl.acm.org/doi/pdf/10.1145/15042.15043]]
* [[R4RS|https://people.csail.mit.edu/jaffer/r4rs.pdf]]
* [[R5RS|https://conservatory.scheme.org/schemers/Documents/Standards/R5RS/r5rs.pdf]]
* [[Scheme Requests for Implementation|https://srfi.schemers.org/]]/%

%/
!!Concepten en notaties bij het beschrijven van de semantiek
* <<tiddler Bibliografie##Felleisen>> &larr; ''R6RS''
* <<tiddler Bibliografie##Matthews-2004>> &larr; ''R6RS''
* <<tiddler Bibliografie##Matthews-2005>> &larr; ''R6RS''
* <<tiddler Bibliografie##Matthews-2007>> &larr; ''R6RS''
* <<tiddler Bibliografie##Stoy>> &larr; ''R5RS'', ''R7RS''
* <<tiddler Bibliografie##Wright>> &larr; ''R6RS''
<<tiddler ToggleRightSidebar>>
<<tiddler RefreshPageDisplay with: {{config.options.chkFixRightSidebar ? "&#x2b0d;" : "&#x1f793;";}} {{(config.options.chkFixRightSidebar ? "un" : "") + "fix both sidebars";}}>>
<script>
  var co = config.options;
  var sb = document.getElementById('sidebar');
  var gt = document.getElementById('gotoTiddler');

  co.chkFixRightSidebar = !co.chkFixRightSidebar;

  sb.style.position = co.chkFixRightSidebar ? 'absolute' : 'fixed';
  sb.style.bottom   = co.chkFixRightSidebar ? ''         : '0';
  gt.style.width    = co.chkFixRightSidebar ? '165px'    : '150px';
</script>
/***
|Name|SectionLinksPlugin|
|Source|http://www.TiddlyTools.com/#SectionLinksPlugin|
|Documentation|http://www.TiddlyTools.com/#SectionLinksPlugin|
|Version|1.4.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|allow tiddler sections in TiddlyLinks to be used as anchor points|
This plugin enhances tiddler links so that they can include section references that ''auto-scroll to the indicated section heading'' within a tiddler (i.e., similar to the 'anchor' behavior provided in HTML by {{{<a name="foo">}}} and {{{<a href="#foo">...</a>}}}).  The {{{<<tiddler>>}}} macro syntax has also be extended to allow section references without a tiddler name, so that transclusion of //hidden sections from the same tiddler// can be easily accomplished.  The plugin also adds a new macro, <<sectionTOC>> which can auto-generate and embed a 'Table of Contents' outline view into a tiddler to enable quick navigation to sections within that tiddler.
!!!Usage
<<<
!!!!~TiddlyLink syntax
You can link to a section of a tiddler by adding the "##sectionname" syntax to the tiddlername:
{{{
[[SomeTiddler##SomeSection]]
}}}
When clicked, the tiddler is displayed and the specified section heading is automatically scrolled into view. If the tiddler title is omitted or the 'here' keyword is used, e.g.,
{{{
[[##SomeSection]] or [[here##SomeSection]]>>
}}}
then the current containing tiddler is implied by default.
!!!!HTML anchor syntax
You can use HTML syntax to create a scrollable 'anchor' location within a tiddler without use of the standard TW section heading syntax:
{{{
<html><a name="sectionname" /></html>
}}}
You can then link to that section using the enhanced TiddlyLink syntax as above.
!!!!{{{<<tiddler>>}}} macro 
The {{{<<tiddler>>}}} syntax has been extended so that when the tiddler title is omitted or the 'here' keyword is used, e.g.,
{{{
<<tiddler ##SomeSection>> or <<tiddler here##SomeSection>>
}}}
then the current containing tiddler is implied by default.
!!!!"""<<sectionTOC>>""" macro
This macro generates a 'Table of Contents' outline-style bullet list with links to all sections within the current tiddler.  Simply place the following macro at the //end of the tiddler content// (i.e., following all section headings).  Important note: //''The {{{<<sectionTOC>>}}} macro must occur at the end of the tiddler in order to locate the rendered section headings that precede it.''//
{{{
<<sectionTOC>> or <<sectionTOC className>>
}}}
To position the macro's //output// within the tiddler, you must create a special 'target element' that uses a specific classname (default='sectionTOC'), like this:
{{{
{{sectionTOC{}}}
}}}
When the {{{<<sectionTOC>>}}} macro is rendered, it will find the matching 'sectionTOC'-classed element and writes it's output there.  You can also add the macro and/or target elements directly to the [[ViewTemplate]] definition, so that every tiddler can automatically display the table of contents:
{{{
<span class='sectionTOC'></span> <!-- target element -->
...
<span macro='sectionTOC'></span> <!-- must be at end of tiddler -->
}}}
<<<
!!!Configuration
<<<
You can change the {{{<<SectionTOC>>}}} output link format by adding the following statement to a tiddler tagged with <<tag systemConfig>>
{{{
config.macros.sectionTOC.linkFormat='[[%0|##%0]]';
}}}
The default value (shown above) produces a link to each section within the tiddler, using "%0" to insert the section name into the link.  You can add extra formatting to generate additional output to suit your purposes.  For example, if you have EditSectionPlugin installed, you could include a link that invokes that plugin's popup editor directly from each item in the TOC display, like this:
{{{
config.macros.sectionTOC.linkFormat='[[%0|##%0]] <<editSection [[##%0]] [[(edit)]]>>';
}}}
<<<
!!!Examples
<<<
links to sections defined by ''TW heading syntax'' (e.g, {{{!!!sectionname}}}):{{indent{
[[SectionLinksPlugin##onClickTiddlerLink]]
[[##onClickTiddlerLink]] //(current tiddler implied)//}}}
links to anchors defined by ''HTML syntax'' (e.g., {{{<html><a href="anchorname"></html>}}}):{{indent{
[[SectionLinksPlugin##sampleanchorlink]]
[[##sampleanchorlink]] //(current tiddler implied)//}}}
<<<
!!!Revisions
<<<
2011.12.21 1.4.2 refactor sectionTOCformat to permit customization
2011.02.08 1.4.1 in isExternalLink() hijack, strip section references before testing for external link
2010.08.09 1.4.0 in scrollToSection(), added support for using HTML <a name="..."> anchor elements
2009.08.21 1.3.4 added handling to ignore leading/trailing whitespace in section references
2009.08.21 1.3.3 in createTiddlyLink(), add tiddlyLinkNonExistingSection class if matching section is not found
2009.08.14 1.3.2 in createTiddlyLink(), don't override core value for ~TiddlyLink attribute
2009.08.02 1.3.1 in sectionTOC.handler(), trim leading/trailing whitespace from generated section links
2009.08.01 1.3.0 in scrollToSection(), apply 3-tier section matching (exact, startsWith, contains)
2009.07.06 1.2.2 fixed displayTiddler() hijack
2009.07.03 1.2.1 in {{{<<sectionTOC>>}}}, suppress output if target is not found
2009.06.02 1.2.0 added support for 'here' keyword in {{{[[here##section]]}}} links and {{{<<tiddler here##section>>}}} macro
2009.04.09 1.1.1 in sectionTOC macro, make target visible when TOC is rendered.
2009.01.18 1.1.0 added {{{<<sectionTOC>>}}} macro to generate numbered-bullet links to sections of current tiddler
2009.01.06 1.0.0 converted to stand-alone plugin
2008.10.14 0.0.0 initial release (as [[CoreTweaks]] #784 - http://trac.tiddlywiki.org/ticket/784)
<<<
!!!Code
***/
//{{{
version.extensions.SectionLinksPlugin= {major: 1, minor: 4, revision: 2, date: new Date(2011,12,21)};

Story.prototype.scrollToSection = function(title,section) {
	if (!title||!section) return; var t=this.getTiddler(title); if (!t) return null;
	var elems=t.getElementsByTagName('*');
	var heads=[]; var anchors=[];
	for (var i=0; i<elems.length; i++)
		if (['H1','H2','H3','H4','H5'].contains(elems[i].nodeName)) heads.push(elems[i]);
	for (var i=0; i<elems.length; i++)
		if (elems[i].nodeName=='A' && (elems[i].getAttribute('name')||'').length) anchors.push(elems[i]);
	var found=null;
	for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim()==section) { found=heads[i]; break; }
	if (!found) for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim().startsWith(section)) { found=heads[i]; break; }
	if (!found) for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim().indexOf(section)!=-1) { found=heads[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name')==section) { found=anchors[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name').startsWith(section)) { found=anchors[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name').indexOf(section)!=-1) { found=anchors[i]; break; }
	if (found) {
		// if section heading is collapsed, click to expand it - see [[FoldHeadingsPlugin]]
		if (hasClass(found,'foldable') && found.nextSibling.style.display=='none') found.onclick();
		// scroll *after* tiddler animation
		var delay=config.options.chkAnimate?config.animDuration+100:0;
		setTimeout('window.scrollTo('+findPosX(found)+','+findPosY(found)+')',delay);
		return found;
	}
}
//}}}
/***
!!!!core hijacks
***/
/***
!!!!!createTiddlyLink
***/
//{{{
// [[tiddlername##section]] and [[##section]]
if (!window.createTiddlyLink_section)
	window.createTiddlyLink_section=window.createTiddlyLink;
window.createTiddlyLink=function(place,title) {
	var t=story.findContainingTiddler(place); var tid=t?t.getAttribute('tiddler'):'';
	var parts=title.split(config.textPrimitives.sectionSeparator);
	var title=parts[0]; var section=parts[1]; if (section) section=section.trim();
	if (!title.length || title.toLowerCase()=='here') title=tid;  // default=current tiddler
	arguments[1]=title;
	var btn=createTiddlyLink_section.apply(this,arguments);
	if (section) {
		btn.setAttribute('section',section);
		if (store.getTiddlerText(title+config.textPrimitives.sectionSeparator+section)===null)
			addClass(btn,'tiddlyLinkNonExistingSection');
	}
	return btn;
}
//}}}
/***
!!!!!onClickTiddlerLink
***/
//{{{
if (!window.onClickTiddlerLink_section)
	window.onClickTiddlerLink_section=window.onClickTiddlerLink;
window.onClickTiddlerLink=function(ev) {
	var e=ev||window.event;	var target=resolveTarget(e); var title=null;
	while (target!=null && title==null) {
		title=target.getAttribute('tiddlyLink');
		section=target.getAttribute('section');
		target=target.parentNode;
	} 
	var t=story.findContainingTiddler(target); var tid=t?t.getAttribute('tiddler'):'';
	if (title!=tid||!section) // avoid excess scrolling for intra-tiddler links
		onClickTiddlerLink_section.apply(this,arguments);
	story.scrollToSection(title,section);
	return false;
}
//}}}
/***
!!!!! displayTiddler
***/
//{{{
if (!Story.prototype.displayTiddler_section)
	Story.prototype.displayTiddler_section=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	var parts=title.split(config.textPrimitives.sectionSeparator);
	var title=parts[0]; var section=parts[1]; if (section) section=section.trim();
	if (!title.length || title.toLowerCase()=='here') {
		var t=story.findContainingTiddler(place);
		title=t?t.getAttribute('tiddler'):'';
	}
	arguments[1]=title;  // default=current tiddler
	this.displayTiddler_section.apply(this,arguments);
	story.scrollToSection(title,section);
}
//}}}
/***
<html><a name="sampleanchorlink" /></html>This is a sample ''anchor link'': {{{<html><a name="sampleanchorlink" /></html>}}}
!!!!!isExternalLink
***/
//{{{
if (!config.formatterHelpers.isExternalLink_section)
	config.formatterHelpers.isExternalLink_section=config.formatterHelpers.isExternalLink;
config.formatterHelpers.isExternalLink=function(link) {  // remove section references before testing
	var l=link.split(config.textPrimitives.sectionSeparator)[0];
	return config.formatterHelpers.isExternalLink_section(l);
}
//}}}
/***
!!!!!tiddler.handler
***/
//{{{
if (!config.macros.tiddler.handler_section)
	config.macros.tiddler.handler_section=config.macros.tiddler.handler;
config.macros.tiddler.handler=function(place,macroName,params,wikifier,paramString,tiddler)
{
	if (!params[0]) return;
	var sep=config.textPrimitives.sectionSeparator;
	var parts=params[0].split(sep); var tid=parts[0]; var sec=parts[1]; if (sec) sec=sec.trim();
	if ((tid.toLowerCase()=='here'||!tid.length) && sec) { // fixup for 'here##section' and '##section'
		var here=story.findContainingTiddler(place)
		var tid=here?here.getAttribute('tiddler'):tiddler?tiddler.title:'';
		arguments[2][0]=tid+sep+sec;
		arguments[4]=paramString.replace(new RegExp('(here)?'+sep+sec),tid+sep+sec);
	}
	config.macros.tiddler.handler_section.apply(this,arguments);
}
//}}}
/***
!!!!sectionTOC macro
***/
//{{{
config.macros.sectionTOC = {
	targetClass: 'sectionTOC',
	linkFormat: '[[%0|##%0]]',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var out=[];
		var targetClass=params[0]||this.targetClass;
		var t=story.findContainingTiddler(place); if (!t) return;
		var elems=t.getElementsByTagName('*');
		var level=5; // topmost heading level
		for (var i=0; i<elems.length; i++) {
			var txt=getPlainText(elems[i]).trim();
			var link=this.linkFormat.format([txt]);
			switch(elems[i].nodeName) {
				case 'H1': out.push('#'+link);		level=1; break;
				case 'H2': out.push('##'+link);		level=level<2?level:2; break;
				case 'H3': out.push('###'+link);	level=level<3?level:3; break;
				case 'H4': out.push('####'+link);	level=level<4?level:4; break;
				case 'H5': out.push('#####'+link);	level=level<5?level:5; break;
				default: if (hasClass(elems[i],targetClass)) var target=elems[i];
			}
		}
		// trim excess bullet levels
		if (level>1) for (var i=0; i<out.length; i++) out[i]=out[i].substr(level-1);
		// show numbered list
		if (out.length && target) {
			if (target.style.display=='none') target.style.display='block';
			wikify(out.join('\n'),target);
		}
	}
}
//}}}
/***
!!!Invoke macro
{{{
<<sectionTOC>>
}}}
***/
// //<<sectionTOC>>
{{pre{
<script>return console.devlog</script>
}}}
/%
!info
|Name|ShowDocumentInfo|
|Source|http://www.TiddlyTools.com/#ShowDocumentInfo|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show TiddlyWiki version, document timestamp, and plugin info|
Usage
<<<
{{{
<<tiddler ShowDocumentInfo>>
<<tiddler ShowDocumentInfo with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler ShowDocumentInfo with: "info">>}}}
<<tiddler ShowDocumentInfo##show with: "info">>
<<<
<<tiddler ShowDocumentInfo##code with: {{store.getTiddlerText('ShowDocumentInfo##show')}}>>
!end
!code
Code
<<<
{{{
$1
}}}
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="Show TiddlyWiki version, filedate and tiddler summary"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	if(typeof version==undefined||version.title!='TiddlyWiki')
		{alert(document.location.href+'\n\nis not a TiddlyWiki document');return false;}
	var ver=version.major+'.'+version.minor+'.'+version.revision;
	var tids=window.store.getTiddlers('modified').reverse();
	var plugins=window.store.getTaggedTiddlers('systemConfig','modified').reverse();
	var msg='TiddlyWiki version: '+ver
		+'\nDocument modified: '+document.lastModified
		+'\nLast tiddler changed: '+tids[0].title
		+'\n\nThere are a total of '+tids.length+' tiddlers,'
		+' including '+plugins.length+' plugins:\n\n';
	var fmt='YYYY.0MM.0DD 0hh:0mm:0ss'
	msg+=plugins.map(function(t){return t.modified.formatString(fmt)+' | '+t.title;}).join('\n');
	alert(msg);
 	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='ShowDocumentInfo'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'!='$'+'1'?'$1':'[i] - Show TiddlyWiki document info...'}}>>
/%
!info
|Name|ShowPlugins|
|Source|http://www.TiddlyTools.com/#ShowPlugins|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|generates a report of all installed plugins in a [[PluginInfo]] shadow tiddler|
Usage
<<<
{{{
<<tiddler ShowPlugins>>
<<tiddler ShowPlugins with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler ShowPlugins with: "click me">>}}}
<<tiddler ShowPlugins##show with: "click me">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="view a list of all installed plugins"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var plugins=window.store.getTaggedTiddlers('systemConfig','title');
	var out='|Title|Date|Size|Author|Version|~CoreVersion|h\n|sortable|k\n';
	out+=plugins.map(function(t) {
		return '|'+'[['+t.title+']]'
		+'|'+t.modified.formatString('YYYY.0MM.0DD')
		+'|'+t.text.length
		+'|'+store.getTiddlerSlice(t.title,'Author')
		+'|'+store.getTiddlerSlice(t.title,'Version')
		+'|'+store.getTiddlerSlice(t.title,'CoreVersion')+'|';
	}).join('\n');
	config.shadowTiddlers.PluginInfo=out;
	story.displayTiddler(null,'PluginInfo');"
>$1</a></html>
!end
%/<<tiddler {{var src='ShowPlugins'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'=='$'+'1'?'PluginInfo':'$1'}}>>
/***
|Name|[[ShowPopupPlugin]]|
|Source|http://www.TiddlyTools.com/#ShowPopupPlugin|
|Version|2.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|display tiddler content in a TiddlyWiki popup panel|
!!!!!Documenatation
>see [[ShowPopupPluginInfo]]
!!!!!Revisions
<<<
2011.03.13 2.1.1 in click(), removed check for popup already shown (prevents nested popups!)
| Please see [[ShowPopupPluginInfo]] for previous revision details |
2006.09.09 1.0.0 initial release (transclusion)
<<<
!!!!!Code
***/
//{{{
version.extensions.ShowPopupPlugin=
	{ major:2, minor:1, revision:1, date:new Date(2011,3,13) };
config.macros.showPopup = {
	tip: 'display "%0" in a popup',
	init: function() {
		config.shadowTiddlers.ShowPopup =
			'<<showPopup tiddler:[[$1]] label:"$2" tip:"$3" buttonClass:"button $4" width:"$5" popupClass:"$6" "$7">>';
		config.annotations.ShowPopup =
			'created by ShowPopupPlugin';
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var p=paramString.parseParams('name',null,true,false,true);
		var tid=getParam(p,'tiddler','TiddlerName');
		var label=getParam(p,'label',tid);
		var tip=getParam(p,'tip',this.tip.format([tid]));
		var buttonClass=getParam(p,'buttonClass','');
		var width=getParam(p,'width','auto');
		var popupClass=getParam(p,'popupClass','');
		var above=params.contains('above');
		var mouseover=params.contains('mouseover');
		var b=createTiddlyButton(place, label, tip, this.click, buttonClass, null, null,
			{ tid:tid, popupClass:popupClass, width:width, above:above });
		b.innerHTML=label; // render HTML for entities, images, etc
		if (mouseover) b.onmouseover=b.onclick;  // option: mouseover triggers click
	},
	click: function(ev) { var ev=ev||window.event;
		// DISABLED if (Popup.find(this)!=-1)return false; // popup already shown!
		var p=Popup.create(this); if(!p)return false; // popup not created!
		addClass(p,this.getAttribute('popupClass'));
		var d=createTiddlyElement(p,'div');
		var s=d.style; s.whiteSpace='normal'; s.width=this.getAttribute('width'); s.padding='2px';
		wikify(store.getTiddlerText(this.getAttribute('tid'),''),d);
		if (this.getAttribute('above')!='true') Popup.show();
		else Popup.show('top','left',{x:0,y:-jQuery(d).outerHeight()});
		ev.cancelBubble=true; if(ev.stopPropagation)ev.stopPropagation(); return false;
	}
}
//}}}
/***
|Name|ShowPopupPluginInfo|
|Source|http://www.TiddlyTools.com/#ShowPopupPlugin|
|Documentation|http://www.TiddlyTools.com/#ShowPopupPluginInfo|
|Version|2.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for ShowPopupPlugin|
!!!!!Usage
<<<
{{{
<<showPopup tiddler:[[TiddlerName]] label:"..." tip:"..." buttonClass:"..." width:"..." popupClass:"..." above>>
}}}
*''~TiddlerName''<br>title of the tiddler to be displayed
*''label''<br>text for the command link //(default=~TiddlerName)//
*''tooltip''<br>mouseover help text for the link //(default="display ~TiddlerName in a popup")//
*''buttonClass''<br>CSS classname applied to the command text //(default=button)//
*''width''<br>width of the popup (using CSS measurements) //(default=auto)//
*''popupClass''<br>CSS classname applied to the popup panel. //(default=none)//<br>Use 'sticky' for persistent popups (see StickyPopupPlugin)
*''above''<br>when this keyword is used, the bottom of the popup will be aligned with the top of the command link text label (i.e., the popup appears //above// the label).
*''mouseover''<br>when this keyword is used, the popup is shown whenever the mouse is moved over the label, without requiring a click (i.e., a "hot spot")
For backward-compatibility with existing document content, you can also use the {{{<<tiddler>>}}} macro to transclude the [[ShowPopup]] //shadow tiddler//, like this:
{{{
<<tiddler ShowPopup with: [[TiddlerName]] label tooltip buttonClass width popupClass 'above'>>
}}}
Note: transclusion uses //unnamed// parameters that must occur in the order shown above.  You can use "" as placeholders to apply default parameter values.
<<<
!!!!!Examples
<<<
Popup below label (defaults):
>{{{<<showPopup tiddler:GettingStarted>>}}}
><<showPopup tiddler:GettingStarted>>
Popup above label:
>{{{<<showPopup tiddler:GettingStarted above>>}}}
><<showPopup tiddler:GettingStarted above>>
Popup mouseover above label:
>{{{<<showPopup above mouseover tiddler:GettingStarted>>}}}
><<showPopup above mouseover tiddler:GettingStarted>>
<<<
!!!!!Revisions:
<<<
2011.03.13 2.1.1 in click(), removed check for popup already shown (prevents nested popups!)
2011.03.12 2.1.0 added 'mouseover' param
2011.03.05 2.0.1 in click(), fixed popup alignment when NOT using 'above'
2011.03.03 2.0.0 converted to plugin and added optional 'above' keyword param
2009.09.10 1.2.0 documentation/code cleanup
2007.03.02 1.1.0 added class, width, popupClass params
2006.09.09 1.0.0 initial release (transclusion)
<<<
/%
!info
|Name|ShowTabsForTags|
|Source|http://www.TiddlyTools.com/#ShowTabsForTags|
|Version|2.0.0//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|generate a tabbed display for tiddlers with a specified set of tags|
Usage
<<<
{{{
<<tiddler ShowTabsForTags with: "tag tag ...">>
}}}
*''"tag tag..."''<br>is a space-separated list of tag values, ALL of which must be present on the tiddlers that are to be displayed.
<<<
Example
<<<
{{{<<tiddler ShowTabsForTags with: package>>}}}
<<tiddler ShowTabsForTags##show with: package>>
<<<
!end
!out
{{wrap{$1}}}
!end  <-- 2021-02-15: class 'left' removed (class 'wrap' retained)
!show
<<tiddler ShowTabsForTags##out with: {{
	var tags="$1".readBracketedList();
	// get matching tiddlers in date order (newest first) and add params to tabs macro output
	var out="";
	if (tags.length) {
		var tids=store.getTaggedTiddlers(tags[0],'modified').reverse();
		for (var t=0; t<tids.length; t++)
			if (tids[t].tags.containsAll(tags))
				out+='[[%0 ]] "view %0" [[%0]]'.format([tids[t].title]); 
	}
	out.length?"<<tabs tabTabsForTags "+out+">\>"
		:"There are no tiddlers tagged with <<tag "+tags.join(">\> and <<tag ")+">\>";
}}>>
!end
%/<<tiddler {{var src='ShowTabsForTags'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]]>>
@@line-height:1em;<<search>>@@/%
%/@@line-height:1.2em;/%
%/<<collapseAll>> {{ml1em vrl1 pl1em{<<expandAll>>}}}/%
%/<<closeAll>>/%
%/<<slider chkOtherSidebarOptions [[More sidebar options]] "more ↕" "More menu items">>/%
%/<<slider chkSliderOptionsPanel OptionsPanel "options ↕" "Change TiddlyWiki advanced options">>@@
/***
|''Name''|SimpleSearchPlugin|
|''Description''|displays search results as a simple list of matching tiddlers|
|''Authors''|FND|
|''Version''|0.4.1|
|''Status''|stable|
|''Source''|http://devpad.tiddlyspot.com/#SimpleSearchPlugin|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/plugins/SimpleSearchPlugin.js|
|''License''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''Keywords''|search|
!Revision History
!!v0.2.0 (2008-08-18)
* initial release
!!v0.3.0 (2008-08-19)
* added Open All button (renders Classic Search option obsolete)
* sorting by relevance (title matches before content matches)
!!v0.4.0 (2008-08-26)
* added tag matching
!To Do
* tag matching optional
* animations for container creation and removal
* when clicking on search results, do not scroll to the respective tiddler (optional)
* use template for search results
!Code
***/
//{{{
if(!version.extensions.SimpleSearchPlugin) { //# ensure that the plugin is only installed once
version.extensions.SimpleSearchPlugin = { installed: true };

if(!config.extensions) { config.extensions = {}; }

config.extensions.SimpleSearchPlugin = {
	heading: "Search Results",
	containerId: "searchResults",
	btnCloseLabel: "close",
	btnCloseTooltip: "dismiss search results",
	btnCloseId: "search_close",
	btnOpenLabel: "Open all",
	btnOpenTooltip: "open all search results",
	btnOpenId: "search_open",

	displayResults: function(matches, query) {
		story.refreshAllTiddlers(true); // update highlighting within story tiddlers
		var el = document.getElementById(this.containerId);
		query = '"""' + query + '"""'; // prevent WikiLinks
		if(el) {
			removeChildren(el);
		} else { //# fallback: use displayArea as parent
			var container = document.getElementById("displayArea");
			el = document.createElement("div");
			el.id = this.containerId;
			el = container.insertBefore(el, container.firstChild);
		}
		var msg = "!" + this.heading + "\n";
		if(matches.length > 0) {
			msg += "''" + config.macros.search.successMsg.format([matches.length.toString(), query]) + ":''\n";
			this.results = [];
			for(var i = 0 ; i < matches.length; i++) {
				this.results.push(matches[i].title);
				msg += "* [[" + matches[i].title + "]]\n";
			}
		} else {
			msg += "''" + config.macros.search.failureMsg.format([query]) + "''"; // XXX: do not use bold here!?
		}
		createTiddlyButton(el, this.btnCloseLabel, this.btnCloseTooltip, config.extensions.SimpleSearchPlugin.closeResults, "button", this.btnCloseId);
		wikify(msg, el);
		if(matches.length > 0) { // XXX: redundant!?
			createTiddlyButton(el, this.btnOpenLabel, this.btnOpenTooltip, config.extensions.SimpleSearchPlugin.openAll, "button", this.btnOpenId);
		}
	},

	closeResults: function() {
		var el = document.getElementById(config.extensions.SimpleSearchPlugin.containerId);
		removeNode(el);
		config.extensions.SimpleSearchPlugin.results = null;
		highlightHack = null;
	},

	openAll: function(ev) {
		story.displayTiddlers(null, config.extensions.SimpleSearchPlugin.results);
		return false;
	}
};

config.shadowTiddlers.StyleSheetSimpleSearch = "/*{{{*/\n" +
	"#" + config.extensions.SimpleSearchPlugin.containerId + " {\n" +
	"\toverflow: auto;\n" +
	"\tpadding: 5px 1em 10px;\n" +
	"\tbackground-color: [[ColorPalette::TertiaryPale]];\n" +
	"}\n\n" +
	"#" + config.extensions.SimpleSearchPlugin.containerId + " h1 {\n" +
	"\tmargin-top: 0;\n" +
	"\tborder: none;\n" +
	"}\n\n" +
	"#" + config.extensions.SimpleSearchPlugin.containerId + " ul {\n" +
	"\tmargin: 0.5em;\n" +
	"\tpadding-left: 1.5em;\n" +
	"}\n\n" +
	"#" + config.extensions.SimpleSearchPlugin.containerId + " .button {\n" +
	"\tdisplay: block;\n" +
	"\tborder-color: [[ColorPalette::TertiaryDark]];\n" +
	"\tpadding: 5px;\n" +
	"\tbackground-color: [[ColorPalette::TertiaryLight]];\n" +
	"}\n\n" +
	"#" + config.extensions.SimpleSearchPlugin.containerId + " .button:hover {\n" +
	"\tborder-color: [[ColorPalette::SecondaryMid]];\n" +
	"\tbackground-color: [[ColorPalette::SecondaryLight]];\n" +
	"}\n\n" +
	"#" + config.extensions.SimpleSearchPlugin.btnCloseId + " {\n" +
	"\tfloat: right;\n" +
	"\tmargin: -5px -1em 5px 5px;\n" +
	"}\n\n" +
	"#" + config.extensions.SimpleSearchPlugin.btnOpenId + " {\n" +
	"\tfloat: left;\n" +
	"\tmargin-top: 5px;\n" +
	"}\n" +
	"/*}}}*/";
store.addNotification("StyleSheetSimpleSearch", refreshStyles);

// override Story.search()
Story.prototype.search = function(text, useCaseSensitive, useRegExp) {
	highlightHack = new RegExp(useRegExp ? text : text.escapeRegExp(), useCaseSensitive ? "mg" : "img");
	var matches = store.search(highlightHack, null, "excludeSearch");
	var q = useRegExp ? "/" : "'";
	config.extensions.SimpleSearchPlugin.displayResults(matches, q + text + q);
};

// override TiddlyWiki.search() to sort by relevance
TiddlyWiki.prototype.search = function(searchRegExp, sortField, excludeTag, match) {
	var candidates = this.reverseLookup("tags", excludeTag, !!match);
	var primary = [];
	var secondary = [];
	var tertiary = [];
	for(var t = 0; t < candidates.length; t++) {
		if(candidates[t].title.search(searchRegExp) != -1) {
			primary.push(candidates[t]);
		} else if(candidates[t].tags.join(" ").search(searchRegExp) != -1) {
			secondary.push(candidates[t]);
		} else if(candidates[t].text.search(searchRegExp) != -1) {
			tertiary.push(candidates[t]);
		}
	}
	var results = primary.concat(secondary).concat(tertiary);
	if(sortField) {
		results.sort(function(a, b) {
			return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);
		});
	}
	return results;
};

} //# end of "install only once"
//}}}
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Vervolg van [[Iteratiemechanismen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''

<<tiddler [[{}::togglesliders]]>> Python, Ruby en Lua kennen alle een ''{{tt{for&mdash;in}}}''-statement, in Python geformuleerd als {{hitt z{''for'' //vars// ''in'' //object//'':'' //actions//}}} en in de andere twee niet veel anders. Wat voor mechanisme gaat daarachter schuil? Bij Python heb ik gepoogd dat te reconstrueren door gewapend met wat opgedane kennis van iteratoren en generatoren{{ref{&#x200a;[[[1]|##1]]}}} van alles uit te proberen. Ruby was een makkie, omdat alle ook maar enigszins deugdelijke handleidingen vertellen hoe de vork daar in de steel zit. 'PiL'{{ref{&#x200a;[[[2]|##2]]}}} tenslotte pleegt steeds uitvoerig uit te leggen hoe het er in Lua onder water aan toe gaat, dus daar krijg ik de ingrediënten voor een werkend simulatiemodel op een presenteerblaadje aangereikt. Ik zal de drie modellen die ik heb gebouwd (elk in zijn eigen taal) hier behandelen in volgorde van afnemende bevattelijkheid. Dat betekent Ruby, Python, Lua./%

%/
!!Ruby
In Ruby is het {{tt t{for&mdash;in}}}-statement nauwelijks iets anders dan de method {{tt{[[each|Geïntegreerde provider/deliverer/pilot à la Ruby]]}}} in cadeaupapier. Vind of schrijf een method {{tt t{//object//.each}}} en je  kunt vanzelf itereren via {{pref hitt z pred{''for'' //varlist// ''in'' //object// do //actions// end}}}. Niet dat ik dat ooit gedaan had, want ik prefereer de directe methode door {{tt t{each}}} rechtstreeks aan te spreken. Maar voor deze verhandeling ontkwam ik er niet aan. Mijn nabootsing van {{tt t{for&mdash;in}}} is van een verpletterende eenvoud:
{{pref tt s med ws pred d2p r scroll{
def ''pilot''(provider, @@background-color:#ffcccc;&procedure@@)
"""  provider.each""" @@background-color:#ffcccc;&procedure@@
end
}}}/%

%/Aan te roepen met bijvoorbeeld {{hitt z pred{''pilot''(dictionary) @@background-color:#ffcccc;{|k, v| puts "#{k} #{v}" }@@}}}. Volmaakt is deze imitatie echter niet. Er zitten wat haken en ogen aan de zichtbaarheid van variabelen. Alle variabelen tussen {{hitt z pred{for}}} en {{hitt z pred{end}}} hebben dezelfde scope als het direct omringende deel van de programmacode. Kan een voordeel zijn, kan een nadeel zijn. De {{tt t{each}}}-constructie, of liever gezegd het code block dat er als argument aan wordt meegegeven, biedt meer privacy, al is dat niet een geheel zorgeloos gebeuren. Onderstaande code vergelijkt de werking van het {{tt t{for&mdash;in}}}-statement met die van de {{tt t{pilot}}}-method. Laatstgenoemde wordt twee keer aangeroepen om de scope van de gebruikte variabelen af te tasten.
+++(~ForinImitaties_Ruby)!!![Het volledige Ruby-script &darr;|show][Het volledige Ruby-script &uarr;|hide]
{{lf w60pct pref tt s med ws pred d2p r scroll{
{{fpur{"""# Script: Homebaked-pilot-in-Ruby-1.9+.rb
# Date  : 2023-03-05, Meindert Meindertsma
#
#   Role       Ruby term         Name in this script  Variant state
#   ---------  ----------------  -------------------  -------------
#   provider   -                 dictionary
#   deliverer  iterator          each                 x
#   pilot      -                 for, pilot, each
#   ---------  ----------------  -------------------  -------------


#------====| DICTIONARY |====-----#"""}}}
"""
dictionary = {"A" => 10, "B" => 11, "C" => 12}
"""
{{fpur{"""#---- Home-baked pilot ----#"""}}}
def ''pilot''"""(provider, &procedure)
  provider.each &procedure
end
"""
{{fpur{"""#---- Local variable of main ----#"""}}}
"""k = "D"
"""
{{fpur{"""#---- Apply for statement ----#"""}}}
"""puts "for:"

"""''for'' k, v1 ''in''""" dictionary do
  x = 1
  puts "#{k} #{v1} -- #{x}"
end

puts "---"
begin
  puts "#{k} #{v1} -- #{x}"  #=> prints 'A 10 -- 1'
rescue Exception
  puts "#{k} (Error: #{$!})"
end
puts "---"
"""
{{fpur{"""#---- Local variable of main ----#"""}}}
"""k = "D"
"""
{{fpur{"""#---- Apply home-baked pilot ----#"""}}}
"""puts "pilot:"

"""''pilot''"""(dictionary) do |k, v2|
  x = 2
  puts "#{k} #{v2} -- #{x}"
end

puts "---"
begin
  puts "#{k} #{v2}"
rescue Exception
  puts "#{k} (Error: #{$!}) -- #{x}"  #=> Ruby 1.8  prints 'A (Error: ...) -- 2'
                                      #=> Ruby 1.9+ prints 'D (Error: ...) -- 2'
end
"""
@@background-color:#ffcccc;{{fpur{"""#---- Local variable of main ----#"""}}}
v3 = 13

{{fpur{"""#---- Apply home-baked pilot (Ruby 1.9+ only) ----#"""}}}
"""puts "---"
puts "pilot 1.9+:"

"""''pilot''"""(dictionary) do |k, v3; x|
  x = 3
  puts "#{k} #{v3} -- #{x}"
end

puts "---"
puts "#{k} #{v3} -- #{x}""""@@
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pref tt s med ws pred d2p r scroll{
''Uitvoer door Ruby 1.8''

"""for:
C 12 -- 1
B 11 -- 1
A 10 -- 1
---
"""''{{fblu{A 10}}}''""" -- """''{{fblu{1}}}''"""
---
pilot:
C 12 -- 2
B 11 -- 2
A 10 -- 2
---
"""''{{fred{A}}} {{fblu{(Error: ...)}}}''""" -- """{{fred{''2''}}}
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pref tt s med ws pred d2p r scroll{
''Uitvoer door Ruby 1.9+''

"""for:
A 10 -- 1
B 11 -- 1
C 12 -- 1
---
"""''{{fblu{C 12}}}''""" -- """''{{fblu{1}}}''"""
---
pilot:
A 10 -- 2
B 11 -- 2
C 12 -- 2
---
"""''{{fblu{D (Error: ...)}}}''""" -- """{{fred{''2''}}}
@@background-color:#ffcccc;"""---
pilot 1.9+:
A 10 -- 3
B 11 -- 3
C 12 -- 3
---
"""{{fblu{''D 13''}}} """--""" {{fblu{''2''}}}@@
}}}{{clear block{De frase {{pref hitt z pred{do ... end}}} in {{tt t{for&mdash;in}}} is onderdeel van de syntaxis van dit statement. De andere voorkomens van {{pref hitt z pred{do ... end}}} in dit script zijn //code blocks//, die ook met accolades mogen worden afgebakend: {{pref hitt z pred{{ ... """}"""}}}. Tussen de verticale strepen {{pref hitt z pred{|...|}}} staan de formele parameters van het block. Een block kan als laatste argument aan een method worden meegegeven (feitelijk is dat het enige wat je ermee kunt doen) en staat dan altijd buiten de haakjes rondom de voorafgaande argumenten.}}}/%
%/
Het script laat zien hoe de variabelen in de blocks {{pref hitt z pred{do |k, v//i//| x = //i//; puts "#{k} #{v//i//}"; end}}} worden behandeld. Idealiter zijn de parameters {{tt t{k}}} en {{tt t{v//i//}}} strikt lokaal, en van eventuele andere variabelen in het block zou je moeten kunnen bepalen of deze ook zo lokaal zijn dan wel tot de omringende code behoren.

In Ruby 1.8 is de regel: als een blockvariabele reeds buiten het block is waargenomen, behoort het tot de omgeving, en anders is het een puur interne aangelegenheid (een block zal dus nooit een nieuwe variabele aan zijn omgeving toevoegen). Wat er op die manier met de parameter {{tt t{k}}} gebeurt, bevalt me totaal niet. Ik heb die in de onderste regel van de uitvoer daarom rood gekleurd. Je kunt zien dat de parameter {{tt t{v2}}} wèl intern is gebleven (de volledige foutmelding luidt {{sans{"Error: undefined local variable or method `v//{{{i}}}//' for main:Object"}}}). Om mijn tevredenheid hierover aan te geven heb ik die blauw gekleurd. 

Vanaf versie 1.9 zijn de parameters tenminste per definitie goed afgeschermd, zie de blauwe uitvoer op dezelfde hoogte als die van 1.8. Maar de variabele {{tt t{x}}} blijkt na afloop van de iteraties veranderd. Dus die is weer rood gemaakt. Het is in 1.9+ gelukkig wel mogelijk {{tt t{x}}} via de declaratie {{pref hitt z pred{do |k, v3@@background-color:#ffcccc;''; x''@@| x = 3; puts "#{k} #{v3}"; end}}} lokaal te maken. De blauwe kleur van de laatste uitvoerregel straalt mijn ingenomenheid met dit resultaat uit.

Aan beide uitvoeren is af te lezen dat versie 1.9 de volgorde van de dictionary-elementen heeft gestabiliseerd. In Ruby is een dictionary een instance van de class ''{{{Hash}}}''./%

%/
===
!!Python
De {{tt t{pilot}}}-functie die ik voor Python heb geconstrueerd heeft beduidend meer code nodig dan het Ruby-equivalent. De logica ervan is echter heel goed te volgen (zie ook [['Iterabiliteit' in Python]]):
# Maak van de provider (het //iterabele// object waarover geïtereerd moet worden) een echte [[iterator|Provider à la Python-iterator]] door de ''{{{__iter__}}}''-method hiervan aan te roepen. Het is beter om dat niet rechtstreeks te doen, maar via de functie ''{{{iter}}}'', die de heldere foutmelding {{sans{"TypeError: '...' object is not iterable"}}} afgeeft als {{tt t{"""__iter__"""}}} ontbreekt en {{sans{"iter() returned non-iterator of type '...'"}}} als de ''{{{__next__}}}''-method ontbreekt. Mocht de provider van zichzelf al een iterator of [[generator|Provider à la Python-generator]] (een speciaal soort iterator) zijn, dan doet de aanroep van {{tt t{iter}}} geen kwaad. In zo'n geval wordt simpelweg het oorspronkelijke object geretourneerd.
# {{_{Herhaal de volgende stappen: (//a//) Haal via de {{tt t{"""__next__"""}}}-method de argumenten op die de uit te voeren procedure nodig heeft. Ik heb ook hier weer een wrapperfunctie, ''{{{next}}}'', voor gebruikt. (//b//) Roep de uit te voeren procedure aan met de zojuist verkregen argumenten.
Mocht de provider niets meer kunnen leveren, dan zal {{tt t{"""__next__"""}}} de uitzonderingstoestand ''{{{StopIteration}}}'' afkondigen. Dit moet worden afgevangen door de {{tt t{while}}}-lus af te breken met {{tt t{break}}}.}}}
# Binnen de {{tt t{for&mdash;in}}}-lus heeft ook de uit te voeren procedure de macht het itereren af te kappen, namelijk via het {{tt t{break}}}-statement. Dit mechanisme is gesimuleerd met behulp van de hier speciaal voor aangelegde uitzondering ''{{{BreakIteration}}}''. Binnen {{tt t{pilot}}} wordt deze afgevangen en omgezet in een echte {{tt t{break}}}. Een soortgelijke constructie is voor simulatie van {{tt t{continue}}} aangelegd: deze uitzondering heet ''{{{ContinueIteration}}}''. Heel expliciet maar technisch gezien eigenlijk overbodig, want {{tt t{continue}}} kan binnen de aangeroepen procedure ook worden gesimuleerd met een {{tt t{return}}}-statement.
{{pre{
def ''pilot''(provider, {{b2{procedure}}}):
"""    provider = iter(provider)       """{{fgre{# ensure it's an iterator}}}
"""    while True:
        try:
            vars = next(provider)
        except StopIteration:
            break
        try:
            if type(vars) == tuple:
                """{{b2{procedure}}}(*vars)"""
            else:
                """{{b2{procedure}}}(vars)"""
        except BreakIteration:
            break
        except ContinueIteration:
            continue"""
}}}/%

%/De functie is aan te roepen met bijvoorbeeld {{hitt z{''pilot''(dictionary, {{b2p{lambda k: print(k, dictionary[k])}}})}}}. Ik heb in onderstaand script het {{tt t{for&mdash;in}}}-statement en de {{tt t{pilot}}}-functie beide op vier verschillende manieren op een dictionary losgelaten.
+++(~ForinImitaties_Python)!!![Het volledige Python-script &darr;|show][Het volledige Python-script &uarr;|hide]
{{lf w80pct pre{
{{fgre{"""# Script: Homebaked-pilot-in-Python.py
# Date  : 2023-03-24, Meindert Meindertsma
#
#   Role       Python term       Name in this script  Variant state
#   ---------  ----------------  -------------------  -------------
#   provider   -                 dictionary
#              iterator          iter(dictionary)     x
#              generator         generator            x
#   deliverer  -                 next, __next__
#   pilot      -                 for, pilot
#   ---------  ----------------  -------------------  -------------"""}}}
"""
class BreakIteration(StopIteration): pass
class ContinueIteration(StopIteration): pass

"""
{{fgre{"""#------====| DICTIONARY |====-----#
"""}}}
print('DICTIONARY')
dictionary = {'A': 10, 'B': 11, 'C': 12}

{{fgre{"""#---- Home-baked pilot ----#"""}}}
def ''pilot''"""(provider, procedure):
    provider = iter(provider)    """{{fgre{# ensure it's an iterator}}}
"""    while True:
        try:
            vars = next(provider)
        except StopIteration:
            break
        try:
            if type(vars) == tuple:
                """{{b2{procedure}}}(*vars)"""
            else:
                """{{b2{procedure}}}(vars)"""
        except BreakIteration:
            break
        except ContinueIteration:
            continue
"""
{{fgre{"""#---- Global variable ----#"""}}}
"""k = 'D'
"""
{{fgre{"""#---- Apply for statement ----#"""}}}
"""print('for:')

for k in dictionary:
    x = 1
    print(k, dictionary[k], '--', x)

print('---')
print(k, '--', x)
print('---')
"""
{{fgre{"""#---- Global variables ----#"""}}}
"""k = "D"
"""
{{fgre{"""#---- Apply home-baked pilot ----#"""}}}
"""print('pilot:')

def proc(k):
    x = 2
    print(k, dictionary[k], '--', x)

pilot(dictionary, proc)

print('---')
print(k, '--', x)
print('===')

"""
{{fgre{"""#------====| PREMATURE STOP |====-----#"""}}}
"""
print('PREMATURE STOP')

print('for:')
for k in dictionary:
    print(k, dictionary[k])
    if k == 'B':
        break

print('---')

print('pilot:')
def _(k):
    print(k, dictionary[k])
    if k == 'B':
        raise BreakIteration    """{{fgre{"""# simulate break"""}}}"""
pilot(dictionary, _)

print('===')

"""
{{fgre{"""#------====| DICTIONARY ITEMS |====-----#"""}}}
"""
print('DICTIONARY ITEMS')
"""
{{fgre{"""#---- Global variables ----#"""}}}
"""k, v = "D", 13

dictitems = dictionary.items()
print('for:')

for k, v in dictitems:
    print(k, v)

print('---')
print(k, v)
print('---')
"""
{{fgre{"""#---- Global variables ----#"""}}}
"""k, v = "D", 13
"""
{{fgre{"""#---- Apply home-baked pilot ----#"""}}}
"""print('pilot:')

pilot(dictitems, lambda k, v: print(k, v))

print('---')
print(k, v)
print('===')

"""
{{fgre{"""#------====| GENERATOR |====-----#"""}}}
"""
print('GENERATOR')
"""
{{fgre{"""#---- Global variables ----#"""}}}
"""k, v = "D", 13
"""
{{fgre{"""#---- Apply for statement ----#"""}}}
"""generator = ((k, dictionary[k]) for k in dictionary)
print('for:')

for k, v in generator:
    print(k, v)

print('---')
print(k, v)
print('---')
"""
{{fgre{"""#---- Global variables ----#"""}}}
"""k, v = "D", 13
"""
{{fgre{"""#---- Apply home-baked pilot ----#"""}}}
"""generator = ((k, dictionary[k]) for k in dictionary)
print('pilot:')

pilot(generator, lambda k, v: print(k, v))

print('---')
print(k, v)"""
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pre{
''Uitvoer''
"""
DICTIONARY
for:
A 10 -- 1
B 11 -- 1
C 12 -- 1
---
C -- 1
---
pilot:
A 10 -- 2
B 11 -- 2
C 12 -- 2
---
D -- 1
===
PREMATURE STOP
for:
A 10
B 11
---
pilot:
A 10
B 11
===
DICTIONARY ITEMS
for:
A 10
B 11
C 12
---
C 12
---
pilot:
A 10
B 11
C 12
---
D 13
===
GENERATOR
for:
A 10
B 11
C 12
---
C 12
---
pilot:
A 10
B 11
C 12
---
D 13"""
}}}{{clear block{Alle variabelen in de {{tt t{for&mdash;in}}} blijven na afloop zichtbaar. De {{tt t{pilot}}}- en {{tt t{proc}}}-functie gedragen zich zoals je van functies in Python mag verwachten, en houden {{tt t{k}}} en {{tt t{x}}} dus netjes binnenboord.}}}/%
%/
De iterator van een ''{{{dict}}}'' biedt slecht één iteratorvariabele aan, die de sleutel representeert. Daarom heb ik gezocht naar oplossingen die ook de bijbehorende waarde als variabele beschikbaar stellen. Aldus ben ik tot drie oplossingen gekomen, die alle drie aardig illustreren wat 'The pickaxe' bedoelt met [["other languages (...) implement methods that generate external helper objects that carry the iterator state"|Geïntegreerde provider/deliverer/pilot à la Ruby]]:
# Onder de kop 'DICTIONARY': oorspronkelijke ''{{tt{dict}}}''-object &rarr; ''{{tt{dict_keyiterator}}}''-object
# Onder de kop 'DICTIONARY ITEMS: oorspronkelijke ''{{tt{dict}}}''-object &rarr; ''{{tt{dict_items}}}''-object &rarr; ''{{tt{dict_itemiterator}}}''-object
# Onder de kop 'GENERATOR': oorspronkelijke ''{{tt{dict}}}''-object &rarr; ''{{tt{generator}}}''-object
Afgaande op [[The Zen of Python|https://peps.python.org/pep-0020/]]:
<<<
There should be one -- and preferably only one -- obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
<<<
voorzie ik een gerede kans dat ik hiermee circa één voor de hand liggende oplossing heb aangeboord en dat mijn landgenoten deze moeiteloos kunnen aanwijzen.

Sinds Python 3.7 geldt voor {{tt t{dict}}} net zoals voor {{tt t{Hash}}} in Ruby 1.9+: "Dict keeps insertion order"./%

%/
===
!!Lua
De interne logica van Lua's {{tt t{for&mdash;in}}} deed me in eerste instantie wat aan balletje-balletje denken. Het statement maakt gebruik van een meegegeven delivery-functie (in Lua aangeduid met 'iterator') die moet worden aangeroepen met twee argumenten: een //invariant state// (onveranderlijke toestand) en een initiële waarde voor de //control variable// (besturingsvariabele -- mag als argument worden weggelaten als de waarde {{tt t{nil}}} is). De functie retourneert vervolgens een nieuwe waarde voor de control variable en (afhankelijk van de desbetreffende functie) mogelijk nog meer variabelen. De uit te voeren procedure wordt vervolgens met de aldus verkregen variabele(n) aangeroepen. Is die procedure klaar, dan roept {{tt t{for&mdash;in}}} de delivery-functie opnieuw aan, nu met de zojuist ontvangen waarde van de control variable als tweede argument. En zo gaat dat door. Het proces stopt als de delivery-functie {{tt t{nil}}} teruggeeft ten teken dat er verder niets meer te halen valt.

De [[invariant state|'Invariant state' in Lua]] kan van alles zijn. Een sequentie, een dictionary, een vast increment voor een teller, bedenk het maar.

Iets om bij het lezen van onderstaande code even erg in te hebben: de indexering van sequenties begint in Lua bij {{tt t{1}}}. De parameterbehandeling in de linker definitie van {{tt t{pilot}}} is op het eerste gezicht misschien wat minder overzichtelijk dan die van de rechter ({{hitt4 z{...}}} is net zoiets als {{hitt z{*args}}} in Python en Ruby). Ik geef er om ergonomische reden echter de voorkeur aan om de uit te voeren procedure als laatste parameter aan te houden, zodat de meest weelderige naamloze functies kunnen worden aangeboden zonder dat daar als een gemakkelijk over het hoofd te zien staartje nog twee of drie kleine argumentjes op volgen. Ik heb dus voor de linker oplossing gekozen. Het maakt verder niet zo veel uit, in functioneel opzicht zijn beide uitwerkingen gelijkwaardig.
{{lf w45pct pre4{
function ''pilot'' (sequence, {{b1{procedure}}})
"""  local deliver, invariantState, controlvar = unpack(sequence)
  while true do
    local variables = { deliver(invariantState, controlvar) }
    controlvar = variables[1]
    if controlvar == nil then break end
    """{{b1{procedure}}}(unpack(variables))"""
  end
end"""
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{w45pct pre4{
function ''pilot'' ({{b1{procedure}}}, ...)
"""  local deliver, invariantState, controlvar = ...
  while true do
    local variables = { deliver(invariantState, controlvar) }
    controlvar = variables[1]
    if controlvar == nil then break end
    """{{b1{procedure}}}(unpack(variables))"""
  end
end"""
}}}/%

%/Aan te roepen met bijvoorbeeld:
{{lf w45pct pre4{
''pilot''( { next, dictionary }, {{b1{function (k, v) print(k, v) end}}} ) }}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{w45pct pre4{
''pilot''({{b1{function (k, v) print(k, v) end}}}, next, dictionary)
}}}/%

%/Na het definiëren van {{tt t{pilot}}} was ik met de rest van het testscript snel klaar.
+++(~ForinImitaties_Lua)!!![Het volledige Lua-script &darr;|show][Het volledige Lua-script &uarr;|hide]
{{lf w80pct pre4{
{{fgre{"""-- Script: Homebaked-pilot-in-Lua.lua
-- Date  : 2023-03-06, Meindert Meindertsma
--
--   Role       Lua term          Name in this script  Variant state
--   ---------  ----------------  -------------------  -------------
--   provider   -                 dictionary
--   deliverer  iterator          next
--   pilot      true interator    for, pilot           x
--   ---------  ----------------  -------------------  -------------
"""}}}
unpack = {{fgre{"""--[[Lua 5.1]]"""}}} unpack or {{fgre{"""--[[Lua 5.2+]]"""}}} table.unpack


{{fgre{"""------====| DICTIONARY |====------"""}}}
"""
dictionary = {A = 10, B = 11, C = 12}
"""
{{fgre{"""----- Home-baked pilot -----"""}}}
function ''pilot'' """(sequence, procedure)
  local deliver, invariantState, controlvar = unpack(sequence)
  while true do
    local variables = { deliver(invariantState, controlvar) }
    controlvar = variables[1]
    if controlvar == nil then break end
    procedure(unpack(variables))
  end
end
"""
{{fgre{"""----- Global variables -----"""}}}
"""k, v = "D", 13
"""
{{fgre{"""----- Apply for statement -----"""}}}
"""print "for:""""
''for'' k, v ''in'' next, dictionary do print(k, v) end
"""
print "---"
"""
{{fgre{"""----- Apply home-baked pilot -----"""}}}
"""print "pilot:""""
''pilot''"""( { next, dictionary }, function (k, v) print(k, v) end )

print "---"
print(k, v)"""
}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w15pct pre4{
''Uitvoer''
"""
for:
A       10
C       12
B       11
---
pilot:
A       10
C       12
B       11
---
D       13"""
}}}{{clear block{Alle in {{tt t{for&mdash;in}}} en {{tt t{pilot}}} gebruikte variabelen blijken lokaal. Parameters zijn in Lua per definitie lokaal, en dat geldt ook voor de stuurvariabelen in {{tt t{for&mdash;in}}}. Voor het overige geldt, dat variabelen binnen blokken zoals afgebakend door onder meer {{hitt4 z{do}}} ... {{hitt4 z{end}}} lokaal kunnen worden gemaakt m.b.v. het {{tt t{local}}}-statement; zo niet, dan blijven ze van buitenaf zichtbaar.}}}/%
%/
De volgorde van dictionary-elementen is -- anders dan tegenwoordig in Ruby en Python -- onbepaald. Overigens, sequenties en dictionaries behoren in Lua tot hetzelfde gegevenstype, te weten ''{{sans{table}}}''. Een table kan allebei tegelijk zijn, zoals {{hitt4 z{"""{10, 20, 30, A = 10, B = 11, C = 12}"""}}}. Intern worden tables wel uitgesplitst in een sequence-gedeelte en een hash table-gedeelte, maar dat is niet direct zichtbaar voor de programmeur. Wel indirect in de vorm van de ''{{{#}}}''-operator waarmee je de lengte van het sequence-deel kunt opvragen, diverse sequence-functies ({{tt t{concat}}}, {{tt t{insert}}}, {{tt t{remove}}}, {{tt t{sort}}}) en de voorgedefinieerde als provider opererende functie {{tt{[[ipairs|Lua's ingebouwde providers en deliverers]]}}} ('indexed pairs') waarmee je in de juiste volgorde over de sequence-elementen kunt itereren. Het sequence-gedeelte strekt zich uit over de table-elementen waarvan de sleutels samen een aaneengesloten reeks {{tt t{1}}} t/m {{tt t{//n//}}} vormen.
===

----
|plain |k
|<html><a name="1">[1]</a></html>|Hoofdstuk 23 van <<tiddler Bibliografie##Spronck>> |
|<html><a name="2">[2]</a></html>|<<tiddler Bibliografie##Ierusalimschy>>  |
''{{fred sans{~!~ Deze tiddler moet nog geschreven worden. ~!~}}}''

Zie ook een aanzet in het document {{pref sans t{Python - statische variabelen}}} (28 december 2022) en een hoop Python-, Ruby-, Lua- en JavaScript-programmatuur in {{pref sans t{~\+data\Knutselhoekje\Python - Pieter Spronck - De programmeursleerling\StaticFunction\}}}.

Vanuit [[Geneste Python-modules##Modules creëren binnen een programma]] wordt verwezen naar deze tiddler.
<html><a class="siteLogo" href="javascript:;" onclick="story.closeAllTiddlers(); restart();" title="Home"><img src="core/EenJaarOfWat-donkergroen-neerhangend.png" alt="EJOW" width=178 style="margin:0 0 2px 0;" /></a></html>
|raw full|k
|Tijdelijke uitstalling van weetjes en ideetjes | &#x0020;@@text-transform:none;letter-spacing:0pt;<<tiddler ##SCRIPT>>@@ <<tiddler [[Last modification date]]>>|
<<tiddler HideTiddlerTags>>/%

---------------------------------------------------------------------------------------------------------------------------------------
  Werk de wijzingsdatum bij in de tiddler [[Last modification date]], bereikbaar via optie "Laatste wijzigingsdatum" in het hoofdmenu.
---------------------------------------------------------------------------------------------------------------------------------------

!SCRIPT
<script>return readOnly ? "" : "<html><b class='hws rr be fwhi saco z'><span class='sy'>&#x2711;</span> " + config.options.txtUserName.toString() + "&#x200a;</b></html>&nbsp;";</script>
!END SCRIPT

%/
@@display:none;EEN JAAR OF WAT@@<html><a title="Town" onmouseover="town.src='core/town-a1.png'" onmouseout="town.src='core/town-a0.png'" onmousedown="town.src='core/town-a2.png'" onmousup="town.src='core/town-a0.png'" href="../index.html"><img id="town" src="core/town-a0.png" style="position:absolute; top:6px; right:6px;"></a><img src="core/EEN JAAR OF WAT.png" width=708px style="position:relative;top:4px; left:-2px;"></html>
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Naast [[Iteratiemechanismen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Iteratiemechanismen]] label: "Bundel ↘">>}}}''
!!Verkrijging
De slicing-operatie kan worden toegepast op iterabelen van het type {{tt t{str}}}, {{tt t{bytes}}}, {{tt t{bytearray}}}, {{tt t{tuple}}} en {{tt t{list}}}. Het ophalen van elementen uit een iterabele wordt geïllustreerd aan de hand van de variabele ''{{hitt{s}}}'':
{{ib pre{
''s'' = 'spam'  {{f2m{#=> 'spam'}}}
type(''s'')     {{f2m{#=> <class 'str'>}}}
len(''s'')      {{f2m{#=> 4}}}
}}}
De onderstreepte indices in onderstaande voorbeelden verwijzen naar lokaties buiten de string. Dit betreft dus indices kleiner dan {{tt t{-4}}} of groter dan {{tt t{3}}}./%

%/
!!!Positieve stapgrootte
;{{n{Samenvatting:}}}
:''{{hitt{s[:]}}}'' en ''{{hitt{s[::]}}}'' komen overeen met ''{{hitt{s[ 0 : len(s) : 1 ]}}}''.
:''{{hitt{s[::{{sans n{//positiveStep//}}}]}}}'' komt overeen met ''{{hitt{s[ 0 : len(s) : {{sans n{//positiveStep//}}} ]}}}''.
;{{n{Voorbeelden:}}}
:{{_{
|tt pref |k
|!{{sans{Impliciet}}} |!{{sans{Positief}}} |!{{sans{Negatief}}} |!{{sans{Waarde}}} |
|s[]                  |                    |                    |{{sans fred{//SyntaxError: incomplete input//}}} |
|s[:]                 |s[0:__4__]          |s[-4:__4__]         |'spam'            |
|s[:__9__]            |s[0:__9__]          |s[-4:__9__]         |'spam'            |
|s[:3]                |s[0:3]              |s[-4:-1]            |'spa'             |
|s[:1]                |s[0:1]              |s[-4:-3]            |'s'               |
|s[:0]                |s[0:0]              |s[-4:-4]            |"""''"""          |
|s[1:]                |s[1:__4__]          |s[-3:__4__]         |'pam'             |
|s[__-9__:]           |s[__-9__:__4__]     |s[__-9__:__4__]     |'spam'            |
|s[::0]               |s[0:__4__:0]        |s[-4,__4__:0]       |{{sans fred{//ValueError: slice step cannot be zero//}}}&nbsp; |
|s[::]                |s[0:__4__:1]        |s[-4:__4__:1]       |'spam'            |
|s[::2]               |s[0:__4__:2]&nbsp;  |s[-4,__4__:2]&nbsp; |'sa'              |
}}}/%

%/
!!!Negatieve stapgrootte
;{{n{Samenvatting:}}}
:''{{hitt{s[::{{sans n{//negativeStep//}}}]}}}'' komt overeen met ''{{hitt{s[ -1 : -(len(s)+1) : {{sans n{//negativeStep//}}} ]}}}''.
;{{n{Voorbeelden:}}}
:{{_{
|tt pref |k
|!{{sans{Impliciet}}} |!{{sans{Positief}}}  |!{{sans{Negatief}}} |!{{sans{Waarde}}} |
|s[::-1]              |s[3:__-5__:-1]&nbsp; |s[-1:__-5__:-1]     |'maps'&nbsp;      |
|s[:__-9__:-1]        |s[3:__-9__:-1]       |s[-1:__-9__:-1]     |'maps'            |
|s[:-4:-1]&nbsp;      |s[3:0:-1]            |s[-1:-4:-1]&nbsp;   |'map'             |
|s[:-2:-1]            |s[3:2:-1]            |s[-1:-2:-1]         |'m'               |
|s[:-1:-1]            |s[3:3:-1]            |s[-1:-1:-1]         |"""''"""          |
|s[:0:-1]             |s[3:0:-1]            |s[-1:-4:-1]         |'map'             |
|s[2::-1]             |s[2:__-5__:-1]       |s[-2:__-5__:-1]     |'aps'             |
|s[__9__::-1]         |s[__9__:__-5__:-1]   |s[__9__:__-5__:-1]  |'maps'            |
|s[::-2]              |s[3:__-5__:-2]       |s[-1:__-5__:-2]     |'mp'              |
}}}/%

%/
!!Toekenning
Slices zijn ook geschikt om waarden aan delen van muteerbare iterabelen zoals {{tt t{bytearray}}}, {{tt t{tuple}}} en {{tt t{list}}} toe te kennen. Hieronder is dat voor de variabele ''{{hitt{ba}}}'' uitgewerkt:
{{ib pre{
''ba'' = bytearray(b'spam')  {{f2m{#=> bytearray(b'spam')}}}
type(''ba'')                 {{f2m{#=> <class 'bytearray'>}}}
len(''ba'')                  {{f2m{#=> 4}}}
}}}
Bij een stapgrootte van {{tt t{1}}} (impliciet of expliciet) is het vrij overzichtelijk wat er gebeurt. In ''{{pref hitt{ba[{{sans n{//start//}}}:{{sans n{//stop//}}}:1] = {{sans n{//bytes//}}}}}}'' wordt het gedeelte van {{sans{//start//}}} tot {{sans{//stop//}}} vervangen door de inhoud van {{sans{//bytes//}}}, ongeacht de lengte van {{sans{//bytes//}}}.
Bij alle andere stapgroottes luistert het nauwer. Er is dan sprake van een 'extended slice', die bestaat uit de geselecteerde elementen van het linkere lid. De lengte van het rechter lid moet hier exact mee overeenkomen.
;{{n{Voorbeelden:}}}
:{{_{
|tt pref |k
|!{{sans{Impliciet}}} |!{{sans{Positief}}}         |!{{sans{Negatief}}}        |white-space:normal;!{{sans{Nieuwe&nbsp;waarde {{n{i.p.v. {{tt{bytearray(b'spam')}}}}}}}}} |
|ba[:] = b'shrubbery' |ba[0:__4__:1] = b'shubbery' |ba[-4:-1:1] = b'shrubbery' |bytearray(b'shrubbery')&nbsp; |
|ba[:2] = b'h'        |ba[0:2:1] = b'h'            |ba[-4:-2:1] = b'h'         |bytearray(b'ham')       |
|ba[1:2] = b"""''"""  |ba[1:2:1] = b"""''"""       |ba[-3:-2:1] = b"""''"""    |bytearray(b'sam')       |
|ba[2:2] = b'h'       |ba[2:2:1] = b'h'            |ba[-2:-2:1] = b'h'         |bytearray(b'spham')     |
|ba[2:3] = b'er'      |ba[2:3:1] = b'er'           |ba[-2:-1:1] = b'er'        |bytearray(b'sperm')     |
|ba[::2] = b'S'       |ba[0:__4__:2] = b'S'        |ba[-4:-1:2] = b'S'         |@@white-space:normal;{{saco fred{//ValueError: attempt to assign bytes of size 1 to extended slice of size 2//}}}@@ |
|ba[:2:2] = b'S'      |ba[0:2:2] = b'S'            |ba[-4:-2:2] = b'S'         |bytearry(b'Spam') |
|ba[:1:2] = b'S'      |ba[0:1:1] = b'S'            |ba[-4:-3:2] = b'S'         |bytearry(b'Spam') |
|ba[:0:2] = b'S'      |ba[0:0:2] = b'S'            |ba[-4:-4:2] = b'S'         |@@white-space:normal;{{saco fred{//ValueError: attempt to assign bytes of size 1 to extended slice of size {{tt{0}}}//}}}@@ |
|ba[::2] = b'SA'      |ba[0:__4__:-1] = b'SA'      |ba[-4:-1:2] = b'SA'        |bytearry(b'SpAm') |
|ba[::2] = b'SAS'     |ba[0:__4__:-1] = b'SAS'     |ba[-4:-1:2] = b'SAS'       |@@white-space:normal;{{saco fred{//ValueError: attempt to assign bytes of size 3 to extended slice of size 2//}}}@@ |
|ba[::-1] = b'sgge'   |ba[3:__-5__:-1] = b'sgge'   |ba[-1:__-5__:-1] = b'sgge' |bytearray(b'eggs')      |
|ba[::-2] = b'MP'     |ba[3:__-5__:-1] = b'MP'     |ba[-1:__-5__:-1] = b'MP'   |bytearray(b'sPaM')      |
}}}
!!Betrokken dunders en de class {{tt{slice}}}
* ''{{hitt{{{sans n{//obj//}}}."""__iter__"""({{sans n{//self//}}})}}}''
* ''{{hitt{{{sans n{//obj//}}}."""__getitem__"""({{sans n{//self//}}}, {{sans n{//key//}}})}}}''
* {{hitt{{{sans{//obj//}}}''."""__setitem__"""(''{{sans{//self//}}}'','' {{sans{//key//}}}'','' {{sans{//value//}}}'')''}}}
waarin {{sans{//key//}}} een {{tt t{slice}}}-object kan zijn, zoals rechtstreeks te instantiëren is met <<eval [=[''{{pref hitt{slice({{sans n{//stop//}}})}}}'' of ''{{pref hitt{slice({{sans n{//start//}}}, {{n{{{sans{//stop//}}}$(}}}, {{n{{{sans{//step//}}}$)$0}}})}}}''. Python doet dat echter automatisch via de slicing-operator ''{{pref hitt{[{{n{{{sans{// start//}}}$0}}}:{{n{{{sans{// stop//}}}$0$(}}}:{{n{{{sans{// step//}}}$0$)$0}}}]}}}'', die tot de aanroep van {{tt t{"""__getitem__"""}}} of {{tt t{"""__setitem__"""}}} leidt. Ook de indexing-operator ''{{pref hitt{[{{sans n{// index //}}}]}}}'' en de mapping-operator ''{{pref hitt{[{{sans n{// key //}}}]}}}'' roepen deze dunders aan.]=] f2m>>

+++(~Slices_Voorbeeld)[Voorbeeld &darr;|show][Voorbeeld &uarr;|hide]
{{lf w50pct pre{"""class Tenfold:
    len = 0

    def __init__(self, len):
        self.len = len

    def """''"""__iter__"""''"""(self):
        return self

    def """''"""__getitem__"""''"""(self, key):
        if type(key) == """''slice''""":
            print(key, '->', key."""''indices''"""(self.len))
            return [f'{i : 7d} ->{i * 10 : 3d}'
                    for i in range(*key."""''indices''"""(self.len))]
        else:
            if -self.len <= key < 0:
                return f'{key : 7d} ->{(self.len + key) * 10 : 3d}'
            elif 0 <= key < self.len:
                return f'{key : 7d} ->{key * 10 : 3d}'
            else:
                return f'{key : 7d} -> {None}'

tenfold = Tenfold(4)

print(tenfold[0])
print(tenfold[3])
print(tenfold[4])
print(tenfold[-1])
print(tenfold[-4])
print(tenfold[-5])

print()
print('[:]     -> ', end='')
for item in tenfold[:]    : print(item)
print('[0:4]   -> ', end='')
for item in tenfold[0:4]  : print(item)
print('[0:3]   -> ', end='')
for item in tenfold[0:3]  : print(item)
print('[-4:-1] -> ', end='')
for item in tenfold[-4:-1]: print(item)
print('[-9:9]  -> ', end='')
for item in tenfold[-9:9] : print(item)
print('[::-1]  -> ', end='')
for item in tenfold[::-1] : print(item)

print()
for item in tenfold       : print(item)         """}}}<<divlf 1.5% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w40pct pre{
''Uitvoer''

"""      0 ->  0
      3 -> 30
      4 -> None
     -1 -> 30
     -4 ->  0
     -5 -> None

[:]     -> slice(None, None, None) -> (0, 4, 1)
      0 ->  0
      1 -> 10
      2 -> 20
      3 -> 30
[0:4]   -> slice(0, 4, None) -> (0, 4, 1)
      0 ->  0
      1 -> 10
      2 -> 20
      3 -> 30
[0:3]   -> slice(0, 3, None) -> (0, 3, 1)
      0 ->  0
      1 -> 10
      2 -> 20
[-4:-1] -> slice(-4, -1, None) -> (0, 3, 1)
      0 ->  0
      1 -> 10
      2 -> 20
[-9:9]  -> slice(-9, 9, None) -> (0, 4, 1)
      0 ->  0
      1 -> 10
      2 -> 20
      3 -> 30
[::-1]  -> slice(None, None, -1) -> (3, -1, -1)
      3 -> 30
      2 -> 20
      1 -> 10
      0 ->  0

"""{{fred{"""Traceback (most recent call last):
  """File "C:\&compfn;&compfn;&compfn;&compfn;&compfn;\slices.py", line 45, in <module>"""
    for item in tenfold       : print(item)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: iter() returned non-iterator of type 'Tenfold'"""}}}
}}}{{clear block{Weliswaar is {{tt t{Tenfold}}} iterabel gemaakt, maar daarmee is er nog geen iterator ontstaan. Dat wordt pas bewerkstelligd door naast {{tt t{"""__iter__"""}}} tevens een dunder {{tt t{"""__next__"""}}} te definiëren.

Omgekeerd heeft {{tt t{Tenfold}}} helemaal geen {{tt t{"""__iter__"""}}}-method nodig om de indexing- en slicing-operators naar behoren te laten werken. De dunder {{tt t{"""__getitem__"""}}} is al genoeg voor de indexing-operator. De slicing-operator verlangt van {{tt t{"""__getitem__"""}}} een iterabele waarde terug, wat natuurlijk best logisch is.

Het weglaten van {{tt t{"""__iter__"""}}} uit {{tt t{Tenfold}}} heeft echter wel een verrassende uitwerking op het laatste statement, {{pref hitt z{for item in tenfold: print(item)}}}. In plaats van te klagen over het non-iteratorschap van {{tt t{Tenfold}}} slaat Python enthousiast aan het itereren. Overenthousiast zelfs, want het iteratieproces stopt niet meer, tenzij er van buitenaf wordt ingegrepen! De iteratievariabele {{tt t{item}}} krijgt daarbij de returnwaarde van {{tt t{"""__getitem__"""}}}, die kennelijk achtereenvolgens met de impliciete keys {{tt t{0}}} t/m oneindig wordt aangeroepen. Ik concludeer daaruit, dat louter de aanwezigheid van deze dunder al voldoende is om {{tt t{Tenfold}}} iterabel te maken. En wel zodanig, dat een eventuele dunder {{tt t{"""__next__"""}}} er met een {{pref hitt{raise StopIteration()}}} geen vat op heeft. Zo'n {{tt t{raise}}}-statement moet in {{tt t{"""__getitem__"""}}} worden ondergebracht. Dan kan het iteratieproces zichzelf in de hand houden.}}}

===
!!Bijzondere waarden
In plaats van de velden //{{sans{start}}}//, //{{sans{stop}}}// en //{{sans{step}}}// in de slicing-operator leeg te laten, mag net zo goed {{tt t{None}}} worden ingevuld, met hetzelfde effect. Verder gelden de waarden {{tt t{False}}} en {{tt t{True}}} in numerieke context als {{tt t{0}}} respectievelijk {{tt t{1}}}, dus ook in de slicing- en indexing-operatoren./%

!!!!{{pref ppur u3s d3s{ Smalltalk (Cuis) }}} &rarr; {{pref pred u3s d3s{ Ruby }}} &rarr; {{pref b3w u3s d3s{ Python 3 }}} &rarr; {{pref pgre u3s d3s{ Lua }}} &rarr; {{pref pblu u3s d3s{ Scheme }}} &rarr; {{pref pyel u3s d3s{ Rebol 2 }}} &nbsp; &nbsp; <<tiddler [[{}::togglesliders]]>>/%

%/
+++(~Smalltalk80Blocks_Recursion)!!![Recursion &darr;|show][Recursion &uarr;|hide]
{{lf qdn{<br>Output:}}}{{lift dn1px w50pct{{{dn ib pre b3d u3d d3d fwhi{{{_{
''120''
}}}}}}}}}/%

%/{{block pre ppur{{{_{
Smalltalk at: #Fac put: nil.

Fac := [ :n | n <= 1 ifTrue: [ 1 ] ifFalse: [ n * (Fac value: n - 1) ] ].

Transcript show: (Fac value: 5); newLine
}}}}}}/%

%/{{block pre pred{{{lf praem vrr{
Fac = lambda {|n| n <= 1 ? 1 : n * Fac.call n - 1 }

puts Fac.call 5
}}}{{ib plhem praem vrr{
Fac = lambda {|n| n <= 1 ? 1 : n * Fac[n - 1] }

puts Fac[5]
}}}{{ib pl1em{
Fac = ->(n) { n <= 1 ? 1 : n * Fac[n - 1] }

puts Fac[5]
}}}}}}/%

%/{{block pre pred{
{{serif{+++(~Smalltalk80Blocks_Ruby)[Method &darr;|show][Method &uarr;|hide]
&nbsp;
{{tt{
def fac(n); n <= 1 ? 1 : n * fac(n - 1); end

puts fac 5
}}}
===
}}}}}}/%

%/{{block pre b3w{{{_{
fac = lambda n: 1 if n <= 1 else n * fac(n - 1)

print(fac(5))
}}}}}}/%

%/{{block pre b3w{
{{serif{+++(~Smalltalk80Blocks_Python)[Classical function definition &darr;|show][Classical function definition &uarr;|hide]
&nbsp;
{{tt{
def fac(n): 1 if n <= 1 else n * fac(n - 1)

print(fac(5))
}}}
===
}}}}}}/%

%/{{block pre pgre{{{_{
fac = function (n) return n <= 1 and 1 or n * fac(n - 1) end

print(fac(5))
}}}}}}/%

%/{{block pre pblu{{{lf praem vrr{
(define fac (lambda (n) (if (<= n 1) 1 (* n (fac (- n 1))))))

(display (fac 5)) (newline)
}}}{{ib plhem{
(define (fac n) (if (<= n 1) 1 (* n (fac (- n 1))))))

(display (fac 5)) (newline)
}}}}}}/%

%/{{block pre pyel{{{_{
fac: func [n] [either n <= 1 [1] [n * fac n - 1]]

print fac 5
}}}}}}
===/%

%/{{_{
+++(~Smalltalk80Blocks_Closure)!!![Closure &darr;|show][Closure &uarr;|hide]
{{lf qdn{<br>Output:}}}{{lf dn1px{{{dn ib pre0 b3d u3d d3d fwhi{{{_{
''
Counter0:
  0
  1
  2
  3

Counter1:
  1
  2

Counter0:
  4''
}}}}}}}}}{{lf qdn{<br>or}}}{{lift dn1px{{{dn ib pre0 b3d u3d d3d fwhi{{{_{
''
counter0:
  0
  1
  2
  3

counter1:
  1
  2

counter0:
  4''
}}}}}}}}}/%

%/{{block pre ppur{{{_{
Smalltalk at: #Countermaker put: [ :i |
  | j |
  j := i - 1.     {{f3m{//"Cannot store this value in i."//}}}
  [ j := j + 1 ]
].

Smalltalk at: #Counter0 put: (Countermaker value: 0).
Transcript newLine show: 'Counter0:'; newLine.
3 timesRepeat: [ Transcript show: '  ', Counter0 value printString; newLine ].

Smalltalk at: #Counter1 put:(Countermaker value: 1).
Transcript show: '  ', Counter0 value printString; newLine.
Transcript newLine show: 'Counter1:'; newLine.
2 timesRepeat: [ Transcript show: '  ', Counter1 value printString; newLine ].

Transcript newLine show: 'Counter0:'; newLine.
Transcript show: '  ', Counter0 value printString; newLine
}}}}}}/%

%/{{block pre pred{{{lf prbem vrr{
Countermaker = lambda {|i|
  i -= 1
  lambda { i += 1 }
}

Counter0 = Countermaker.call 0
puts "\nCounter0:"
3.times { puts "  " + Counter0.call.to_s }

Counter1 = Countermaker.call 1
puts "  " + Counter0.call.to_s
puts "\nCounter1:"
2.times { puts "  " + Counter1.call.to_s }

puts "\nCounter0:"
puts "  " + Counter0.call.to_s
}}}{{ib plaem prbem vrr{
Countermaker = lambda do |i|
  i -= 1
  lambda { i += 1 }
end

Counter0 = Countermaker[0]
puts "\nCounter0:"
3.times { puts "  #{Counter0[]}" }

Counter1 = Countermaker[1]
puts "  #{Counter0[]}"
puts "\nCounter1:"
2.times { puts "  #{Counter1[]}" }

puts "\nCounter0:"
puts "  #{Counter0[]}"
}}}{{ib pl2em{
def countermaker(i)
  i -= 1
  lambda { i += 1 }
end

Counter0 = countermaker 0
puts "\nCounter0:"
3.times { puts "  #{Counter0[]}" }

Counter1 = countermaker 1
puts "  #{Counter0[]}"
puts "\nCounter1:"
2.times { puts "  #{Counter1[]}" }

puts "\nCounter0:"
puts "  #{Counter0[]}"
}}}}}}/%

%/{{block pre b3w{{{_{
def countermaker(i):
    i -= 1
    def _():
        nonlocal i
        return (i := i + 1)
    return _

counter0 = countermaker(0)
print("\ncounter0:")
for _ in range(3): print(f"  {counter0()}")

counter1 = countermaker(1)
print(f"  {counter0()}")
print("\ncounter1:")
for _ in range(2): print(f"  {counter1()}")

print("\ncounter0:")
print(f"  {counter0()}")
}}}}}}/%

%/{{block pre pgre{{{_{
function countermaker (i)
  i = i - 1
  return function ()
    i = i + 1
    return i
  end
end

counter0 = countermaker(0)
print "\ncounter0:"
for _ = 1, 3 do print("  " .. counter0()) end

counter1 = countermaker(1)
print("  " .. counter0())
print "\ncounter1:"
for _ = 1, 2 do print("  " .. counter1()) end

print "\ncounter0:"
print("  " .. counter0())
}}}}}}/%

%/{{block pre pblu{{{_{
(define (countermaker i)
    (set! i (- i 1))
    (lambda () (set! i (+ i 1)) i))

(define counter0 (countermaker 0))
(newline) (display "counter0:") (newline)
(do ((i 1 (+ i 1))) ((> i 3)) (begin (display (string-append "  " (number->string (counter0)))) (newline)))

(define counter1 (countermaker 1))
(display (string-append "  " (number->string (counter0)))) (newline)
(newline) (display "counter1:") (newline)
(do ((i 1 (+ i 1))) ((> i 2)) (begin (display (string-append "  " (number->string (counter1)))) (newline)))

(newline) (display "counter0:") (newline)
(display (string-append "  " (number->string (counter0)))) (newline)
}}}}}}/%

%/{{block pre pblu{
{{serif{+++(~Smalltalk80Blocks_Scheme)[Recursive &darr;|show][Recursive &uarr;|hide]
&nbsp;
{{tt{
(define (countermaker i)
    (set! i (- i 1))
    (lambda () (set! i (+ i 1)) i))

(define counter0 (countermaker 0))
(newline) (display "counter0:") (newline)
(letrec ((times (lambda (n)
                  (if (> n 0)
                    (begin (display (string-append "  " (number->string (counter0)))) (newline)
                           (times (- n 1)))))))
  (times 3))

(define counter1 (countermaker 1))
(display (string-append "  " (number->string (counter0)))) (newline)
(newline) (display "counter1:") (newline)
(letrec ((times (lambda (n)
                  (if (> n 0)
                    (begin (display (string-append "  " (number->string (counter1)))) (newline)
                           (times (- n 1)))))))
  (times 2))

(newline) (display "counter0:") (newline)
(display (string-append "  " (number->string (counter0)))) (newline)
}}}
===
}}}}}}/%

%/{{block pre pyel{{{_{
countermaker: closure [i] [i: i - 1 does [i: i + 1]]

counter0: countermaker 0
print "^/counter0:"
loop 3 [print ["  " counter0]]

counter1: countermaker 1
print ["  " counter0]
print "^/counter1:"
loop 2 [print ["  " counter1]]

print "^/counter0:"
print ["  " counter0]
}}}}}}/%

%/{{block pre pyel serif{
+++(~Smalltalk80Blocks_Rebol)[Non-closure &darr;|show][Non-closure &uarr;|hide]}}}
{{lf pr3em vrr tt{

countermaker: func [i] [i: i - 1 does [i: i + 1]]

counter0: countermaker 0
print "^/counter0:"
loop 3 [print ["  " counter0]]

counter1: countermaker 1
print ["  " counter0]
print "^/counter1:"
loop 2 [print ["  " counter1]]

print "^/counter0:"
print ["  " counter0]
}}}{{ib pl2em{
{{lf dn serif{Output:<br>&nbsp;}}}{{lift dn1px{{{dn ib pre0 b3d u3d d3d fwhi tt{{{_{
''
counter0:
  0
  1
  2
  1

counter1:
  2
  3

counter0:
  4''
}}}}}}}}}}}}
===
}}}
===/%

%/+++(~Smalltalk80Blocks_Locals)!!![Local variables &darr;|show][Local variables &uarr;|hide]
{{lf qdn{<br>Output:}}}{{lift dn1px w50pct{{{dn ib pre b3d u3d d3d fwhi{{{_{
''13
42
13''
}}}}}}}}}/%

%/{{block pre ppur{{{lf pr2em vrr{
[ | a b |
  a := 13.
  b :=  7.
  Transcript show: a; newLine.

  [ | {{fred{a |               //"<-Error: Name already used in this method."//
    a := 6 * b.
    Transcript show: a; newLine
  ] value.

  Transcript show: a; newLine
] value}}}
}}}{{ib plhem pr2em vrr{

Smalltalk at: #a put: 13.
Smalltalk at: #b put:  7.
Transcript show: a; newLine.

[ | a |
  a := 6 * b.
  Transcript show: a; newLine
] value.

Transcript show: a; newLine.
Transcript show: Smalltalk at: #a; newLine
}}}{{ib pl1em{
{{lf dn serif{Output:<br>&nbsp;}}}{{lift dn1px{{{dn ib pre0 b3d u3d d3d fwhi tt{{{_{
''13
42
nil
13''
}}}}}}}}}}}}
}}}/%

%/{{lf pre pred{{{_{
a = 13
b =  7
puts a

lambda do |; a|
  a = 6 * b
  puts a
end.call

puts a
}}}}}}/%

%/{{lf pre b3w{{{_{
a = 13
b =  7
print(a)

def _():
    a = 6 * b
    print(a)
_()

print(a)
}}}}}}/%

%/{{lf pre pgre{{{_{
local a = 13
local b =  7
print(a)

do
  local a = 6 * b
  print(a)
end

print(a)
}}}}}}/%

%/{{lf pre pblu{{{_{
(define a 13)
(define b  7)
(display a) (newline)

(let
  ((a (* 6 b)))
  (display a) (newline))


(display a) (newline)
}}}}}}/%

%/{{lf pre pyel{{{_{
a: 13
b:  7
print a

use [a] [
    a: 6 * b
    print a
]

print a
}}}}}}{{lf plaem{
<br><br><br><br><br><br><br><br>
}}}
* The first Smalltalk, Ruby, and Lua examples start with //local// variables ''{{{a}}}'' and ''{{{b}}}''.
* The second Smalltalk, Python, Scheme, and Rebol examples start with //global// variables ''{{{a}}}'' and ''{{{b}}}''.
* All examples have the value ''{{sans{6 {{tt{*}}} b}}}'' assigned to a //local// variable ''{{{a}}}''.
{{clear block{}}}
===
/***
|Name|SnapshotPlugin|
|Source|http://www.TiddlyTools.com/#SnapshotPlugin|
|Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo|
|Version|1.4.3//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|save or print HTML+CSS image of rendered document content|
This plugin provides a macro as well as tiddler toolbar commands to create a file or browser window containing the //rendered// CSS-and-HTML that is currently being displayed for selected elements of the current document.
!!!!!Documentation
>see [[SnapshotPluginInfo]]
!!!!!Configuration
<<<
<<option chkSnapshotHTMLOnly>> output HTML only (omit CSS)
<<<
!!!!!Revisions
<<<
2011.02.14 1.4.3 fix OSX error: use picker.file.path
2011.01.03 1.4.2 added snapshotSaveViewer toolbar command
2010.12.15 1.4.1 added 'snapshot' class to wrapper
|please see [[SnapshotPluginInfo]] for additional revision details|
2008.04.21 1.0.0 initial release - derived from [[NewDocumentPlugin]] with many improvements...
<<<
!!!!!Code
***/
//{{{
version.extensions.SnapshotPlugin= {major: 1, minor: 4, revision: 3, date: new Date(2011,2,14)};

if (config.options.chkSnapshotHTMLOnly===undefined)
	config.options.chkSnapshotHTMLOnly=false;

config.macros.snapshot = {
	snapLabel: "save a snapshot",
	printLabel: "print a snapshot",
	snapPrompt: "save an HTML image",
	printPrompt: "print an HTML image",
	hereID: "here",
	viewerID: "viewer",
	storyID: "story",
	allID: "all",
	askID: "ask",
	askTiddlerID: "askTiddler",
	askDOMID: "askDOM",
	askMsg: "select an element...",
	hereItem: "tiddler: '%0'",
	viewerItem: "tiddler: '%0' (content only)",
	storyItem: "story column (one file)",
	storyFilesItem: "story column (multiple files)",
	allItem: "entire document",
	tiddlerItem: "select a tiddler...",
	IDItem: "select a DOM element by ID...",
	HTMLItem: "[%0] output HTML only (omit CSS)",
	fileMsg: "select or enter a target path/filename",
	defaultFilename: "snapshot.html",
	okmsg: "snapshot written to %0",
	failmsg: "An error occurred while creating %0",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var printing=params[0]&&params[0]=="print"; if (printing) params.shift();
		params = paramString.parseParams("anon",null,true,false,false);
		var id=getParam(params,"id","here");
		var label=getParam(params,"label",printing?this.printLabel:this.snapLabel);
		var prompt=getParam(params,"prompt",printing?this.printPrompt:this.snapPrompt);
		var btn=createTiddlyButton(place,label,prompt, function(ev){
			this.setAttribute("snapID",this.getAttribute("startID"));
			config.macros.snapshot.go(this,ev)
		});
		btn.setAttribute("startID",id);
		btn.setAttribute("snapID",id);
		btn.setAttribute("printing",printing?"true":"false");
		btn.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
	},
	go: function(here,ev) {
		var cms=config.macros.snapshot; // abbreviation
		var id=here.getAttribute("snapID");
		var printing=here.getAttribute("printing")=="true";
		var HTMLOnly=here.getAttribute("HTMLOnly")=="true";

		if (id==cms.askID||id==cms.askTiddlerID||id==cms.askDOMID) {
			cms.askForID(here,ev);
		} else if (id==cms.storyID) {
			story.forEachTiddler(function(t,e) {
				var out=cms.getsnap(e,e.id,printing,HTMLOnly);
				if (printing) cms.printsnap(out);
				else cms.savesnap(out,e.getAttribute('tiddler')+'.html');
			});
		} else {
			if (id==cms.allID) id="contentWrapper";
			var snapElem=document.getElementById(id);
			if (id==cms.hereID || id==cms.viewerID)
				var snapElem=story.findContainingTiddler(here);
			if (snapElem && hasClass(snapElem,"tiddler") && (id==cms.viewerID || HTMLOnly)) {
				// find viewer class element within tiddler element
				var nodes=snapElem.getElementsByTagName("*");
				for (var i=0; i<nodes.length; i++)
					if (hasClass(nodes[i],"viewer")) { snapElem=nodes[i]; break; }
			}
			if (!snapElem) // not in a tiddler or no viewer element or unknown ID
				{ e.cancelBubble=true; if(e.stopPropagation)e.stopPropagation(); return(false); }
			// write or print snapshot
			var out=cms.getsnap(snapElem,id,printing,HTMLOnly);
			if (printing) cms.printsnap(out); else cms.savesnap(out);
		}
		return false;
	},
	askForID: function(here,ev) {
		var ev = ev ? ev : window.event; 
		var cms=config.macros.snapshot; // abbreviation
		var id=here.getAttribute("snapID");
		var indent='\xa0\xa0\xa0\xa0';
		var p=Popup.create(here); if (!p) return false; p.className+=' sticky smallform';
		var s=createTiddlyElement(p,'select'); s.button=here;
		if (id==cms.askID) {
			s.options[s.length]=new Option(cms.askMsg,cms.askID);
			var tid=story.findContainingTiddler(here);
			if(tid) { 
				var title=tid.getAttribute("tiddler");
				if (here.getAttribute("HTMLOnly")!="true")
					s.options[s.length]=new Option(indent+cms.hereItem.format([title]),cms.hereID);
				s.options[s.length]=new Option(indent+cms.viewerItem.format([title]),cms.viewerID);
			}
			s.options[s.length]=new Option(indent+cms.tiddlerItem,cms.askTiddlerID);
			s.options[s.length]=new Option(indent+cms.IDItem,cms.askDOMID);
			s.options[s.length]=new Option(indent+cms.storyItem,"tiddlerDisplay");
			s.options[s.length]=new Option(indent+cms.storyFilesItem,cms.storyID);
			s.options[s.length]=new Option(indent+cms.allItem,"contentWrapper");
		}
		if (id==cms.askDOMID) {
			s.options[s.length]=new Option(cms.IDItem,cms.askDOMID);
			var elems=document.getElementsByTagName("*");
			var ids=[];
			for (var i=0;i<elems.length;i++)
				if (elems[i].id.length && elems[i].className!="animationContainer")
					ids.push(elems[i].id);
			ids.sort();
			for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i],ids[i]);
		}
		if (id==cms.askTiddlerID) {
			s.options[s.length]=new Option(cms.tiddlerItem,cms.askTiddlerID);
			var elems=document.getElementsByTagName("div");
			var ids=[];
			for (var i=0;i<elems.length;i++) { var id=elems[i].id;
				if (id.length && id.substr(0,story.idPrefix.length)==story.idPrefix && id!="tiddlerDisplay")
					ids.push(id);
			}
			ids.sort();
			for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i].substr(story.idPrefix.length),ids[i]);
		}
		s.options[s.length]=new Option(cms.HTMLItem.format([here.getAttribute("HTMLOnly")=="true"?"\u221a":"_"]),cms.HTMLItem);
		s.onchange=function(ev){
			var ev = ev ? ev : window.event; 
			var cms=config.macros.snapshot; // abbreviation
			var here=this.button;
			if (this.value==cms.HTMLItem) {
				config.options.chkSnapshotHTMLOnly=!config.options.chkSnapshotHTMLOnly;
				here.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
				config.macros.option.propagateOption("chkSnapshotHTMLOnly","checked",
					config.options.chkSnapshotHTMLOnly,"input");
			} else
				here.setAttribute("snapID",this.value);
			config.macros.snapshot.go(here,ev);
			return false;
		};
		Popup.show();
		ev.cancelBubble=true;
		if(ev.stopPropagation)ev.stopPropagation();
		return false;
	},
	getpath: function() {
		// get current path
		var path=getLocalPath(window.location.href);
		var slashpos=path.lastIndexOf("/");
		if (slashpos==-1) slashpos=path.lastIndexOf("\\"); 
		if (slashpos!=-1) path=path.substr(0,slashpos+1); // trim filename
		return path;
	},
	getsnap: function(snapElem,id,printing,HTMLOnly) {
		var cms=config.macros.snapshot; // abbreviation
		var out='<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />';
		if (printing)
			out+='<base href="file:///'+cms.getpath().replace(/\\/g,'/')+'"></base>\n';
		if (!HTMLOnly) {
			var styles=document.getElementsByTagName('style');
			var fmt='<style>\n/* stylesheet=%0 */\n%1\n\n</style>\n';
			for(var i=0; i < styles.length; i++)
				out+=fmt.format([styles[i].getAttribute('id'),styles[i].innerHTML]);
		}
		out+='</head>\n';

		var elems=snapElem.getElementsByTagName('input');
		for (var i=0; i<elems.length; i++) { var e=elems[i];
			if (e.type=='text')		e.defaultValue=e.value;
			if (e.type=='checkbox')	 	e.defaultChecked=e.checked;
			if (e.type=='radiobutton')	e.defaultChecked=e.checked;
		}
		var elems=snapElem.getElementsByTagName('textarea');
		for (var i=0; i<elems.length; i++)	elems[i].defaultValue=elems[i].value;

		var fmt='<body>\n\n<div class="snapshot %0">%1</div>\n\n</body>\n';
		out+=fmt.format([(id==cms.viewerID?'tiddler viewer':''),snapElem.innerHTML]);

		return '<html>\n'+out+'</html>';
	},
	printsnap: function(out) {
		var win=window.open("","_blank","");
		win.document.open();
		win.document.writeln(out);
		win.document.close();
		win.focus(); // bring to front
		win.print(); // trigger print dialog
	},
	savesnap: function(out,target) {
		var cms=config.macros.snapshot; // abbreviation
		// make sure we are local
		if (window.location.protocol!="file:")
			{ alert(config.messages.notFileUrlError); return; }
		var target=target||cms.askForFilename(cms.fileMsg,cms.getpath(),cms.defaultFilename);
		if (!target) return; // cancelled by user
		// if specified file does not include a path, assemble fully qualified path and filename
		var slashpos=target.lastIndexOf("/"); if (slashpos==-1) slashpos=target.lastIndexOf("\\");
		if (slashpos==-1) {
			var h=document.location.href;
			var cwd=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf('/')+1)));
			target=cwd+target;
		}
		var link="file:///"+target.replace(/\\/g,'/'); // link for message text
		var ok=saveFile(target,convertUnicodeToUTF8(out));
		var msg=ok?cms.okmsg.format([target]):cms.failmsg.format([target]);
		displayMessage(msg,link);
	},
	askForFilename: function(msg,path,file) {
/*
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeSave);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension='html';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
				if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.path;
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
*/
			try { // XP/Vista only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
				s.FilterIndex=3; // default to HTML files;
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
//		}
		return result;
	}
};
//}}}

// // TOOLBAR DEFINITIONS
//{{{
config.commands.snapshotSave = {
	text: "snap",
	tooltip: config.macros.snapshot.snapPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","ask");
		src.setAttribute("printing","false");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotSaveViewer = {
	text: "snap",
	tooltip: config.macros.snapshot.snapPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","viewer");
		src.setAttribute("printing","false");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotPrint = {
	text: "print",
	tooltip: config.macros.snapshot.printPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","ask");
		src.setAttribute("printing","true");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotPrintViewer = {
	text: "print",
	tooltip: config.macros.snapshot.printPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","viewer");
		src.setAttribute("printing","true");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
//}}}

// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/***
|Name|SnapshotPluginInfo|
|Source|http://www.TiddlyTools.com/#SnapshotPlugin|
|Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo|
|Version|1.4.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for [[SnapshotPlugin]]|
This plugin provides a macro as well as tiddler toolbar commands that creates a file or opens a new browser window containing the //rendered// HTML and CSS style definitions that are being displayed for selected elements of the current document.
!!!!!Usage:
<<<
As a macro embedded in tiddler content:
{{{
<<snapshot print label:text prompt:text id:elementID|here|viewer|story|all|ask>
}}}
where:
*''print'' //(optional)//<br>when present, causes the snapshot output to be directed to a new browser tab/window instead of saving it to a file.  In addition, the print dialog for that tab/window is automatically invoked.
*''label'' //(optional)//<br>is the text to be displayed for the command link generated by the macro
*''prompt'' //(optional)//<br>is the 'tool tip' message displayed when you mouseover the command link
*''id:...'' //(optional)//<br>specifies the document element to be captured, and can be one of:
**''elementID''<br>is a specific DOM element ID, such as "displayArea", "mainMenu", "contentWrapper", etc.
**''here''<br>the containing tiddler in which the macro (or toolbar command) occurs, including the tiddler title and subtitle (date/time/author) information.
**''viewer''<br>same as ''here'', but omits the tiddler title, subtitle and toolbar elements (i.e., it includes //only// the content of the tiddler)
**''story''<br>selects all currently displayed tiddlers (i.e., the 'story column')
**''all''<br>selects the entire document contents, including page header, main menu and sidebar displays
**''ask''<br>when the snapshot command link is clicked, a droplist is displayed so you can choose from several pre-defined elements: "current tiddler", "story column", or "entire document", or "DOM element ID..."  When DOM element ID is chosen, the droplist is refreshed to show the individual ID's for all currently rendered DOM elements (at least, the ones that have ID's).  For any given DOM element ID, only the portions of the document that are contained //within// the specified DOM element will be transcribed to the resulting snapshot or print output.  
//''NOTE: when no parameters are specified, the macro creates a snapshot file using the containing tiddler as the default element.'' (e.g., equivalent to {{{<<snapshot id:here>>}}}//

The snapshot/print functions can also be embedded as tiddler toolbar commands in [[ViewTemplate]]:
{{{
<span class='toolbar' macro='toolbar snapshotSave'></span>
<span class='toolbar' macro='toolbar snapshotSaveViewer'></span>
<span class='toolbar' macro='toolbar snapshotPrint'></span>
<span class='toolbar' macro='toolbar snapshotPrintViewer'></span>
}}}
* By default, the toolbar commands use the "id:ask" option to display a droplist of elements to select from.  The "...Viewer" form of each command bypasses the droplist and automatically selects the current tiddler viewer area for saving/printing.

Please note that, although the snapshot/print that is created using the HTML+CSS of the displayed content, ''there is NO javascript code'' written into the snapshot.  As a result, the snapshot only ''reproduces the //appearance// of the displayed content, allowing you to //view// or //print// the result'', but does not permit you to interact with it in other ways.

For example, even simple processing (such as mouseover highlighting) will not function from the snapshot.  You can't click a TiddlyLink to open other tiddlers, because A) there is no code that handles the click and B) there is no underlying 'storeArea' (and core code) to retrieve and render anything!  You also can't use ANY command links, since these also require javascript code (and the core) to operate. 

__''Custom CSS for printing''__
There can be differences in the appearance of snapshot output when rendered on different devices (e.g. screen vs. printer).  Although these differences are typically very minor, it is sometimes necessary to define alternative CSS styles to account for the differences in device characteristics, such as font metrics, page sizes, resolutions, etc.  You can use the {{{@@media}}} wrapper within your custom StyleSheet CSS to define printer-specific formatting:
{{{
@media print {
...
}
}}}
The plugin places the snapshot output within a custom CSS class wrapper, using the classname, "{{{.snapshot}}}".  This enables you to define and apply custom formatting rules to 'fine tune' the appearance of the snapshot output, regardless of the intended output device.  For example, the following rule will override and hide tiddler borders and background colors when displaying and/or printing snapshots.
{{{
.snapshot .viewer { border:0 !important; background-color:none !important; }
}}}
<<<
!!!!!Examples:
<<<
{{{<<snapshot>>}}}: <<snapshot>>
{{{<<snapshot id:mainMenu>>}}}: <<snapshot id:mainMenu>>
{{{<<snapshot print id:story>>}}}: <<snapshot print id:story>>
{{{<<snapshot print id:ask>>}}}: <<snapshot print id:ask>>
{{{<<snapshot print noCSS id:viewer>>}}}: <<snapshot print noCSS id:viewer>>
<<<
!!!!!Configuration
<<<
<<option chkSnapshotHTMLOnly>> output HTML only (omit CSS)
<<<
!!!!!Revisions
<<<
2011.01.03 1.4.2 added snapshotSaveViewer toolbar command
2010.12.15 1.4.1 added 'snapshot' class to wrapper
2010.11.20 1.4.0 added snapshotPrintViewer toolbar command
2009.10.12 1.3.0 added multi-file story snapshot
2009.09.25 1.2.1 in getSnap(), added META tag to set UTF-8 encoding for I18N support
2009.06.04 1.2.0 added handling in getSnap() so current form input values are shown in snapshots
2008.05.16 1.1.1 added try..catch around addEvent/removeEvent calls to avoid error in Opera
2008.04.28 1.1.0 removed 'viewerHTML' from 'ask' droplist and replaced with toggle for "output HTML only".  Removed 'noCSS' parameter and replaced with config.options.chkSnapshotHTMLOnly global option.  Added "select a tiddler..." to 'ask' droplist
2008.04.24 1.0.1 in saveSnap(), convert output from Unicode to UTF before passing to saveFile().  Fixes "unknown name" error in IE's file.Write() function.
2008.04.21 1.0.0 initial release - derived from [[NewDocumentPlugin]] with many improvements, including: "ask for ID" using droplist of available DOM elements, use "<base href=...>" for correctly resolving image references, wrap 'viewer only' output in class="tiddler viewer" for proper application of inherited CSS styles, snapshotSave and snapshotPrint tiddler toolbar command definitions, and more...

__Excerpted revisions from [[NewDocumentPlugin]] (obsolete)__
2008.04.20 1.8.0 added support for 'noCSS' and 'viewer' params for alternative snapshot output
2007.03.30 1.7.0 added support for "print" param as alternative for "snap".  When "print" is used, the filename is ignored and ouput is directed to another browser tab/window, where the print dialog is then automatically triggered.
2007.03.30 1.6.1 added support for "here" keyword for current tiddler elementID and "prompt:text" param for specifying tooltip text
2006.10.18 1.5.0 new optional param for 'snap'... specify alternative DOM element ID (default is still "contentWrapper").  Based on a suggestion from Xavier Verges.
2006.03.09 1.2.0 added special "snap" filter parameter to generate and write "snapshot" files containing static HTML+CSS for currently rendered document.
2006.02.03 1.0.0 Created.
<<<
Sorting in ASCII order (or more precisely: byte value order) can be more difficult than expected. The {{{sort}}} program seems to ignore punctuation characters, for instance. Suppose we have this file {{{3lines.txt}}}:
{{{
abc
ghi
.def
}}}
Possibly not what we want:
<html><pre>
$ <font color="green"><b>sort 3lines.txt</b></font>
abc
.def
ghi
</pre></html>/%
%/To get the ASCII order:
<html><pre>
$ <font color="green"><b>LC_COLLATE=C sort 3lines.txt</b></font>
.def
abc
ghi
</pre></html>
----

[{{t s{11 OCTOBER 2021}}}] In my experience, macOS applies the ASCII order by default.
<<tiddler [[{}::togglesliders]]>> De ontwikkeling van [[C|https://en.wikipedia.org/wiki/C_(programming_language)]] valt kortweg zo samen te vatten:
{{u3 d3 r pl1em ws{
[[ALGOL 60]] {{fblu{&rarr;}}} CPL {{fred{&rarr;}}} BCPL {{fred{&rarr;}}} B {{fblu{&rarr;}}} C (1972) {{fblu{&rarr;}}} K&R C (C78) {{fblu{&rarr;}}} [[ANSI/ISO C|https://en.wikipedia.org/wiki/ANSI_C]] (C89/C90) {{fblu{&rarr;}}} C95 {{fblu{&rarr;}}} C99 {{fblu{&rarr;}}} C11 {{fgra{&rarr;}}} C17 {{fblu{&rarr;}}} C23
}}} De blauwe pijlen geven groei aan, de rode vereenvoudiging, en de grijze correctie. Dat maakt inzichtelijk waarom [[B|https://en.wikipedia.org/wiki/B_(programming_language)]] voor sommigen de ultieme programmeertaal is.{{ref{[[[1]|##01]]}}} Aangezien ik pas kort na 1990 voor het eerst zelf iets met C heb gedaan, is ''ANSI C'' het vertrekpunt geworden voor mijn inventarisatie van wat er in de loop der tijd aan de taal gesleuteld is./%

%/
!!C23
* ''{{sans{[[Overzicht|https://en.wikipedia.org/wiki/C23_(C_standard_revision)]]}}}''
* Véél nieuwigheden
* ''{{tt rr bred fwhi{!}}}'' Verwijdering van verouderde constructies:
** //Trigrafen//
** Functiedefinities/declaraties volgens K&R, d.w.z. //zonder informatie over de functieparameters//
** //Signed integers anders dan two's complement//
** De {{tt t{*_HAS_SUBNORM}}}//-macro's// in {{tt t{<float.h>}}}/%

%/
+++(~C_C17)!![C17 &darr;|show][C17 &uarr;|hide]
* ''{{sans{[[Overzicht|https://en.wikipedia.org/wiki/C17_(C_standard_revision)]]}}}''
* Alleen rechtzetting van wat kleine foutjes in C11.
===/%

%/+++(~C_C11)!![C11 &darr;|show][C11 &uarr;|hide]
* ''{{sans{[[Overzicht|https://en.wikipedia.org/wiki/C11_(C_standard_revision)]]}}}''
* Verbeterde ondersteuning van //Unicode//
* //Type-generic expressions// m.b.v. keyword ''{{hitt{_Generic}}}'' 
* //Cross-platform multi-threading API// ({{tt t{threads.h}}})
* //Atomaire primitieven// en //types// (type qualifier ''{{hitt{_Atomic}}}'')
* //Anonieme structures// en //unions// 

===/%

%/+++(~C_C99)!![C99 &darr;|show][C99 &uarr;|hide]
* ''{{sans{[[Overzicht|https://en.wikipedia.org/wiki/C99_(C_standard_revision)]]}}}''{{ref{&#x200a;[[[2]|##02]]}}}
* Nieuwe //ingbebouwde gegevenstypen//: {{tt t{long long}}}, {{tt t{_Bool}}}, {{tt t{_Complex}}} en {{tt t{_Imaginary}}}
* Nieuwe taalvoorzieningen, waaronder //static array indices//, //designated initializers//, //compound literals//, //variable-length arrays//, //flexible array members//, //variadische macro's// en het keyword ''{{hitt{restrict}}}''
* Nieuwe //library headers//, waaronder {{tt t{stdint.h}}}, {{tt t{<tgmath.h>}}}, {{tt t{fenv.h}}} en {{tt t{<complex.h>}}}
* Verbeterde compatibiliteit met diverse C++-voorzieningen, waaronder //inline functions//, //regelcommentaar// m.b.v. ''{{hitt{"""//"""}}}'', //menging van declaraties en code//, en //universele karakternamen in identifiers//
* ''{{tt rr bred fwhi{!}}}'' Verwijdering van gevaarlijk geachte C89/C90-voorzieningen zoals //impliciete functiedeclaraties// en //impliciete typering// ''{{hitt{ int}}}''

===/%

%/+++(~C_C95)!![C95 (amendement van C89/C90) &darr;|show][C95 (amendement van C89/C90) &uarr;|hide]
* ''{{sans{[[Overzicht|https://en.wikipedia.org/wiki/ANSI_C]]}}}''{{ref{&#x200a;[[[3]|##03]]}}}
* Verbeterde ondersteuning van //multibyte-// en //wide characters//
* Toevoeging van //digrafen//
* Standardmacros voor //alternatieve schrijfwijze van operators//, zoals ''{{hitt{and}}}'' voor ''{{hitt{&&}}}''
* Standardmacro {{tt t{"""__STDC_VERSION__"""}}}

===

----
|plain |k
|<html><a name="01">[1]</a></html>|De meest recente compiler die ik in de Internet-etalage zag liggen, heet [[BCause|https://github.com/spydr06/BCause]] en zou alleen {{sans{gnu-linux-x86_64}}}-systemen ondersteunen. |
|<html><a name="02">[2]</a></html>|<<tiddler Bibliografie##Prata>> |
|<html><a name="03">[3]</a></html>|<<tiddler Bibliografie##K&R>><br>Dit boek maakt gewag van de ANSI-standaard. Dat zal dan de draft C86 of de prerelease C88 zijn geweest. |
<<tiddler [[{}::togglesliders]]>> Onderstaande inventarisatie is slechts een selectie van de veranderingen (stapeling/aanpassing/verwijdering van features) die me het meest interessant leken. Ik heb daarbij nauwelijks verder terug gekeken dan de ontwikkelingen na de door Mark Lutz uitvoerig beschreven en becommentarieerde versie 3.3.{{ref{[[[1]|##1]]}}} Uitgebreidere overzichten zijn te vinden in [[What's New in Python|https://docs.python.org/3/whatsnew/index.html]].
!!Versies 3.10 en 3.11
Moeten nog worden geïnventariseerd./%

%/
+++(~Python_Versie3_9)!![Versie 3.9 &darr;|show][Versie 3.9 &uarr;|hide]
* ''{{sans{[[Overzicht|https://docs.python.org/3/whatsnew/3.9.html]]}}}''
* [[PEP 584 – Add union operators to dict|https://peps.python.org/pep-0584/]]  (operators merge ''{{hitt z{|}}}'' and update ''{{hitt z{|=}}}'' aan class {{tt t{dict}}} toegevoegd)
* [[PEP 585 – Type Hinting Generics In Standard Collections|https://peps.python.org/pep-0585/]]
* [[PEP 614 – Relaxing Grammar Restrictions On Decorators|https://peps.python.org/pep-0614/]] ({{hitt z{@buttons''{{fred{[0]}}}''.clicked.connect}}} -- voorheen verboden -- mag nu ook)
* [[PEP 616 – String methods to remove prefixes and suffixes|https://peps.python.org/pep-0616/]]
* [[PEP 593 – Flexible function and variable annotations|https://peps.python.org/pep-0593/]]
* [[PEP 615 – Support for the IANA Time Zone Database in the Standard Library|https://peps.python.org/pep-0615/]]
* [[PEP 602 – Annual Release Cycle for Python|https://peps.python.org/pep-0602/]] (namelijk in oktober)

===/%


%/+++(~Python_Versie3_8)!![Versie 3.8 &darr;|show][Versie 3.8 &uarr;|hide]
* ''{{sans{[[Overzicht|https://docs.python.org/3/whatsnew/3.8.html]]}}}''
* [[PEP 572 – Assignment Expressions|https://peps.python.org/pep-0572/]] (met 'walrus-operator' ''{{hitt z{:=}}}'')
* {{_{[[PEP 570 – Python Positional-Only Parameters|https://peps.python.org/pep-0570/]]:
In {{hitt z{def f(a, b, ''/'', c, d, ''*'', e, f): print(a, b, c, d, e, f)}}} kunnen {{tt t{a}}} en {{tt t{b}}} uitsluitend positioneel worden meegegeven, {{tt t{c}}} en {{tt t{d}}} zowel positioneel als per keyword, terwijl bij {{tt t{e}}} en {{tt t{f}}} het keyword verplicht is.}}}
* {{_{Ondersteuning van ''{{hitt z{=}}}'' in f-strings:
{{pref hitt z{a = 42; print(f'{a=}', f'{a = }', f'{type(a)  =  }' sep = ', ')}}} drukt {{pref tt t z hws u3m d3m r{a=42, a = 42, type(a)  =  <class 'int'>}}} af -- alle spaties rond het isgelijkteken doen mee.}}}
* [[PEP 587 – Python Initialization Configuration|https://peps.python.org/pep-0587/]] (nieuwe C API)
* Dict en dictviews zijn via de functie ''{{hitt z{reversed}}}'' nu ook iterabel in omgekeerde volgorde.

===/%

%/+++(~Python_Versie3_7)!![Versie 3.7 &darr;|show][Versie 3.7 &uarr;|hide]
* ''{{sans{[[Overzicht|https://docs.python.org/3/whatsnew/3.7.html]]}}}''
* [[PEP 563 – Postponed Evaluation of Annotations|https://peps.python.org/pep-563]]
* Nieuwe voorzieningen in ''{{hitt z{asyncio}}}'' module; ''{{hitt z{async}}}'' and ''{{hitt z{await}}}'' zijn voortaan gereserveerde keywords
* [[PEP 567 – Context Variables|https://peps.python.org/pep-567]] (nieuwe library ''{{hitt z{contextvars}}}'')
* [[PEP 557 – Data Classes|https://peps.python.org/pep-557]] (nieuwe decorator ''{{hitt z{dataclass}}}'')
* Nieuwe module ''{{hitt z{importlib.resources}}}''
* [[PEP 553 – Built-in breakpoint()|https://peps.python.org/pep-0553/]]
* De module ''{{hitt z{time}}}'' ondersteunt nu ook een resolutie van nanoseconden
* [[PEP 540 – Add a new UTF-8 Mode|https://peps.python.org/pep-0540/]] (nieuwe commandline-optie ''{{hitt z{-X utf8}}}'' en omgevingsvariabele ''{{hitt z{PYTHONUTF8}}}'')

===/%

%/+++(~Python_Versie3_6)!![Versie 3.6 &darr;|show][Versie 3.6 &uarr;|hide]
* ''{{sans{[[Overzicht|https://docs.python.org/3/whatsnew/3.6.html]]}}}''
* [[PEP 498 – Formatted string literals|https://peps.python.org/pep-498]] oftewel //f-strings//
* [[PEP 526 – Syntax for variable annotations|https://peps.python.org/pep-0526/]] (vervolg op PEP 484 in versie 3.5)
* [[PEP 515 – Underscores in Numeric Literals|https://peps.python.org/pep-0515/]] (zoals ''{{hitt z{1_000_000}}}'')
* [[PEP 525 – Asynchronous Generators|https://peps.python.org/pep-0525/]] (aanvulling op PEP 492 in versie 3.5)
* [[PEP 530 – Asynchronous Comprehensions|https://peps.python.org/pep-0530/]]
* [[PEP 506 – Adding A Secrets Module To The Standard Library|https://peps.python.org/pep-0506/]]
* [[PEP 487 – Simpler customisation of class creation|https://peps.python.org/pep-0487/]] (subclass creation without using a metaclass)
* [[PEP 519 – Adding a file system path protocol|https://peps.python.org/pep-0519/]]
* [[PEP 495 – Local Time Disambiguation|https://peps.python.org/pep-0495/]] (zomertijd/wintertijd)
* [[PEP 520 – Preserving Class Attribute Definition Order|https://peps.python.org/pep-0520/]]
* [[PEP 468 – Preserving the order of **kwargs in a function|https://peps.python.org/pep-0468/]]
* New ''{{hitt{dict}}}'' implementation: //The {{t t{dict}}} type now uses a “compact” representation based on a proposal by Raymond Hettinger which was first implemented by PyPy. The memory usage of the new dict() is between 20% and 25% smaller compared to Python 3.5. The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon...//
* A ''{{hitt{global}}}'' or ''{{hitt{nonlocal}}}'' statement must now textually appear before the first use of the affected name in the same scope. Previously this was a {{tt t{SyntaxWarning}}}.

===/%

%/+++(~Python_Versie3_5)!![Versie 3.5 &darr;|show][Versie 3.5 &uarr;|hide]
* ''{{sans{[[Overzicht|https://docs.python.org/3/whatsnew/3.5.html]]}}}''
* [[PEP 492 – Coroutines with async and await syntax|https://peps.python.org/pep-0492/]]
* [[PEP 465 – A dedicated infix operator for matrix multiplication|https://peps.python.org/pep-0465/]] (namelijk ''{{hitt {@}}}'')
* [[PEP 448 – Additional Unpacking Generalizations|https://peps.python.org/pep-0448/]] (iterable unpacking operator ''{{hitt{*}}}'' en dictionary unpacking operator ''{{hitt{**}}}'')
* [[PEP 484 – Type Hints|https://peps.python.org/pep-0484/]]
* [[PEP 479 – Change StopIteration handling inside generators|https://peps.python.org/pep-0479/]]
* [[PEP 486 – Make the Python Launcher aware of virtual environments|https://peps.python.org/pep-0486/]]

===/%

%/+++(~Python_Versie3_4)!![Versie 3.4 &darr;|show][Versie 3.4 &uarr;|hide]
* ''{{sans{[[Overzicht|https://docs.python.org/3/whatsnew/3.4.html]]}}}''
* [[PEP 3156 – Asynchronous IO Support Rebooted: the “asyncio” Module|https://peps.python.org/pep-3156/]]
* [[PEP 435 – Adding an Enum type to the Python standard library|https://peps.python.org/pep-0435/]]
* [[PEP 428 – The pathlib module – object-oriented filesystem paths|https://peps.python.org/pep-0428/]]
* [[PEP 450 – Adding A Statistics Module To The Standard Library|https://peps.python.org/pep-0450/]]
* [[PEP 443 – Single-dispatch generic functions|https://peps.python.org/pep-0443/]]
* [[PEP 3154 – Pickle protocol version 4|https://peps.python.org/pep-3154/]]
* [[PEP 442 – Safe object finalization|https://peps.python.org/pep-0442/]]

===/%

%/+++(~Python_Versie3)!![Misschien toch ook nog steeds het noemen waard &darr;|show][Misschien toch ook nog steeds het noemen waard &uarr;|hide]
* ''{{sans{[[Versie 3.3|https://docs.python.org/3/whatsnew/3.3.html]]}}}:''
** [[PEP 405 – Python Virtual Environments|https://peps.python.org/pep-0405/]]
** [[PEP 380 – Syntax for Delegating to a Subgenerator|https://peps.python.org/pep-380/]]
** [[PEP 3155 – Qualified name for classes and functions|https://peps.python.org/pep-3155/]]
** [[PEP 412 – Key-Sharing Dictionary|https://peps.python.org/pep-0412/]]
* ''{{sans{[[Versie 3.2|https://docs.python.org/3/whatsnew/3.2.html]]}}}:'' [[PEP 389 – argparse - New Command Line Parsing Module|https://peps.python.org/pep-389/]]
* ''{{sans{[[Versie 3.1|https://docs.python.org/3/whatsnew/3.1.html]]}}}:'' [[PEP 378 – Format Specifier for Thousands Separator|https://peps.python.org/pep-0378/]]
* ''{{sans{[[Versie 3.0|https://docs.python.org/3/whatsnew/3.0.html]]}}}:'' [[PEP 3102 – Keyword-Only Arguments|https://peps.python.org/pep-3102/]] (functieparameter ''{{hitt{*}}}'')

===

----
|plain |k
|<html><a name="1">[1]</a></html>|<<tiddler Bibliografie##Lutz>> Bijgewerkt voor 3.3 en 2.7. |
This is a rather simplified representation of the state transitions in Opswise. A complete overview of all task states (designated as //statuses//) kan be found [[here|https://www.stonebranch.com/confluence/display/UC64/Displaying+Task+Instance+Status#DisplayingTaskInstanceStatus-TaskInstanceStatusTypes]]. The commands to force transitions are described [[here|https://www.stonebranch.com/confluence/display/UC64/Manually+Running+and+Controlling+Tasks]]. The transitions table below is a matrix of the 11 by 11 most common states in daily use. The initial state of a task instance is marked with the &#x25CF; symbol, and the six possible final states are marked with a &#x25C9;. Arrowheads denote the automatic transitions. The green ones (''{{fgre{&#x25BA;}}}'') follow the happy path of states, the red ones (''{{fred{&#x25BA;}}}'') an exception path.

<<eval [=[|vertical-align:bottom;!From &#x25BC; |vertical-align:top; !To &#x25BA;|!{{pref tt{  0  }}}<br><html><big><big><big>&#x25CF;</big></big></big></html>|!&nbsp;{{pref tt{ 10 }}}&nbsp;<br><html><big><big><big>&nbsp;</big></big></big></html>|!&nbsp;{{pref tt{ 20 }}}&nbsp;<br><html><big><big><big>&nbsp;</big></big></big></html>|!&nbsp;{{pref tt{ 80 }}}&nbsp;<br><html><big><big><big>&nbsp;</big></big></big></html>|!&nbsp;{{pref tt{ 81 }}}&nbsp;<br><html><big><big><big>&nbsp;</big></big></big></html>|!{{pref tt{ 120 }}}<br><html><big><big>&#x25C9;<big></big></big></big></html>|!{{pref tt{ 130 }}}<br><html><big><big>&#x25C9;<big></big></big></big></html>|!{{pref tt{ 140 }}}<br><html><big><big>&#x25C9;<big></big></big></big></html>|!{{pref tt{ 180 }}}<br><html><big><big>&#x25C9;<big></big></big></big></html>|!{{pref tt{ 190 }}}<br><html><big><big>&#x25C9;<big></big></big></big></html>|!{{pref tt{ 200 }}}<br><html><big><big>&#x25C9;<big></big></big></big></html>|
|~|~|>|>|bgcolor:$2P;|>|bgcolor:$2L;|>|>|bgcolor:red;|>|>|bgcolor:green;|
|>|bgcolor:$2W;''{{pref tt{  0 Defined        }}}'' &#x25CF;     | = | ''{{fgre{&#x25BA;}}}'' | H | ''{{fgre{&#x25BA;}}}''  |    | ''{{fred{&#x25BA;}}}'' |   |   | S | F |   |
|>|bgcolor:$2W;''{{pref tt{ 10 Waiting        }}}''              |   | =                      | H | ''{{fgre{&#x25BA;}}}''  |    | ''{{fred{&#x25BA;}}}'' |   |   | S | F |   |
|>|bgcolor:$2W;''{{pref tt{ 20 Held           }}}''              | R | R                      | = |                         | R  |                        |   |   | S | F |   |
|>|bgcolor:$2P;''{{pref tt{ 80 Running}}}'' //-- task//          | &nbsp; | &nbsp;       | &nbsp; | = | &nbsp;              | &nbsp; | C | ''{{fred{&#x25BA;}}}'' |   | F | ''{{fgre{&#x25BA;}}}'' |
|>|bgcolor:$2P;''{{pref tt{ 80 Running}}}'' //-- workflow//      |   |                        |   | = | C ''{{fred{&#x25BA;}}}'' |                        |   |   |   | F | ''{{fgre{&#x25BA;}}}'' |
|>|bgcolor:$2P;''{{pref tt{ 81 Running/Problems<br>    }}}''//(only workflow)// |   |         | H | &sect;                  | =  |                        |   |   |   | F |   |
|>|bgcolor:#ffddcc;''{{pref tt{120 Start Failure  }}}'' &#x25C9; |   |                        |   | &reg;                   |    | =                      |   |   |   | F |   |
|>|bgcolor:#ffddcc;''{{pref tt{130 Cancelled      }}}'' &#x25C9; |   |                        |   | &reg;                   |    |                        | = |   |   | F |   |
|>|bgcolor:#ffddcc;''{{pref tt{140 Failed         }}}'' &#x25C9;<br>{{pref tt{    }}}//(not workflow)// |   |   |   | &reg; |    |                        |   | = |   | F |   |
|>|bgcolor:#ccffbb;''{{pref tt{180 Skipped        }}}'' &#x25C9; | U | U                      |   |                         |    |                        |   |   | = |   |   |
|>|bgcolor:#ccffbb;''{{pref tt{190 Finished       }}}'' &#x25C9; |   |                        |   | &reg;                   |    |                        |   |   |   | = |   |
|>|bgcolor:#ccffbb;''{{pref tt{200 Success        }}}'' &#x25C9; |   |                        |   | &reg;                   |    |                        |   |   |   |   | = |
|>|bgcolor:$2M;|>|>|bgcolor:$2P;|>|bgcolor:$2L;|>|>|bgcolor:red;|>|>|bgcolor:green;|]=]>>
/%

%/Transitions can also be realized by commands on a higher level (the enclosing workflow instance) or a lower level (the enclosed task instances). They are not included in the matrix, with one exception. The transition from {{hitt s{81&nbsp;Running/Problems}}} back to {{hitt s{80&nbsp;Running}}} is indicated by a ''&sect;'' sign. This can only be achieved by solving the problems on the level of the underlying tasks, directly below or even deeper.

In the Condition property of the Opswise connectors, states {{{180}}}&ndash;{{{200}}} are aggregated as 'Success', and states {{{120}}}&ndash;{{{140}}} as 'Failure'. Not surprisingly, the Condition 'Success/Failure' includes states {{{120}}}&ndash;{{{200}}}./%

%/
!!Transition commands
<<eval [=[|!Status &#x25BC; |!Command &#x25BA;|!C|!F|!S|!U|!H|!R|!&reg;|
|>|bgcolor:$2W;vertical-align:top;''{{pref tt{  0 Defined        }}}'' &#x25CF;     | |Force Finish<br>Force Finish (Halt) |Skip<br>Skip Path | |vertical-align:top;Hold |vertical-align:top;Release Recursive | |
|>|bgcolor:$2W;vertical-align:top;''{{pref tt{ 10 Waiting        }}}''              | |Force Finish<br>Force Finish (Halt) |Skip<br>Skip Path | |vertical-align:top;Hold |vertical-align:top;Release Recursive | |
|>|bgcolor:$2W;vertical-align:top;''{{pref tt{ 20 Held           }}}''              | |Force Finish<br>Force Finish (Halt) |Skip<br>Skip Path | | |Release<br>Release Recursive | |
|>|bgcolor:$2P;vertical-align:top;''{{pref tt{ 80 Running}}}'' //-- task//          |vertical-align:top;Cancel |Force Finish<br>Force Finish (Halt)<br>Force Finish/Cancel<br>Force Finish/Cancel (Halt) | | | | | |
|>|bgcolor:$2P;vertical-align:top;''{{pref tt{ 80 Running}}}'' //-- workflow//      |vertical-align:top;Cancel |Force Finish<br>Force Finish (Halt)<br>Force Finish/Cancel<br>Force Finish/Cancel (Halt) | | | |vertical-align:top;Release Recursive | |
|>|bgcolor:$2P;vertical-align:top;''{{pref tt{ 81 Running/Problems<br>    }}}''//(only workflow)// |vertical-align:top;Cancel |Force Finish<br>Force Finish (Halt)<br>Force Finish/Cancel<br>Force Finish/Cancel (Halt) | | |vertical-align:top;Hold |vertical-align:top;Release Recursive | |
|>|bgcolor:#ffddcc;vertical-align:top;''{{pref tt{120 Start Failure  }}}'' &#x25C9; | |Force Finish<br>Force Finish (Halt) | | | | |vertical-align:top;Re-run |
|>|bgcolor:#ffddcc;vertical-align:top;''{{pref tt{130 Cancelled      }}}'' &#x25C9; | |Force Finish<br>Force Finish (Halt) | | | | |vertical-align:top;Re-run |
|>|bgcolor:#ffddcc;vertical-align:top;''{{pref tt{140 Failed         }}}'' &#x25C9;<br>{{pref tt{    }}}//(not workflow)// | |Force Finish<br>Force Finish (Halt) | | | | |vertical-align:top;Re-run |
|>|bgcolor:#ccffbb;vertical-align:top;''{{pref tt{180 Skipped        }}}'' &#x25C9; | | | |Unskip | | |       |
|>|bgcolor:#ccffbb;vertical-align:top;''{{pref tt{190 Finished       }}}'' &#x25C9; | | | |       | | |Re-run |
|>|bgcolor:#ccffbb;vertical-align:top;''{{pref tt{200 Success        }}}'' &#x25C9; | | | |       | | |Re-run |]=]>>/%

%/<html><h3>Cancel</h3></html>/%
%/Task is not a workflow &rArr; status = {{hitt s{130 Cancelled}}}; status of enclosing workflow = {{hitt s{81 Running/Problems}}}.
Task is a workflow &rArr; status = {{hitt s{81 Running/Problems}}}; status of enclosed tasks = {{hitt s{130 Cancelled}}} (as far as possible).
Cancelled processes are interrupted, and their successors keep on waiting.
Rarely used at Achmea, if ever./%

%/
!!!Force Finish[/Cancel][ Halt]
Task is not a workflow &rArr; status = {{hitt s{190 Finished}}}; status of enclosing workflow = {{hitt s{200 Success}}} when all tasks are ended with status >= {{hitt s{180}}}.
Task is a workflow &rArr; status = {{hitt s{190 Finished}}}; status of enclosed tasks = {{hitt s{190 Finished}}} (as far as possible).
Issuing //Force Finish// or //Force Finish (Halt)// marks the task as finished even though the actual process continues running.
Issuing //Force Finish/__Cancel__// or //Force Finish/__Cancel__ (Halt)// interrupts running processes before marking the task as finished.
To prevent successors from starting, issue //Force Finish __(Halt)__// or //Force Finish/Cancel __(Halt)__//./%

%/
!!!Hold
Task is not a workflow &rArr; status = {{hitt s{20 Held}}}.
Task is a defined or waiting workflow &rArr; status = {{hitt s{20 Held}}}; status of enclosed tasks = {{hitt s{20 Held}}} (as far as possible).
Task is a running workflow &rArr; status does not change; status of enclosed tasks = {{hitt s{20 Held}}} (as far as possible)./%

%/
!!!Release[ Recursive]
To release a held task that is not a workflow, issue //Release//.
To release a held workflow but not its enclosed held tasks, issue //Release//.
To release a held workflow and all its enclosed held tasks, issue //Release __Recursive__//.
To release all enclosed held tasks of a not-held workflow, issue //Release __Recursive__//./%

%/
!!!Re-run
You can re-run a task as long as the enclosing workflow has not completed.
You cannot re-run a workflow.
[img[data/images/Module-types-a-la-Yourdon-and-Constantine.png]]

''{{fred sans{~!~ Deze tiddler is niet af. ~!~}}}''

----
|plain |k
| <html><a name="1">[1]</a></html>|<<tiddler Bibliografie##Y&C>> |
| <html><a name="2">[2]</a></html>|<<tiddler Bibliografie##Martin>> |
/***
!!Layout/%============================================================%/
***/
/*{{{*/
body {margin:0; padding:0;
  font-size:0.7em; font-family:IBM Plex Serif, Charter, Georgia, Lucida Fax, Lucida Bright, serif;
  font-variant-numeric:lining-nums tabular-nums;
}
#wwLeft {position:fixed; top:0; bottom:0; left:0; width:20px; padding-top: 20px; text-align:center; font-size:2em;}
#wwCurtain {position:fixed; top:0; right:220px; bottom:0; left:220px;}
#wwMain {margin:0 20px 0 220px;}
#wwRight {position:fixed; top:0; bottom:0; right:0; width:20px; padding-top: 20px; text-align:center; font-size:2em;}
.siteTitle {font-size:6em; line-height:1em;}
.siteSubtitle {font-size:2.3em; line-height:1.2em; text-transform:uppercase; letter-spacing:1pt;}
.header {margin-top:20px; margin-right:200px; border-radius:8px 8px 0 0;}
.headerForeground {position:relative; padding:26px 32px 20px 32px; text-shadow:1px 1px 3px gray;}
.tiddler {font-size:1.4em; margin:0 8px; padding:8px 24px;}
.title {font-size:3em; line-height:0.95em;}
.subtitle {font-size:0.75em; margin-bottom:1em; padding:6px 0 3px 0;}
#mainMenu {width:180px; top:0; overflow:auto; margin-left:20px; padding:0 20px 0 0; text-align:left;}
#sidebar {width:185px; top:0; right:0; overflow:auto; margin-right:20px; padding:29px 0 0 15px;}
#sidebar .searchField {width: 91.5%; margin-right:0;}
#sidebar input[name="gotoTiddler"] {margin-left:0.4em;}
#sidebar .sliderPanel .txtOptionInput {width:98%;}
#sidebar a[title="Expand all tiddlers"],
  #sidebar a[title="Collapse all tiddlers"] {display:inline-block;}
#sidebar div[tiddler="More sidebar options"] a,
  #sidebar div[tiddler="More sidebar options"] .button {display:block; border-width:1px; border-style:solid;}
#sidebar div[tiddler="More sidebar options"] a,
  #sidebar div[tiddler="More sidebar options"] .button {margin:0em 0.2em; padding:0 0.3em; font-weight:normal;}
#sidebar div[tiddler="More sidebar options"] hr {margin-left:0.5em; border:0; border-top:1px dotted [[ColorPalette::TertiaryDark]];}
#sidebarTabs {margin-bottom:2em; margin-left:0.5em;}
#sidebarTabs .button {margin:0em 0.2em; padding:0.2em 0.33em; display:block;}
#mainMenu, #sidebar, .toggleSidebar {
  font-family:IBM Plex Sans Condensed, IBMPlexSansCond, IBM Plex Sans, Calibri, Lucida Grande, Lucida Sans, -apple-system, BlinkMacSystemFont, sans-serif;
}
.toggleSidebar a, .toggleSidebar :hover, {font-weight: normal !important; font-style:italic; color:green;}
.toolbar .button {padding-top:0; padding-bottom:0;}
.toolbar2 {padding-top:2px;}
.editor input, .editor textarea {font-family:HAL Twined Mono, IBM Plex Mono, Consolas, Menlo, monospace; font-size:0.8em;}
.title+.editor input {margin-top:10px;}  /* as compensation for diminished line-height */
#displayArea {position:relative; margin:0 200px 0 0; border-radius:0 0 8px 8px;}
#messageArea {right:24px;}
#searchResults, #displayArea .breadCrumbs {margin:0 32px 12px 32px;}
.breadcrumbs {display:block;} /* only for popup window */

/*---- MORE LETTERING ----*/
.serif {font-family:IBM Plex Serif, Charter, Georgia, Lucida Fax, Lucida Bright, serif;}
.sans,
  .siteSubtitle,
  #searchResults,
  .breadCrumbs {font-family:IBM Plex Sans, Calibri, Lucida Grande, Lucida Sans, -apple-system, BlinkMacSystemFont, sans-serif;}
.siteTitle {font-family:IBM Plex Sans;}
.saco, .title, h1, h2, h3, h4, h5, h6 {
  font-family:IBM Plex Sans Condensed, IBMPlexSansCond, IBM Plex Sans, Calibri, Lucida Grande, Lucida Sans, -apple-system, BlinkMacSystemFont, sans-serif;
}
.tt, .viewer pre, .viewer code,
  .pretts0, .pretts1, .pretts2, .pretts3, .pretts4, .pretts5, .pretts6,
  .pre0, .pre1, .pre2, .pre3, .pre4, .pre5, .pre6,
  .hitt0, .hitt1, .hitt2, .hitt3, .hitt4, .hitt5, .hitt6,
  .pretts, .pre, .hitt {font-family:HAL Twined Mono, IBM Plex Mono, Consolas, Menlo, monospace;}
.stix {font-family:STIXTwoText, STIXTwoMath, Cambria, Charter, serif; font-size:1.1em; line-height:0.93em;}
.stixmath {font-family:STIXTwoMath, Cambria, Charter, serif; font-size:1.1em; line-height:0.93em;}
.sy {font-family:Symbola;}
.paint {font-family:AkayaKanadaka, cursive; font-size:1.35em; line-height:1em;}
.spaint {font-family:AkayaKanadaka, cursive; font-size:1.22em; line-height:1em;}
.npaint {font-family:NearAkayaKanadaka, cursive; font-size:1.35em; line-height:1em;}
.snpaint {font-family:NearAkayaKanadaka, cursive; font-size:1.22em; line-height:1em;}
.qpaint {font-family:QuasiAkayaKanadaka, cursive; font-size:1.35em; line-height:1em;}
.sqpaint {font-family:QuasiAkayaKanadaka, cursive; font-size:1.22em; line-height:1em;}
.pen {font-family:Montez, cursive; font-size:1.8em; line-height:1em;}
.spen {font-family:Montez, cursive; font-size:1.62em; line-height:1em;}
.hand {font-family:Caveat, cursive; font-size:1.8em; line-height:1em; position:relative; top:1px; left:-2px;}
.shand {font-family:Caveat, cursive; font-size:1.62em; line-height:1em; position:relative; top:1px; left:-2px;}
.mono   {font-family:HAL Twined Mono, IBM Plex Mono, monospace; font-size:12pt;     line-height:13.7pt !important;}
.mono0  {font-family:HAL Twined Mono, IBM Plex Mono, monospace; font-size:12pt;     line-height:16.4pt !important;}
.mono1  {font-family:DejaVuSansMono, monospace;                 font-size:11.95pt;  line-height:13.7pt !important;}
.mono2  {font-family:SourceCodePro, monospace;                  font-size:12pt;     line-height:16.4pt !important;}
.mono3  {font-family:SourceCodeProLight, monospace;             font-size:12pt;     line-height:16.4pt !important;}
.monoz  {font-family:HAL Twined Mono, IBM Plex Mono, monospace; font-size:10.8pt;   line-height:12.2pt !important;}
.mono0z {font-family:HAL Twined Mono, IBM Plex Mono, monospace; font-size:10.8pt;   line-height:14.7pt !important;}
.mono1z {font-family:DejaVuSansMono, monospace;                 font-size:10.755pt; line-height:12.2pt !important;}
.mono2z {font-family:SourceCodePro, monospace;                  font-size:10.8pt;   line-height:14.7pt !important;}
.mono3z {font-family:SourceCodeProLight, monospace;             font-size:10.8pt;   line-height:14.7pt !important;}

.n {font-weight: normal;}     /* 400  */
.t {font-weight: 500;}        /* Text */
.sc {font-size:0.75em; font-weight:500; letter-spacing:0.5px; text-transform:uppercase; line-height:1em;}
.ls { letter-spacing:0.5px;}  /* between 0.25pt (.widenq) and 0.5pt (.widenh) */
.listTitle {font-style:italic;}
.tagging, .tagged {font-family:IBM Plex Sans, Calibri, Lucida Grande, Lucida Sans, -apple-system, BlinkMacSystemFont, sans-serif;}
.tagging .listTitle, .tagged .listTitle {font-style:normal; font-variant:small-caps;}
#searchResults strong {font-weight:normal; font-style:italic;}

h1, .h1 {font-size:2.4em; line-height:1em; padding-bottom:8px;}
#mainMenu h1 {font-size:1.5em; padding-bottom:1px;}
h2, .h2 {font-size:1.8em; line-height:1em;}
#mainMenu h2 {font-size:1.35em;}
h3, .h3, .h3w {font-size:1.5em;}
h3 {font-style: italic;}
#mainMenu h3 {font-size:1.2em;}
h4, .h4 {font-size:1.2em;}
h5 {font-size:1.2em; font-style: italic;}
h6, .h6, #searchResults, .breadCrumbs {font-size:1.1em;}
.s, .z, .viewer pre,
  .pretts0, .pretts1, .pretts2, .pretts3, .pretts4, .pretts5, .pretts6,
  .pre0, .pre1, .pre2, .pre3, .pre4, .pre5, .pre6,
  .pretts, .pre {font-size:0.9em}

sup, sub {line-height:0.9em;}
.ref {position:relative; top:-0.5em; line-height:0.9em; font-size:0.8em;}

.nonviewer {line-height:1.25em;}

/*---- TEXT ALIGNMENTS ----*/
.tal {text-align:left;}
.tac {text-align:center;}
.tar {text-align:right;}

/*---- LIST STYLING ----*/
.od li {list-style-type:decimal;}
.ola li {list-style-type:lower-alpha;}
.oua li {list-style-type:upper-alpha;}
.olr li {list-style-type:lower-roman;}
.our li {list-style-type:upper-roman;}
.on li {list-style-type:none;}
ul {list-style:disc;}
ul ul {list-style:circle;}

/*---- POSITIONING AND DECORATION ----*/
* html .viewer pre {width:97%; padding:0.5em 0.5em 1.1em 0.5em;}
.pref,
  .pretts0, .pretts1, .pretts2, .pretts3, .pretts4, .pretts5, .pretts6,
  .pre0, .pre1, .pre2, .pre3, .pre4, .pre5, .pre6,
  .pretts, .pre {white-space: pre;}
.med, .z,
  .pretts0, .pretts1, .pretts2, .pretts3, .pretts4, .pretts5, .pretts6,
  .pre0, .pre1, .pre2, .pre3, .pre4, .pre5, .pre6, .pretts, .pre {line-height:1.3em;}
.tight {line-height:0.6em !important;}
.low {line-height:1.2em !important;}
.suf {line-height:1.48em !important;}
.ws, .viewer pre,
  .pretts0, .pretts1, .pretts2, .pretts3, .pretts4, .pretts5, .pretts6,
  .pre0, .pre1, .pre2, .pre3, .pre4, .pre5, .pre6,
  .pretts, .pre {margin:1em 0em; padding:0.5em;}
.hws,
  .hi0, .hi1, .hi2, .hi3, .hi4, .hi5, .hi6,
  .high0, .high1, .high2, .high3, .high4, .high5, .high6,
  .hitt0, .hitt1, .hitt2, .hitt3, .hitt4, .hitt5, .hitt6,
  .tape0, .tape1, .tape2, .tape3, .tape4, .tape5, .tape6,
  .hi, .high, .hitt, .tape {padding-left:0.25em; padding-right:0.25em;}
.widenq {letter-spacing:0.25pt;}
.widenh {letter-spacing:0.5pt;}
.widen1 {letter-spacing:1pt;}

.lift {display: block; margin-top:-1.4em;}
.up {position:relative; top:-0.4em;}
.hup {position:relative; top:-0.2em;}
.qup {position:relative; top:-0.1em;}
.up1px {position:relative; top:-1px;}
.dn1px {position:relative; top:1px;}
.qdn {position:relative; top:0.1em;}
.hdn {position:relative; top:0.2em;}
.dn {position:relative; top:0.4em;}
.back {position:relative; left:-0.6em;}
.zi10 {position:absolute; z-index:10;}

.viewer {line-height:1.5em;}
.viewer table {border-collapse:collapse; margin:0.8em 0em;}
.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption {padding:3px 4.5px;}
.viewer pre {line-height:1.5em; border-style:none solid solid none; border-width:0 1px 1px 0; border-radius:0.4em;}
.viewer code {line-height:1.5em; font-size:1.0em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;}
.tagging {margin-right:1em;}
.tagging a {padding:0 0.4em;}
.nonviewer .tagging ul, .nonviewer .tagged ul {margin-left:0.25em; padding-left:0;}
.nonviewer .listTitle {margin-left:0;}
.nonviewer .button {margin:0; padding:0.2em 0.4em;}
.popup li a {padding:0 0.4em 0.2em 0.4em;}
.popup .button {padding:0 0.4em 0 0.4em;}

pre.raw {margin:0; padding:0; border-radius:0;}
.r, pre.r, td.r,
  .pre0, .pre1, .pre2, .pre3, .pre4, .pre5, .pre6,
  .high0, .high1, .high2, .high3, .high4, .high5, .high6,
  .hitt0, .hitt1, .hitt2, .hitt3, .hitt4, .hitt5, .hitt6,
  .pre, .high, .hitt {border-radius:0.4em}
.rr, .r1em {border-radius:1em;}
.rr {padding-left:0.4em; padding-right:0.4em;}
pre.rr, td.rr {border-radius:1em;}

.block {display:block;}
.ib {display:inline-block;}
.li {display:list-item;}
.mlqem {margin-left:0.25em;}     .mrhem {margin-right:0.25em;}
.mlhem {margin-left:0.5em;}      .mrhem {margin-right:0.5em;}
.ml1em {margin-left:1em;}        .mr1em {margin-right:1em;}       .mn1em {margin-left:-1em;}     
.mlaem {margin-left:1.5em;}      .mraem {margin-right:1.5em;}     .mnaem {margin-left:-1.5em;}
.ml2em {margin-left:2em;}        .mr2em {margin-right:2em;}       .mn2em {margin-left:-2em;}
.mlbem {margin-left:2.5em;}      .mrbem {margin-right:2.5em;}     .mnbem {margin-left:-2.5em;}
.ml3em {margin-left:3em;}        .mr3em {margin-right:3em;}       .mn3em {margin-left:-3em;}
.plqem {padding-left:0.25em;}    .prqem {padding-right:0.25em;}
.plhem {padding-left:0.5em;}     .prhem {padding-right:0.5em;}
.pl1em {padding-left:1em;}       .pr1em {padding-right:1em;}
.plaem {padding-left:1.5em;}     .praem {padding-right:1.5em;}
.pl2em {padding-left:2em;}       .pr2em {padding-right:2em;}
.plbem {padding-left:2.5em;}     .prbem {padding-right:2.5em;}
.pl3em {padding-left:3em;}       .pr3em {padding-right:3em;}

.li, dd, .viewer blockquote {margin-left:2em;}
.lf {float:left; margin-right:0.5em;}
.rf {float:right; margin-left:0.5em;}
.left0, .left1, .left2, .left3, .left4, .left5, .left6, .left {float:left; padding-right:0.3em; margin-right:0.5em;}
.oh {overflow:hidden;}
.clear {clear:both;}

.w {display:inline-block; line-height:0.8em; width:0.6em; text-align:center;}
.ww {display:inline-block; width:1.2em; text-align:center;}
.www {display:inline-block; width:1.8em; text-align:center;}
.h3w {position:relative; top:0.1em; left:-0.1em; text-align:center;}
.w15pct {width:15%;}
.w20pct {width:20%;}
.w25pct {width:25%;}
.w30pct {width:30%;}
.w35pct {width:35%;}
.w40pct {width:40%;}
.w45pct {width:45%;}
.w50pct {width:50%;}
.w55pct {width:55%;}
.w60pct {width:60%;}
.w65pct {width:65%;}
.w70pct {width:70%;}
.w75pct {width:75%;}
.w80pct {width:80%;}
.w85pct {width:85%;}
.w90pct {width:90%;}
.w95pct {width:95%;}
.wfull {width:100%;}
.h10em {height:10em;}
.h15em {height:15em;}
.h20em {height:20em;}
.h25em {height:25em;}
.h30em {height:30em;}
.h35em {height:35em;}
.h40em {height:40em;}
.scroll, .viewer pre, .pre0, .pre1, .pre2, .pre3, .pre4, .pre5, .pre6, .pre {overflow:auto;}

/*---- TABLE LAYOUT ----*/
th, td {vertical-align:top;}
.middle th, .middle td {vertical-align:middle;}
table.raw, .raw table, .raw tr, .raw th, .raw td {margin:0; padding:0; border-style:none;}
table.plain, .plain table, .plain tr, .plain th, .plain td {margin:0; padding:0 0.5em 0 0; border-style:none;}
table.bare, .bare table, .bare tr, .bare th, .bare td {margin:0; border-style:none;}
table.open, .open table, .open tr, .open td {border-style:none;}
.open td:nth-child(n+2) {border-left:1px solid [[ColorPalette::SecondaryMid]];}
table.open, .open table {border-bottom:2px solid [[ColorPalette::SecondaryMid]];}
table.default, .default table, .default tr, .default th, .default td, .default thead td {margin:0.8em 1.0em; padding:3px 4.5px; border-width:1px; border-style:solid;}
table.full, .full table {width:100%;}
table.capt caption, .capt table caption {caption-side:top;}
table.capl caption, .capl table caption {text-align:left;}
table .sans, table .saco, table .tt {line-height:0.95em;}

/*---- VERTICAL RULERS ----*/
.vrl, td.vrl, pre.vrl {border-left:1px dashed [[ColorPalette::TertiaryDark]];}
.vrr, td.vrr, pre.vrr {border-right:1px dashed [[ColorPalette::TertiaryDark]];}
.vrl1, td.vrl1, pre.vrl1 {border-left:1px solid [[ColorPalette::PrimarySoft]];}
.vrr1, td.vrr1, pre.vrr1 {border-right:1px solid [[ColorPalette::PrimarySoft]];}
/*}}}*/
/***
!!Colors/%============================================================%/
***/
/*{{{*/
body {background-color:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; background-image:url(core/4x1-CCCCCC-D4CCB2.png); background-repeat:repeat;}
a {color:[[ColorPalette::PrimaryBright]];}
a:hover {background-color:[[ColorPalette::PrimarySoft]]; color:[[ColorPalette::Background]];}
a:active {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a[name], a[name]:hover {color:inherit; background-color:inherit;}
a.tiddlyLink.tiddlyLinkExisting {text-decoration:underline; text-decoration-thickness:6px; text-underline-offset:-2px; text-decoration-color:[[ColorPalette::PrimaryWhitened]]; text-decoration-skip-ink:none;}
a.tiddlyLink.tiddlyLinkExisting:hover {text-decoration:none;}
.tagging a.tiddlyLink.tiddlyLinkExisting {text-decoration:none;}

#wwCurtain {background-color:transparent;}
#displayArea {background-color:[[ColorPalette::Background]];}
#wwRight {color:[[ColorPalette::SecondaryPale]]}
#wwLeft a, #wwRight a {color:[[ColorPalette::SecondaryPale]];}

.header {background-color:[[ColorPalette::Background]];}
.headerForeground {color:[[ColorPalette::Foreground]];}
.headerForeground a {font-weight:bold; color:[[ColorPalette::PrimaryMid]];}
.header a:hover {background:[[ColorPalette::PrimarySoft]]; color:[[ColorPalette::Background]];}
#mainMenu .siteLogo:hover, #anotherRoad:hover {background:transparent;}
.tiddler {border-color:[[ColorPalette::SecondaryLight]]; border-style:dotted; border-width:8px 0px 0px 0px;}
.title {color:[[ColorPalette::PrimaryDark]]; text-shadow:0.5px 0.5px 2.5px gray;}
.listTitle {color:[[ColorPalette::Foreground]];}
.toolbar a {color:[[ColorPalette::TertiaryPale]];}
.toolbar .markedCommand {border-bottom:3px dotted [[ColorPalette::SecondaryPale]];}
.selected .toolbar .markedCommand {border-bottom:3px dotted [[ColorPalette::SecondarySoft]];}

.tagging, .tagged {background:[[ColorPalette::TertiaryPale]]; border:0 solid [[ColorPalette::TertiaryPale]]; border-radius:1em; box-shadow:2px 2px 5px gray;}
.tagging .listTitle, .tagged .listTitle, .tagging a, .tagged a {color:[[ColorPalette::SecondaryDark]];}
.selected .tagging, .selected .tagged {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:0 solid [[ColorPalette::Foreground]];}
.selected .tagging a, .selected .tagged a {color:[[ColorPalette::Background]];}
.selected .tagging a:hover, .selected .tagged a:hover {background:[[ColorPalette::PrimarySoft]];}
.selected .tagging .listTitle, .selected .tagged .listTitle {color:[[ColorPalette::Background]];}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::Foreground]]; background:transparant; border:none;}
h4,h5,h6 {margin-top:1em; margin-bottom:0.2em;}
h1 {border-bottom:2px solid [[ColorPalette::SecondaryMid]];}

.tabset {padding-left:0;}
.tab {
  margin-left:0; margin-right:0.25em; padding:2px 4px 2px 4px;
  -moz-border-radius-topleft:0.5em; -moz-border-radius-topright:0.5em;
  -webkit-border-top-left-radius:0.5em; -webkit-border-top-right-radius:0.5em;
}

.tabSelected {border-right:1px solid [[ColorPalette::TertiaryDark]]; background-color:[[ColorPalette::TertiaryWhitened]]; color:[[ColorPalette::TertiaryDark]]; font-weight:bold;}
.tabUnselected {padding-top:1px; padding-bottom:0;}
.tabContents {background-color:[[ColorPalette::TertiaryWhitened]]; color:[[ColorPalette::TertiaryDark]]; border-right:1px solid [[ColorPalette::TertiaryDark]]; border-bottom:1px solid [[ColorPalette::TertiaryDark]];}
#sidebar .tabSelected {background-color:[[ColorPalette::SecondaryPale]]; border-right:1px solid [[ColorPalette::SecondaryDark]];}
#sidebar .tabUnselected {background-color:[[ColorPalette::SecondaryMid]]; color:[[ColorPalette::SecondaryWhitened]];}
#sidebar .tabSelected:hover, #sidebar .tabUnselected:hover {background-color:[[ColorPalette::PrimarySoft]]; color:[[ColorPalette::Background]];}
#sidebarTabs .tabContents {background-color:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::SecondaryDark]]; border-right:1px solid [[ColorPalette::SecondaryDark]]; border-bottom:1px solid [[ColorPalette::SecondaryDark]];}

#mainMenu a, #mainMenu .button {color:[[ColorPalette::SecondaryDark]]; text-decoration:none;}
#mainMenu .h3 a {color:[[ColorPalette::SecondaryPale]];}
#mainMenu h2 a {color:[[ColorPalette::Foreground]];}
#mainMenu a:hover {background:[[ColorPalette::PrimarySoft]]; color:[[ColorPalette::Background]];}
#mainMenu .button {border-color:[[ColorPalette::SecondaryLight]];}
#mainMenu .button:hover, #mainMenu .button:hover a {color:[[ColorPalette::SecondaryDark]]; background:[[ColorPalette::SecondaryPale]]; border-color:[[ColorPalette::SecondaryLight]];}
#sidebar a, #sidebar .button {color:[[ColorPalette::SecondaryDark]]; text-decoration:none;}
#sidebar a:hover, #sidebar .tabyUnselected {color:[[ColorPalette::Background]];}
#sidebar .button {border-color:transparent;}
#sidebar .button:hover {color:[[ColorPalette::TertiaryDark]];}
#sidebarOptions .sliderPanel {margin-bottom:0.5em; margin-left:0.6em; border-radius:0.5em;}
#sidebarOptions div[tiddler="More sidebar options"] {background-color:[[ColorPalette::SecondaryPale]]; padding-top:0; padding-left:0;}
#sidebarOptions div[tiddler="More sidebar options"] a {border-color:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::SecondaryDark]];}
#sidebarOptions div[tiddler="More sidebar options"] a:hover {color:[[ColorPalette::Background]]; background-color:[[ColorPalette::PrimarySoft]];}
#sidebarOptions div[tiddler="More sidebar options"] a:active {color:[[ColorPalette::Background]]; background-color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions div[tiddler="More sidebar options"] .button {color:[[ColorPalette::SecondaryDark]]; border-color:[[ColorPalette::SecondaryPale]];}
#sidebarOptions div[tiddler="More sidebar options"] .button:hover {color:[[ColorPalette::TertiaryDark]]; background-color:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
#sidebarOptions div[tiddler="More sidebar options"] .button:active {ColorPalette::TertiaryDark]]; background-color:[[ColorPalette::SecondaryMid]]; border-color:[[ColorPalette::SecondaryDark]];}
.toggleSidebar .button {text-shadow:0;}
.popup a {text-decoration:none !important;}
.viewer .button {border:0; border-radius:0.4em; box-shadow:0.5px 0.5px 2.5px gray;}
.viewer .button a {color:[[ColorPalette::PrimaryDark]];}
.viewer .button a:hover {background-color:[[ColorPalette::SecondaryLight]];}
.tagged .button {border:0; border-radius:0.4em;}
.tagging a:hover {border-radius:0.4em;}
.nonviewer .button {border:none; box-shadow:none;}
.empty .button, .empty .button:hover {background-color:[[ColorPalette::Background]]; color:transparent;}
.breadCrumbs {color:[[ColorPalette::PrimarySoft]];}
.breadCrumbs a {color:[[ColorPalette::SecondaryDark]]; text-decoration:none !important;}
.breadCrumbs a:hover {color:[[ColorPalette::Background]];}
#messageArea {background-color:[[ColorPalette::PrimaryPale]];}

.viewer table, .default table, table.twtable {border-color:[[ColorPalette::SecondaryMid]];}
.default table, table.default {border:2px solid [[ColorPalette::SecondaryMid]];}
.viewer th, .viewer thead td, .default th, .default thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border-color:[[ColorPalette::SecondaryMid]] [[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Background]];}
.viewer thead td, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border-color:[[ColorPalette::SecondaryMid]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .default td, .default tr, .twtable td, .twtable tr {border-color:[[ColorPalette::SecondaryMid]];}
tfoot {border-top:2px solid [[ColorPalette::SecondaryMid]];}
.viewer pre {border-right:1px solid [[ColorPalette::TertiaryPale]]; border-bottom:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::SecondaryWhitened]];}
pre.raw {border-style:none;}
.viewer code {color:[[ColorPalette::Foreground]];}

.tape0 {border-top:1px solid [[ColorPalette::TertiaryPale]]; border-bottom:1px solid [[ColorPalette::TertiaryPale]];}
.tape1 {border-top:1px solid [[ColorPalette::PrimaryLight]]; border-bottom:1px solid [[ColorPalette::PrimaryLight]];}
.tape2 {border-top:1px solid [[ColorPalette::SecondaryLight]]; border-bottom:1px solid [[ColorPalette::SecondaryLight]];}
.tape3 {border-top:1px solid [[ColorPalette::TertiaryLight]]; border-bottom:1px solid [[ColorPalette::TertiaryLight]];}
.tape4 {border-top:1px solid [[ColorPalette::PrimaryFair]]; border-bottom:1px solid [[ColorPalette::PrimaryFair]];}
.tape5 {border-top:1px solid [[ColorPalette::SecondaryPale]]; border-bottom:1px solid [[ColorPalette::SecondaryPale]];}
.tape6, .tape {border-top:1px solid [[ColorPalette::TertiaryPale]]; border-bottom:1px solid [[ColorPalette::TertiaryPale]];}

.bred {background-color:red;}
.bora {background-color:darkorange;}
.byel {background-color:#ffee00;}
.bgre {background-color:#009900;}
.bkya {background-color:#008b8b;}
.bcya {background-color:#00aaaa;}
.bblu {background-color:blue;}
.bpur {background-color:#bb00bb;}
.bbla {background-color:black;}
.bgra {background-color:gray;}

.b0, pre.b0, .pre0 pre, .pretts0, .pre0, .hi0, .high0, .hitt0, .tape0, .bwhi {background-color:white;}
.b1, pre.b1, .pre1 pre, .pretts1, .pre1, .hi1, .high1, .hitt1, .tape1, .b1f {background-color:[[ColorPalette::PrimaryFair]];}
.b2, pre.b2, .pre2 pre, .pretts2, .pre2, .hi2, .high2, .hitt2, .tape2, .b2p {background-color:[[ColorPalette::SecondaryPale]];}
.b3, pre.b3, .pre3 pre, .pretts3, .pre3, .hi3, .high3, .hitt3, .tape3, .b3p {background-color:[[ColorPalette::TertiaryPale]];}
.b4, pre.b4, .pre4 pre, .pretts4, .pre4, .hi4, .high4, .hitt4, .tape4, .b1w {background-color:[[ColorPalette::PrimaryWhitened]];}
.b5, pre.b5, .pre5 pre, .pretts5, .pre5, .hi5, .high5, .hitt5, .tape5, .b2w, .pretts, .pre, .hi, .high, .hitt {background-color:[[ColorPalette::SecondaryWhitened]];}
.b6, pre.b6, .pre6 pre, .pretts6, .pre6, .hi6, .high6, .hitt6, .tape6, .b3w, .tape {background-color:[[ColorPalette::TertiaryWhitened]];}

.b1p {background-color:[[ColorPalette::PrimaryPale]];}
.b1l {background-color:[[ColorPalette::PrimaryLight]];}
.b1s {background-color:[[ColorPalette::PrimarySoft]];}
.b1m {background-color:[[ColorPalette::PrimaryMid]];}
.b1d {background-color:[[ColorPalette::PrimaryDark]];}

.b2l {background-color:[[ColorPalette::SecondaryLight]];}
.b2s {background-color:[[ColorPalette::SecondarySoft]];}
.b2m {background-color:[[ColorPalette::SecondaryMid]];}
.b2d {background-color:[[ColorPalette::SecondaryDark]];}

.b3l {background-color:[[ColorPalette::TertiaryLight]];}
.b3s {background-color:[[ColorPalette::TertiarySoft]];}
.b3m {background-color:[[ColorPalette::TertiaryMid]];}
.b3d {background-color:[[ColorPalette::TertiaryDark]];}

.be {background-color:[[ColorPalette::Error]];}

.pred {background-color:#ffe5e5;}
.pora {background-color:#fcf2ea;}
.pyel {background-color:#ffffeb;}
.pbei {background-color:#f3f3f1;}
.pgre {background-color:#e5ffe0;}
.poli {background-color:#e3eee2;}
.pblu {background-color:#e3e7ff;}
.ppur {background-color:#efe3ff;}

.fwhi {color:white;}
.fred {color:red;}
.fora {color:darkorange;}
.fyel {color:#ffee00;}
.fgre {color:#009900;}
.fkya {color:#008b8b;}
.fcya {color:#00aaaa;}
.fblu {color:blue;}
.fpur {color:#bb00bb;}
.fbla {color:black;}
.fgra {color:gray;}

.f0, .f6, .f3s {color:[[ColorPalette::TertiarySoft]];}
.f1, .f1s {color:[[ColorPalette::PrimarySoft]];}
.f2, .f2m {color:[[ColorPalette::SecondaryMid]];}
.f3, .f3m {color:[[ColorPalette::TertiaryMid]];}
.f4, .f1l {color:[[ColorPalette::PrimaryLight]];}
.f5, .f2s {color:[[ColorPalette::SecondarySoft]];}

.f1w {color:[[ColorPalette::PrimaryWhitened]];}
.f1p {color:[[ColorPalette::PrimaryPale]];}
.f1f {color:[[ColorPalette::PrimaryFair]];}
.f1m {color:[[ColorPalette::PrimaryMid]];}
.f1d {color:[[ColorPalette::PrimaryDark]];}

.f2w {color:[[ColorPalette::SecondaryWhitened]];}
.f2p {color:[[ColorPalette::SecondaryPale]];}
.f2l {color:[[ColorPalette::SecondaryLight]];}
.f2d {color:[[ColorPalette::SecondaryDark]];}

.f3w {color:[[ColorPalette::TertiaryWhitened]];}
.f3p {color:[[ColorPalette::TertiaryPale]];}
.f3l {color:[[ColorPalette::TertiaryLight]];}
.f3d {color:[[ColorPalette::TertiaryDark]];}

.fe {color:[[ColorPalette::Error]];}

.u0, td.u0, pre.u0 {border-top:1px solid white; border-left:1px solid white;}
.d0, td.d0, pre.d0 {border-right:1px solid white; border-bottom:1px solid white;}

.u1, td.u1, pre.u1 {border-top:1px solid [[ColorPalette::PrimaryLight]]; border-left:1px solid [[ColorPalette::PrimaryLight]];}
.d1, td.d1, pre.d1, .pre1 pre, .pre1, .high1, .hitt1 {border-right:1px solid [[ColorPalette::PrimaryLight]]; border-bottom:1px solid [[ColorPalette::PrimaryLight]];}
.u2, td.u2, pre.u2 {border-top:1px solid [[ColorPalette::SecondaryLight]]; border-left:1px solid [[ColorPalette::SecondaryLight]];}
.d2, td.d2, pre.d2 {border-right:1px solid [[ColorPalette::SecondaryLight]]; border-bottom:1px solid [[ColorPalette::SecondaryLight]];}
.u3, td.u3, pre.u3 {border-top:1px solid [[ColorPalette::TertiaryLight]]; border-left:1px solid [[ColorPalette::TertiaryLight]];}
.d3, td.d3, pre.d3, .pre0 pre, .pre0, .pre2, .pre3, .high0, .high2, .high3, .hitt0, .hitt2, .hitt3 {border-right:1px solid [[ColorPalette::TertiaryLight]]; border-bottom:1px solid [[ColorPalette::TertiaryLight]];}
.u4, td.u4, pre.u4 {border-top:1px solid [[ColorPalette::PrimaryFair]]; border-left:1px solid [[ColorPalette::PrimaryFair]];}
.d4, td.d4, pre.d4, .pre4 pre, .pre4, .high4, .hitt4 {border-right:1px solid [[ColorPalette::PrimaryFair]]; border-bottom:1px solid [[ColorPalette::PrimaryFair]];}
.u5, td.u5, pre.u5 {border-top:1px solid [[ColorPalette::SecondaryPale]]; border-left:1px solid [[ColorPalette::SecondaryPale]];}
.d5, td.d5, pre.d5 {border-right:1px solid [[ColorPalette::SecondaryPale]]; border-bottom:1px solid [[ColorPalette::SecondaryPale]];}
.u6, td.u6, pre.u6, .pre0 pre, .pre0 {border-top:1px solid [[ColorPalette::TertiaryPale]]; border-left:1px solid [[ColorPalette::TertiaryPale]];}
.d6, td.d6, pre.d6, .pre5 pre, .pre6 pre, .pre5, .pre6, .high5, .high6, .hitt5, .hitt6, .pre, .high, .hitt {border-right:1px solid [[ColorPalette::TertiaryPale]]; border-bottom:1px solid [[ColorPalette::TertiaryPale]];}

.u1p, td.u1p, pre.u1p {border-top:1px solid [[ColorPalette::PrimaryPale]]; border-left:1px solid [[ColorPalette::PrimaryPale]];}
.d1p, td.d1p, pre.d1p {border-right:1px solid [[ColorPalette::PrimaryPale]]; border-bottom:1px solid [[ColorPalette::PrimaryPale]];}
.u1w, td.u1w, pre.u1w {border-top:1px solid [[ColorPalette::PrimaryWhitened]]; border-left:1px solid [[ColorPalette::PrimaryWhitened]];}
.d1w, td.d1w, pre.d1w {border-right:1px solid [[ColorPalette::PrimaryWhitened]]; border-bottom:1px solid [[ColorPalette::PrimaryWhitened]];}
.u1s, td.u1s, pre.u1s {border-top:1px solid [[ColorPalette::PrimarySoft]]; border-left:1px solid [[ColorPalette::PrimarySoft]];}
.d1s, td.d1s, pre.d1s {border-right:1px solid [[ColorPalette::PrimarySoft]]; border-bottom:1px solid [[ColorPalette::PrimarySoft]];}
.u1m, td.u1m, pre.u1m {border-top:1px solid [[ColorPalette::PrimaryMid]]; border-left:1px solid [[ColorPalette::PrimaryMid]];}
.d1m, td.d1m, pre.d1m {border-right:1px solid [[ColorPalette::PrimaryMid]]; border-bottom:1px solid [[ColorPalette::PrimaryMid]];}
.u1d, td.u1d, pre.u1d {border-top:1px solid [[ColorPalette::PrimaryDark]]; border-left:1px solid [[ColorPalette::PrimaryDark]];}
.d1d, td.d1d, pre.d1d {border-right:1px solid [[ColorPalette::PrimaryDark]]; border-bottom:1px solid [[ColorPalette::PrimaryDark]];}

.u2w, td.u2w, pre.u2w {border-top:1px solid [[ColorPalette::SecondaryWhitened]]; border-left:1px solid [[ColorPalette::SecondaryWhitened]];}
.d2w, td.d2w, pre.d2w {border-right:1px solid [[ColorPalette::SecondaryWhitened]]; border-bottom:1px solid [[ColorPalette::SecondaryWhitened]];}
.u2p, td.u2p, pre.u2p {border-top:1px solid [[ColorPalette::SecondaryPale]]; border-left:1px solid [[ColorPalette::SecondaryPale]];}
.d2p, td.d2p, pre.d2p {border-right:1px solid [[ColorPalette::SecondaryPale]]; border-bottom:1px solid [[ColorPalette::SecondaryPale]];}
.u2s, td.u2s, pre.u2s {border-top:1px solid [[ColorPalette::SecondarySoft]]; border-left:1px solid [[ColorPalette::SecondarySoft]];}
.d2s, td.d2s, pre.d2s {border-right:1px solid [[ColorPalette::SecondarySoft]]; border-bottom:1px solid [[ColorPalette::SecondarySoft]];}
.u2m, td.u2m, pre.u2m {border-top:1px solid [[ColorPalette::SecondaryMid]]; border-left:1px solid [[ColorPalette::SecondaryMid]];}
.d2m, td.d2m, pre.d2m {border-right:1px solid [[ColorPalette::SecondaryMid]]; border-bottom:1px solid [[ColorPalette::SecondaryMid]];}
.u2d, td.u2d, pre.u2d {border-top:1px solid [[ColorPalette::SecondaryDark]]; border-left:1px solid [[ColorPalette::SecondaryDark]];}
.d2d, td.d2d, pre.d2d {border-right:1px solid [[ColorPalette::SecondaryDark]]; border-bottom:1px solid [[ColorPalette::SecondaryDark]];}

.u3w, td.u3w, pre.u3w {border-top:1px solid [[ColorPalette::TertiaryWhitened]]; border-left:1px solid [[ColorPalette::TertiaryWhitened]];}
.d3w, td.d3w, pre.d3w {border-right:1px solid [[ColorPalette::TertiaryWhitened]]; border-bottom:1px solid [[ColorPalette::TertiaryWhitened]];}
.u3s, td.u3s, pre.u3s {border-top:1px solid [[ColorPalette::TertiarySoft]]; border-left:1px solid [[ColorPalette::TertiarySoft]];}
.d3s, td.d3s, pre.d3s {border-right:1px solid [[ColorPalette::TertiarySoft]]; border-bottom:1px solid [[ColorPalette::TertiarySoft]];}
.u3m, td.u3m, pre.u3m {border-top:1px solid [[ColorPalette::TertiaryMid]]; border-left:1px solid [[ColorPalette::TertiaryMid]];}
.d3m, td.d3m, pre.d3m {border-right:1px solid [[ColorPalette::TertiaryMid]]; border-bottom:1px solid [[ColorPalette::TertiaryMid]];}
.u3d, td.u3d, pre.u3d {border-top:1px solid [[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryDark]];}
.d3d, td.d3d, pre.d3d {border-right:1px solid [[ColorPalette::TertiaryDark]]; border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.left0, .left6 {border-right:1px solid [[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiarySoft]];}
.left1 {border-right:1px solid [[ColorPalette::PrimaryLight]]; color:[[ColorPalette::PrimarySoft]];}
.left2 {border-right:1px solid [[ColorPalette::SecondaryLight]]; color:[[ColorPalette::SecondaryMid]];}
.left3 {border-right:1px solid [[ColorPalette::TertiaryLight]]; color:[[ColorPalette::TertiaryMid]];}
.left4 {border-right:1px solid [[ColorPalette::PrimaryFair]]; color:[[ColorPalette::PrimaryLight]];}
.left5, .left {border-right:1px solid [[ColorPalette::SecondaryPale]]; color:[[ColorPalette::SecondarySoft]];}

.kbd {border:1px solid [[ColorPalette::TertiaryLight]]; border-radius:0.4em; padding-left:0.25em; padding-right:0.25em;}
.II {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
.III {border-bottom:3px solid [[ColorPalette::TertiaryLight]];}
.IV {border-bottom:4px solid [[ColorPalette::TertiaryLight]];}

/*---- SHADOW ----*/
.shaded {text-shadow:0.5px 0.5px 1.5px gray;}                                            /* for text  */
.yellow {text-shadow:0px 0px 5px yellow;}                                                /* for text  */
.sh, pre.sh, .toggleSidebar .button, .view .button {box-shadow:0.5px 0.5px 2.5px gray;}  /* for block */
.bare .button {box-shadow:none;}                                                         /* for block */

/*---- SPECIAL TABLE COLORS AND WEIGHTS ----*/
.odd tr.oddRow {background-color:[[ColorPalette::SecondaryWhitened]];}
.even tr.evenRow {background-color:[[ColorPalette::SecondaryWhitened]];}
.col1 td:nth-child(1) {background-color:[[ColorPalette::SecondaryPale]];}
.col2 td:nth-child(2) {background-color:[[ColorPalette::SecondaryPale]];}
.thick1 td:nth-child(1) {border-right:2px solid [[ColorPalette::SecondaryMid]];}
.thick2 td:nth-child(2) {border-right:2px solid [[ColorPalette::SecondaryMid]];}
.bold1 td:nth-child(1) {font-weight:bold;}
.bold2 td:nth-child(2) {font-weight:bold;}
/*}}}*/
/*{{{*/
@media print {
.header, #mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 0em 0em 0em 0em;}
* html .viewer pre {font-size:0.8em; line-height:1.0em; padding-bottom:1.5em;}
.viewer pre {font-size:0.8em; line-height:1.0em;}
.viewer code {font-size:1em; color:[[ColorPalette::Foreground]]}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
The ''{{{ln}}}'' command offers four forms for making symbolic links (aka symlinks) to other file objects (files, directories, symlinks). Although possible, it doesn't make sense to create a symlink to itself. 
<html><pre>
<b>ln -s</b><i>[</i><b>T</b><i>] [«options»] [«dir»]«name» [«destdir»]«linkname»</i>  <font color="green">#1: creates <i>[«destdir»]«linkname»</i> as symlink to <i>[«dir»]«name»</i></font>
<b>ln -s </b><i>[«options»] [«dir»]«name»</i>                           <font color="green">#2: creates <b>./</b><i>«name»</i> as symlink to <i>[«dir»]«name»</i></font>
<b>ln -s </b><i>[«options»] [«dir»]«name» ... «destdir»</i>             <font color="green">#3: creates <i>«destdir»«name»</i> ... as symlink(s) to <i>[«dir»]«name» ...</i></font>
<b>ln -st </b><i>«destdir» [«options»] [«dir»]«name» ...</i>            <font color="green">#4: creates <i>«destdir»«name»</i> ... as symlink(s) to <i>[«dir»]«name» ...</i></font>
</pre></html>/%
%/In all these forms:
*a relative path in //«dir»// will __not__ be resolved to an absolute path (or otherwise reinterpreted) in order to serve correctly as the new symlink's target
*//«name»// may be the name of a file, a directory or a symlink (preferably an existing one)
*//«destdir»// (destination directory) must be an existing directory
*//«linkname»// may not be the name of an existing directory/%
%/
The ''{{{-T}}}'' (or ''{{{--no-target-directory}}}'') option in form #1 preserves it from being interpreted as form #3. Some other usefull options:
*''{{{-f}}}'' (or ''{{{--force}}}'') -- remove existing destination files
*''{{{-i}}}'' (or ''{{{--interactive}}}'') -- prompt whether to remove destinations
*''{{{-n}}}'' (or ''{{{--no-dereference}}}'') -- treat destination that is a symlink to a directory as if it were a normal file/%
%/
Relative paths in symlinks will be interpreted as relative to the location of the link itself.

See the man pages for more. And see [[Het bestandssysteem van Linux]] for some background.
!!!Languages
* [["Comparison of programming languages"|https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(syntax)]]
* [["C syntax"|https://en.wikipedia.org/wiki/C_syntax]]
* [["C++"|https://en.wikipedia.org/wiki/C%2B%2B#Language]]
* C#: [["C Sharp"|https://en.wikipedia.org/wiki/Rust_(programming_language)#Syntax_and_features]]
* [["Forth"|https://en.wikipedia.org/wiki/Forth_(programming_language)]] {{ref{[[[1]|##01]]}}}
* [["Go"|https://en.wikipedia.org/wiki/Go_(programming_language)#Design]]
* [["Java syntax"|https://en.wikipedia.org/wiki/Java_syntax]]
* [["JavaScript syntax"|https://en.wikipedia.org/wiki/JavaScript_syntax]]
* [["Kotlin"|https://en.wikipedia.org/wiki/Kotlin_(programming_language)]]
* Lisp: [["S-expression"|https://en.wikipedia.org/wiki/S-expression]]
* [["Lua"|https://en.wikipedia.org/wiki/Lua_(programming_language)#Syntax]]
* [["Objective-C"|https://en.wikipedia.org/wiki/Objective-C]]
* [["Perl language structure"|https://en.wikipedia.org/wiki/Perl_language_structure]]
* [["Python syntax and semantics"|https://en.wikipedia.org/wiki/Python_syntax_and_semantics]]
* [["Rexx"|https://en.wikipedia.org/wiki/Rexx]]
* [["Ruby syntax"|https://en.wikipedia.org/wiki/Ruby_syntax]]
* [["Rust"|https://en.wikipedia.org/wiki/Rust_(programming_language)#Syntax_and_features]]
* [["Scala"|https://en.wikipedia.org/wiki/Scala_(programming_language)]]
* [["Scheme"|https://en.wikipedia.org/wiki/Scheme_(programming_language)]]/%

%/
!!!Special techniques
* [["Homoiconicity"|https://en.wikipedia.org/wiki/Homoiconicity]] -- Lisp and Rebol examples<br>&nbsp;/%

%/
----
{{lf{<html><a name="01">[1]</a></html>}}} {{ib w95pct{+++(~SyntaxAndSemanticsOfProgrammingLanguages)[Here's an elaboration that might clarify the <html><span class="sans t">FLOOR5</span></html> example &darr;|show][Here's an elaboration that might clarify the <html><span class="sans t">FLOOR5</span></html> example &uarr;|hide]
<br>The functional equivalent of the subroutine {{pref hitt t z{'': FLOOR5 ( //n// """--""" //n//' ) DUP 6 < IF DROP 5 ELSE 1 - THEN ;''}}} (where the block comment between parentheses documents what the stack looks like before and after the execution) could be coded in Lua as:
{{pre{
function ''floor5'' (value)
  if value < 6 then return 5 else return value - 1 end
end
}}}/%

%/That doesn't reveal the underlying Forth mechanisms. More insight in how Forth operates under the hood is given by the simulation model below, also written in Lua:
{{block pre{{{_{
//"""-----""" Requisites in this simulation model """-----"""//
STACK    = {}
OPERANDS = {}

function push (value)                 """--"""
  table.insert(STACK, value)          """--""" //v//
end

function dup ()                       """--""" //v//
  push(STACK[#STACK])                 """--""" //v v//
end

function pop ()                       """--""" //v//
  return table.remove(STACK)          """--"""
end

function drop ()                      """--""" //v//
  pop()                               """--"""
end

//"""-----""" Simulation of the// ''FLOOR5'' //subroutine """-----"""//
function ''floor5'' ()                    """--""" //n//
  dup()                               """--""" //n n//
  push(6)                             """--""" //n n// 6
  OPERANDS[2] = pop()                 """--""" //n n//
  OPERANDS[1] = pop()                 """--""" //n//
  push(OPERANDS[1] < OPERANDS[2])     """--""" //n f//
  if pop() then                       """--""" //n//
    drop()                            """--"""
    push(5)                           """--""" 5
  else                                """--""" //n//
    push(1)                           """--""" //n// 1
    OPERANDS[2] = pop()               """--""" //n//
    OPERANDS[1] = pop()               """--"""
    push(OPERANDS[1] - OPERANDS[2])   """--""" //n//'
  end
end

//"""-----""" Simulation of the subroutine calls// ''13 FLOOR5'' //and// ''4 FLOOR5'' """-----"""
push(13)                              """--""" 13
''floor5''()                              """--""" 12
print(STACK[#STACK])

push(4)                               """--""" 12 4
''floor5''()                              """--""" 12 5
print(STACK[#STACK])
}}}}}}The line comments at the right side show the contents of the upper part of the stack.
/%

%/
In the same way, //what// {{pref hitt t z{'': FLOOR5 ( //n// """--""" //n//' ) 1- 5 MAX ;''}}} does could be represented by this Lua code:
{{block pre{{{_{
function ''floor5'' (value)
  return math.max(value - 1, 5)
end
}}}}}}/%

%/and //how// it does that by:
{{block pre{{{_{
//"""-----""" Requisites in this simulation model """-----"""//
STACK    = {}
OPERANDS = {}

function push (value)                         """--"""
  table.insert(STACK, value)                  """--""" //v//
end

function pop ()                               """--""" //v//
  return table.remove(STACK)                  """--"""
end

function dec ()                               """--""" //n//
  OPERANDS[1] = pop()                         """--"""
  push(OPERANDS[1] - 1)                       """--""" //n//'
end

//"""-----""" Simulation of the alternative// ''FLOOR5'' //subroutine """-----"""//
function ''floor5'' ()                            """--""" //n//
  dec()                                       """--""" //n//'
  push(5)                                     """--""" //n//' 5
  OPERANDS[2] = pop()                         """--""" //n//'
  OPERANDS[1] = pop()                         """--"""
  push(math.max(OPERANDS[1], OPERANDS[2]))    """--""" //n//"""''"""
end

//"""-----""" Simulation of the subroutine calls// ''13 FLOOR5'' //and// ''4 FLOOR5'' """-----"""
push(13)                                      """--""" 13
''floor5''()                                      """--""" 12
print(STACK[#STACK])

push(4)                                       """--""" 12 4
''floor5''()                                      """--""" 12 5
print(STACK[#STACK])
}}}}}}
===}}}
De [[YAML]]-boodschappenlijstjes in [[Tom's Obvious Minimal Language|https://toml.io/en/]] (''TOML''):
{{{
naam = "mw. Donkersloot"
boodschappen = [
  "2 kilo peren",
  "1 perforator",
  "1 piano",
  "half pond nougat",
  "3 pakken Brinta",
]
opmerking = "tussen de middag bezorgen"
}}}
{{{
naam = "dhr. Vliegenthart"
boodschappen = [
  "overgordijnen",
  "3 kilo Engelse drop (zonder blauwe)",
  "65 g uien",
  "dakpannen",
  "1 waterpomptang",
  "varkenshaasje",
  { boek = { auteur = "W.F. Hermans", titel = "Ik heb altijd gelijk" } },
  "2 NCRV-gidsen",  # moeten waarschijnlijk wel actueel zijn!
]
}}}
{{{
naam = "mw. De Wit"
boodschappen = [ 2 ons katenspek, 1 stuks Nieuwe Revu, luiwagen, 1 ossetong ]
}}}

Het lijkt erop dat het boek voor meneer Vliegenthart binnen //dit// array niet in blokvorm kan worden geformuleerd. De volgende syntax is ongeldig omdat //alle// array-elementen hier een table moeten zijn:
{{{
naam = "dhr. Vliegenthart"
[[boodschappen]]
  "overgordijnen"
[[boodschappen]]
  "3 kilo Engelse drop (zonder blauwe)"
[[boodschappen]]
  "65 g uien"
[[boodschappen]]
  "dakpannen"
[[boodschappen]]
  "1 waterpomptang"
[[boodschappen]]
  "varkenshaasje"
[[boodschappen]]
  boek.auteur = "W.F. Hermans"
  boek.titel = "Ik heb altijd gelijk"
[[boodschappen]]
  "2 NCRV-gidsen"  # moeten waarschijnlijk wel actueel zijn!
}}}

TOML ondersteunt aardig wat gegevenstypen, maar ''{{{nil}}}'' zit daar niet bij.
<<tiddler [[{}::togglesliders]]>>/%

%/++++(~TwmlChecklistExamples)![Three examples &darr;|show examples][Three examples &uarr;|show examples]
{{lf up{

{{{
<<div "!!!Checklist 1">>/%
%/{{lf pref f1l {{{w{&#x2756;}}} }}} <<div [=[Documented]=]>>/%
%/{{lf pref fgre{{{w{&#x2714;}}} }}} <<div [=[Done]=]>>/%
%/{{lf pref fe  {{{w{&#x25b7;}}} }}} <<div [=[To do or to pay attention to]=]>>/%
%/{{lf pref fred{{{w{&#x2716;}}} }}} <<div [=[Abandoned]=]>>
}}}
}}}{{lf{



{{h1{&rArr;}}}}}} {{ib{{{high0 sh{
{{hws{
<<div "!!!Checklist 1">>/%
%/{{lf pref f1l {{{w{&#x2756;}}} }}} <<div [=[Documented]=]>>/%
%/{{lf pref fgre{{{w{&#x2714;}}} }}} <<div [=[Done]=]>>/%
%/{{lf pref fe  {{{w{&#x25b7;}}} }}} <<div [=[To do or to pay attention to]=]>>/%
%/{{lf pref fred{{{w{&#x2716;}}} }}} <<div [=[Abandoned]=]>>
}}}}}}}}}

----
{{lf up{

{{pre{
"""<<div "!!!Checklist 2">>/%
%/{{ib ml2em{
@@{{mnaem f1l {{{w{&#x2756;}}}}}}  @@ Documented
@@{{mnaem fgre{{{w{&#x2714;}}}}}}  @@ Done
@@{{mnaem fe  {{{w{&#x25b7;}}}}}}  @@ To do or to pay attention to
@@{{mnaem fred{{{w{&#x2716;}}}}}}  @@ Abandoned
}}}
"""
}}}
}}}{{lf{




{{h1{&rArr;}}}}}} 
{{ib up{{{high0 sh{
{{hws{
<<div "!!!Checklist 2">>/%
%/{{ib ml2em{
@@{{mnaem f1l {{{w{&#x2756;}}}}}}  @@ Documented
@@{{mnaem fgre{{{w{&#x2714;}}}}}}  @@ Done
@@{{mnaem fe  {{{w{&#x25b7;}}}}}}  @@ To do or to pay attention to
@@{{mnaem fred{{{w{&#x2716;}}}}}}  @@ Abandoned
}}}

}}}}}}}}}

----
{{lf up{

{{pre{
"""<<div "!!!Checklist 3">>/%
%/{{lift on{
*@@{{mnaem f1l {{{w{&#x2756;}}}}}}  @@ Documented
*@@{{mnaem fgre{{{w{&#x2714;}}}}}}  @@ Done
*@@{{mnaem fe  {{{w{&#x25b7;}}}}}}  @@ To do or to pay attention to
*@@{{mnaem fred{{{w{&#x2716;}}}}}}  @@ Abandoned
}}}
"""
}}}
}}}{{lf up{




{{h1{&rArr;}}}}}}
{{ib up{{{high0 sh{
{{hws{
<<div "!!!Checklist 3">>/%
%/{{lift on{
*@@{{mnaem f1l {{{w{&#x2756;}}}}}}  @@Documented
*@@{{mnaem fgre{{{w{&#x2714;}}}}}}  @@ Done
*@@{{mnaem fe  {{{w{&#x25b7;}}}}}}  @@To do or to pay attention to
*@@{{mnaem fred{{{w{&#x2716;}}}}}}  @@Abandoned
}}}/%
%/}}}}}}}}}
===/%

%/++++(~TwmlChecklistComment)![Eight approaches &darr;|show comment][Eight approaches &uarr;|show comment]
Preferred options: ''{{f1{1//a//}}}'' (over ''{{f1{1}}}''), ''{{f1{2}}}'' (over ''{{f1{3}}}''), ''{{f1{4}}}'', ''{{f1{5//a//}}}'' (over ''{{f1{5}}}''), ''{{f1{6}}}'' -- not necessarily in that order, even though ''{{f1{1//a//}}}'' being terser than the almost similar ''{{f1{5//a//}}}''./%

%/
!!!Checklist 1 (2018 solution)
{{lf f1 h1{''1''}}} <<div [=[''{{tt{span.lf(//left//)}}} + {{tt{div(//right//)}}}'' //by //{{{div}}}// macro// -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt.]=]>>/%
%/{{lf f1 h1{''1''}}} <<div [=[''{{tt{span.lf(//left//)}}} + {{tt{div(//right//)}}}'' //by //{{{div}}}// macro// -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. -- //Height of "1" has only impact on floating part. Width of "1" determines indentation of right part. All //''{{{div}}}''//s produce a line feed, so suppressing blank lines in between requires intermediate //''{{{/%}}}''// ... //''{{{%/}}}''// pairs.//]=]>>/%

%/{{_{
!!!Checklist 1a (2021 solution)
}}}{{_{
{{lf f1 h1{''1//a//''}}} {{oh{
''{{tt{span.lf(//left//)}}} + {{tt{div.oh(//right//)}}}'' //by class specification// -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt.
}}}/%
%/{{lf f1 h1{''1//a//''}}} {{oh{
''{{tt{span.lf(//left//)}}} + {{tt{div.oh(//right//)}}}'' //by class specification// -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. -- //Height of "1a" has only impact on floating part. Width of "1a" determines indentation of right part. All //''{{{div}}}''//s produce a line feed, so suppressing blank lines in between requires intermediate //''{{{/%}}}''// ... //''{{{%/}}}''// pairs.//
}}}}}}/%

%/{{_{
!!!Checklist 2 (2021 solution)
}}}{{ib ml2em{
@@{{mnaem f1 h4{''2''}}}  @@''{{tt{div({{n w{&lang;}}}span(//left//) + //right//{{n{{{w{&rang;}}}^^+^^}}})}}}'' -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt.
@@{{mnaem f1 h4{''2''}}}  @@''{{tt{div({{n w{&lang;}}}span(//left//) + //right//{{n{{{w{&rang;}}}^^+^^}}})}}}'' -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. -- //Size of "2" has impact on both left and right part. Horizontal positioning is specified by positive left margin of the entire checklist (//''{{{div}}}''//) and negative margin of the left //''{{{span}}}''//s.//
}}}/%

%/
!!!Checklist 3 (2021 solution)
{{on{
*@@{{mnaem f1 h4{''3''}}}  @@''{{tt{div(ul(li(span(//left//) + //right//)))}}}'' -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt.
*@@{{mnaem f1 h4{''3''}}}  @@''{{tt{div(ul(li(span(//left//) + //right//)))}}}'' -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. -- //Same principle, but less practical than checklist 2.//
}}}/%

%/{{_{
!!!Checklist 4 (2020 solution)
}}}{{lf f1 h1{''4''}}} {{ib w95pct{''{{tt{span.lf(//left//)}}} + {{tt{span.ib(//right//)}}}'' -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt.}}}
{{lf f1 h1{''4''}}} {{ib w95pct{''{{tt{span.lf(//left//)}}} + {{tt{span.ib(//right//)}}}'' -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. -- //Height of "4" has only impact on floating part. Width of "4" determines indentation of right part. Width of  //''{{{span.ib}}}''// must be restricted to less than 100% in order to let it fit on the same line as //''{{{span.lf}}}''//.//}}}
/%

%/{{_{
!!!Checklist 5 (2020 solution)
}}}{{lf f1 h1{''5''}}} {{block ml3em{''{{tt{span.lf(//left//)}}} + {{tt{span.block(//right//)}}}'' -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt.}}}/%
%/{{lf f1 h1{''5''}}} {{block ml3em{''{{tt{span.lf(//left//)}}} + {{tt{span.block(//right//)}}}'' -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. -- //Height of "5" has only impact on floating part. Left margin of  //''{{{span.block}}}''// must be wide enough to house //''{{{span.lf}}}''//. All //''{{{span.block}}}''//s produce a line feed, so suppressing blank lines in between requires intermediate //''{{{/%}}}''// ... //''{{{%/}}}''// pairs.//}}}/%

%/{{_{
!!!Checklist 5a (2021 solution)
/%}}}{{_{%/
{{lf f1 h1{''5//a//''}}} {{block oh{''{{tt{span.lf(//left//)}}} + {{tt{span.[block,oh](//right//)}}}'' //by class specification// -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt.}}}/%
%/{{lf f1 h1{''5//a//''}}} {{block oh{''{{tt{span.lf(//left//)}}} + {{tt{span.[block,oh](//right//)}}}'' //by class specification// -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. -- //Height of "5a" has only impact on floating part. Width of "5a" determines indentation of right part. All //''{{{span.[block,oh]}}}''//s produce a line feed, so suppressing blank lines in between requires intermediate //''{{{/%}}}''// ... //''{{{%/}}}''// pairs. Almost the same as checklist 1a, but slightly more wordy.//}}}}}}/%

%/{{_{
!!!Checklist 6 (evergreen)
|plain|k
|{{f1 h1{''6''}}} |//Raw table// -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. |
|{{f1 h1{''6''}}} |//Raw table// -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. -- //Size (height, width) of "6" has only impact on left column. Right column starts where right margin of left column stops.// |
}}}
<<tiddler [[{}::togglesliders]]>> The {{z{CSS}}} classes described here are primarily meant as an extention of the standard features provided by the [[TiddlyWiki Markup Language]] ({{z{TWML}}}). The syntax for applying a {{z{CSS}}} class in {{z{TWML}}} is {{pref hitt{''"""{{"""''//«classname1» «classname2» ...//''{''//«content»//''"""}}}"""''}}}.
* {{_{If the third brace is immediately followed by a line break, the expression generates the {{z{HTML}}} element:
{{pref hitt{''<div class="''//«classname1» «classname2» ...//''">''//«content»//''</div>''}}}
without that line break. A line break immediately before the three closing braces (not mandatory) is also ignored.

}}}
* {{_{Otherwise the generated {{z{HTML}}} will look like:
{{pref hitt{''<span class="''//«classname1» «classname2» ...//''">''//«content»//''</span>''}}}
}}}
/%

%/+++(~TwmlElementaryClasses)![Elementary classes &darr;|show Elementary classes][Elementary classes &uarr;|hide Elementary classes]
|col1 thick1 bold1|k
|!Class        |>|!Effect                                        |
|{{{_}}}       |Class without any properties, just meant to force a {{hitt{span}}} or {{hitt{div}}} element | //see// [[Beneficial writer's blocks]] |
|{{{stix}}}    |>|{{stix hi0 sh{STIX Two Text}}}                 |
|{{{sy}}}      |>|{{sy hi0 sh{Symbola}}}                         |
|{{{paint}}}   |>|{{paint tight{Painted}}}                       |
|{{{spaint}}}  |>|{{spaint tight{Small painted}}}                |
|{{{npaint}}}  |>|{{npaint tight{Painted, with l and 0}}}        |
|{{{snpaint}}} |>|{{snpaint tight{Small painted, with l and 0}}} |
|{{{pen}}}     |>|{{pen tight {Pen}}}                            |
|{{{spen}}}    |>|{{spen tight {Small pen}}}                     |
|{{{hand}}}    |>|{{hand tight{Handwriting}}}                    |
|{{{shand}}}   |>|{{shand tight{Small handwriting}}}             |
|{{{serif}}}   |>|{{serif hi0 sh{Serif}}}                        |
|{{{sans}}}    |>|{{sans hi0 sh{Sans serif}}}                    |
|{{{saco}}}    |>|{{saco hi0 sh{Sans serif condensed}}}          |
|{{{tt}}}      |>|{{tt hi0 sh{Teletype (monospace)}}}            |
|{{{sc}}}      |>|{{hi0 sh sc{small caps}}}                      |
|{{{n}}}       |>|{{hi0 sh{normal font-weight}}}                 |
|{{{t}}}       |>|{{hi0 sh t{font-weight 500 (text)}}}           |
|{{tt{h//{{n{«n»}}}//}}} |>|Font-size: {{h6 hi0 sh{h6}}}, {{h4 hi0 sh{h4}}}, {{h3 hi0 sh{h3}}}, {{h2 hi0 sh{h2}}}, {{h1 hi0 sh{h1}}} |
|{{tt{h3w}}}   |>|Font-size ''{{hitt2{h3}}}'' plus some repositioning //(CSS properties// {{hitt s{position: relative; top: 0.1em; left: -0.1em; text-align: center;}}}//)// |
|{{{s}}}     |>|Font-size: {{s hi0 sh{Small}}}                   |
|{{tt{ta//{{n{«a»}}}//}}} |>|Text-alignment left/center/right: {{pref tt hws sh{''tal    ''}}}, {{pref tt hws sh{''  tac  ''}}}, {{pref tt hws sh{''    tar''}}} |
|{{tt{o//{{n{«aa»}}}//}}} |>|List-style-type //«aa»//: ''{{{d}}}'' &rarr; decimal, ''{{{la}}}'' &rarr; lower-alpha, ''{{{ua}}}'' &rarr; upper-alpha, ''{{{lr}}}'' &rarr; lower-roman, ''{{{ur}}}'' = upper-roman, ''{{{n}}}'' = none |
|{{{pref}}}  |>|{{pref hi0 sh{Preformatted     (preserving spaces)}}} |
|{{{tight}}} |>|<html><div class="tight hi0 sh" style="float:left">Tight<br>line-height</div></html> |
|{{{low}}}   |>|<html><div class="low hi0 sh" style="float:left">Low<br>line-height</div></html>     |
|{{{med}}}   |>|<html><div class="med hi0 sh" style="float:left">Medium<br>line-height</div></html>  |
|{{{suf}}}   |>|<html><div class="suf hi0 sh" style="float:left">Sufficient<br>line-height</div></html><br>&nbsp; &nbsp;{{up{{{up{(geared to ''{{{s}}}'')}}}}}} |
|{{{ws}}}    |>|padding-top:0.8em;padding-bottom:0.8em;{{ws sh{Some whitespace around}}}             |
|{{{hws}}}   |{{hws sh{Only padding left and right, __''h''__alf as much as ''{{hitt2{ws}}}''}}}     | {{hws sh{-- //with// ''{{{hws}}}'' --}}} &nbsp; {{sh{-- //without// ''{{{hws}}}'' --}}} |
|{{{widenq}}}|>|{{widenq hi0 sh{letter-spacing 0.25pt}}}                                             |
|{{{ls}}}    |>|{{ls hi0 sh{letter-spacing 0.5px}}}                                                  |
|{{{widenh}}}|>|{{widenh hi0 sh{letter-spacing 0.5pt}}}                                              |
|{{{widen1}}}|>|{{widen1 hi0 sh{letter-spacing 1pt}}}                                                |
|{{{lift}}}  |>|Display content as block with a negative top margin of one line-height               |
|{{{up}}}    |>|{{hi0 sh{Moved {{up{up}}}}}}                                                         |
|{{{hup}}}   |>|{{hi0 sh{Moved {{hup{half up}}}}}}                                                   |
|{{{qup}}}   |>|{{hi0 sh{Moved {{qup{quarter up}}}}}}                                                |
|{{{up1px}}} |>|{{hi0 sh{Moved {{up1px{1px up}}}}}}                                                  |
|{{{dn1px}}} |>|{{hi0 sh{Moved {{dn1px{1px down}}}}}}                                                |
|{{{qdn}}}   |>|{{hi0 sh{Moved {{qdn{quarter down}}}}}}                                              |
|{{{hdn}}}   |>|{{hi0 sh{Moved {{hdn{half down}}}}}}                                                 |
|{{{ref}}}   |>|{{hi0 sh{Moved {{ref{up}}} with smaller font-size than superscript}}}                |
|{{{r}}}     |padding-top:0.5em;padding-bottom:0.5em;{{ws sh{{{bgra fwhi r{-- Small border-radius --}}}}}}   |vertical-align:middle; {{ws sh{{{bgra fwhi{-- //without// ''{{tt{r}}}''//,// ''{{tt{r1em}}}''//, or// ''{{tt{rr}}}'' --}}}}}} |
|{{{r1em}}}  |padding-top:0.5em;padding-bottom:0.5em;{{ws sh{{{bgra fwhi r1em{-- Larger border-radius --}}}}}} |~|
|{{{rr}}}    |padding-top:0.5em;padding-bottom:0.5em;{{ws sh{{{bgra fwhi rr{-- Larger border-radius --}}}}}} |~|
|{{{block}}} |Display as block //(CSS property// {{hitt s{display: block;}}}//)// |vertical-align:middle; //see// [[Beneficial writer's blocks]] |
|{{{ib}}}    |Display as __''i''__nline-__''b''__lock //(CSS property// {{hitt s{display: inline-block;}}}//)// |~|
|{{{li}}}    |Display as __''l''__ist-__''i''__tem //(CSS property// {{hitt s{display: list-item;}}}//)// |~|
|{{tt{m//{{n{«a»«x»}}}//em}}} |Left/right margin in em: //«a»// = {{tt{''l''&vert;''r''}}}; //«x»// = {{tt{''q''&vert;''h''&vert;''1''&vert;''a''&vert;''2''&vert;''b''&vert;''3''}}} &rarr; 0.25 &vert; 0.5 &vert; 1 &vert; 1.5 &vert; 2 &vert; 2.5 &vert; 3 em |~|
|{{tt{mn//{{n{«x»}}}//em}}} |Negative left margin in em: //«x»// = {{tt{''1''&vert;''a''&vert;''2''&vert;''b''&vert;''3''}}} &rarr; &minus;1 &vert; &minus;1.5 &vert; &minus;2 &vert; &minus;2.5 &vert; &minus;3 em |~|
|{{tt{p//{{n{«a»«x»}}}//em}}} |Left/right padding in em: //«a»// = {{tt{''l''&vert;''r''}}}; //«x»// = {{tt{''q''&vert;''h''&vert;''1''&vert;''a''&vert;''2''&vert;''b''&vert;''3''}}} &rarr; 0.25 &vert; 0.5 &vert; 1 &vert; 1.5 &vert; 2 &vert; 2.5 &vert; 3 em |~|
|{{{lf}}} {{n{&vert;}}} {{{rf}}} |__''L''__eft __''f''__loating //(CSS property// {{hitt s{float: left;}}}//)// &vert; __''r''__ight __''f''__loating //(CSS property// {{hitt s{float: right;}}}//)// |~|
|{{{oh}}}    |Makes __''o''__verflow __''h''__idden //(CSS property// {{hitt s{overflow: hidden;}}}//)// |~|
|{{{clear}}} |Prevent a block-level element from appearing next to a floated element //(CSS property// {{hitt s{clear: both;}}}//)// |~|
|{{{w}}}     |>|Normalization of monospace character __''w''__idth: {{high tt s{{{f3m{"""{{tt{"""}}}''"""{{w{&lang;}}}"""''name''"""{{w{&rang;}}}"""''{{f3m{"""}}}"""}}}}}} &rArr; {{tt hi0 sh{{{w{&lang;}}}name{{w{&rang;}}}}}}  |
|{{{ww}}}    |>|Double monospace character width: {{high tt s{{{f3m{"""{{tt{"""}}}x ''"""{{ww{&xrarr;}}}"""'' y''''{{f3m{"""}}}"""}}}}}} &rArr; {{tt hi0 sh{x {{ww{&xrarr;}}} y}}} |
|{{tt{w//{{n{«nn»}}}//pct}}} |>|Width in percent: //«nn»// = 20% to 95% by 5% |
|{{{wfull}}} |>|Full width  //(CSS property// {{hitt s{width: 100%;}}}//)// |
|{{tt{h//{{n{«nn»}}}//em}}} |>|Height //«nn»// = 10 em to 40 em by 5 em |
|{{{scroll}}} |>|In case of overflow -- but only then -- a scrollbar is placed //(CSS property// {{hitt s{overflow: auto;}}}//)// |
|{{{vrl}}}   |>|Vertical bar at the left side //(CSS property// {{hitt s{border-left: 1px dashed """[[ColorPalette::TertiaryDark]]""";}}}//)// |
|{{{vrr}}}   |>|Vertical bar at the right side //(CSS property// {{hitt s{border-right: 1px dashed """[[ColorPalette::TertiaryDark]]""";}}}//)// |
|{{{vrl1}}}  |>|Vertical bar at the left side //(CSS property// {{hitt s{border-left: 1px solid """[[ColorPalette::PrimarySoft]]""";}}}//)// |
|{{{vrr1}}}  |>|Vertical bar at the right side //(CSS property// {{hitt s{border-right: 1px solid """[[ColorPalette::PrimarySoft]]""";}}}//)// |
|{{tt{b//{{n{«n»}}}//}}} |>|Background-color: ''{{b0 hws tt sh{b0}}}'', ''{{b1 hws tt{b1}}}'', ''{{b2 hws tt{b2}}}'', ''{{b3 hws tt{b3}}}'', ''{{b4 hws tt{b4}}}'', ''{{b5 hws tt{b5}}}'', ''{{b6 hws tt{b6}}}'' |
|{{tt{b//{{n{«xx»}}}//}}} |>|Background-color: ''{{b1p hws tt{b1p}}}'', ''{{b1w hws tt{b1w}}}'', ''{{b1f hws tt{b1f}}}'', ''{{b1l hws tt fwhi{b1l}}}'', ''{{b1s hws tt fwhi{b1s}}}'', ''{{b1m hws tt fwhi{b1m}}}'', ''{{b1d hws tt fwhi{b1d}}}'', ''{{b2w hws tt{b2w}}}'', ''{{b2p hws tt{b2p}}}'', ''{{b2l hws tt{b2l}}}'', ''{{b2s hws tt fwhi{b2s}}}'', ''{{b2m hws tt fwhi{b2m}}}'', ''{{b2d hws tt fwhi{b2d}}}'', ''{{b3w hws tt{b3w}}}'', ''{{b3p hws tt{b3p}}}'', ''{{b3l hws tt{b3l}}}'', ''{{b3s hws tt fwhi{b3s}}}'', ''{{b3m hws tt fwhi{b3m}}}'', ''{{b3d hws tt fwhi{b3d}}}'', ''{{be hws tt fwhi{be}}}'' |
|{{tt{b//{{n{«aaa»}}}//}}}  |>|Background-color: ''{{bwhi hi0 tt sh{bwhi}}}'', ''{{bred hws tt fwhi{bred}}}'', ''{{bora hws tt fwhi{bora}}}'', ''{{byel hws tt{byel}}}'', ''{{bgre hws tt fwhi{bgre}}}'', ''{{bkya hws tt fwhi{bkya}}}'', ''{{bcya hws tt fwhi{bcya}}}'', ''{{bblu hws tt fwhi{bblu}}}'', ''{{bpur hws tt fwhi{bpur}}}'', ''{{bbla hws tt fwhi{bbla}}}'', ''{{bgra hws tt fwhi{bgra}}}'' |
|{{tt{f//{{n{«n»}}}//}}} |>|Foreground-color: ''{{f0 tt{f0}}}'', ''{{f1 tt{f1}}}'', ''{{f2 tt{f2}}}'', ''{{f3 tt{f3}}}'', ''{{f4 tt{f4}}}'', ''{{f5 tt{f5}}}'', ''{{f6 tt{f6}}}'' |
|{{tt{f//{{n{«xx»}}}//}}} |>|Foreground-color: ''{{f1p bgra hws tt{f1p}}}'', ''{{f1w bgra hws tt{f1w}}}'', ''{{f1f bgra hws tt{f1f}}}'', ''{{f1l tt{f1l}}}'', ''{{f1s tt{f1s}}}'', ''{{f1m tt{f1m}}}'', ''{{f1d tt{f1d}}}'', ''{{f2w bgra hws tt{f2w}}}'', ''{{f2p bgra hws tt{f2p}}}'', ''{{f2l tt{f2l}}}'', ''{{f2s tt{f2s}}}'', ''{{f2m tt{f2m}}}'', ''{{f2d tt{f2d}}}'', ''{{f3w bgra hws tt{f3w}}}'', ''{{f3p bgra hws tt{f3p}}}'', ''{{f3l tt{f3l}}}'', ''{{f3s tt {f3s}}}'', ''{{f3m tt{f3m}}}'', ''{{f3d tt{f3d}}}'', ''{{fe tt{fe}}}'' |
|{{tt{f//{{n{«aaa»}}}//}}} |>|Foreground-color: ''{{fwhi bgra hws tt{fwhi}}}'', ''{{tt fred{fred}}}'', ''{{tt fora{fora}}}'', ''{{fyel bgra hws tt{fyel}}}'', ''{{tt fgre{fgre}}}'', ''{{tt fkya{fkya}}}'', ''{{tt fcya{fcya}}}'', ''{{tt fblu{fblu}}}'', ''{{tt fpur{fpur}}}'', ''{{tt fbla{fbla}}}'', ''{{tt fgra{fgra}}}'' |
|{{tt{u//{{n{«xx»}}}//}}} |>|Border-color top & left: ''@@bgcolor(gray):padding(0.2em):{{u0 hws tt fwhi{u0}}}@@'', ''{{u1p hi0 tt{u1p}}}'', ''{{u1w hi0 tt{u1w}}}'', ''{{u4 hi0 tt{u4}}}'', ''{{u1 hi0 tt{u1}}}'', ''{{u1m hi0 tt{u1m}}}'', ''{{u1d hi0 tt{u1d}}}'', ''{{u2w hi0 tt{u2w}}}'', ''{{u5 hi0 tt{u5}}}'', ''{{u2 hi0 tt{u2}}}'', ''{{u2s hi0 tt{u2s}}}'', ''{{u2m hi0 tt{u2m}}}'', ''{{u2d hi0 tt{u2d}}}'', ''{{u3w hi0 tt{u3w}}}'', ''{{u6 hi0 tt{u6}}}'', ''{{u3 hi0 tt{u3}}}'', ''{{u3s hi0 tt{u3s}}}'', ''{{u3m hi0 tt{u3m}}}'', ''{{u3d hi0 tt{u3d}}}'' |
|{{tt{d//{{n{«xx»}}}//}}} |>|Border-color right & bottom: ''@@bgcolor(gray):padding(0.2em):{{d0 hws tt fwhi{d0}}}@@'', ''{{d1p hi0 tt{d1p}}}'', ''{{d1w hi0 tt{d1w}}}'', ''{{d4 hi0 tt{d4}}}'', ''{{d1 hi0 tt{d1}}}'', ''{{d1m hi0 tt{d1m}}}'', ''{{d1d hi0 tt{d1d}}}'', ''{{d2w hi0 tt{d2w}}}'', ''{{d5 hi0 tt{d5}}}'', ''{{d2 hi0 tt{d2}}}'', ''{{d2s hi0 tt{d2s}}}'', ''{{d2m hi0 tt{d2m}}}'', ''{{d2d hi0 tt{d2d}}}'', ''{{d3w hi0 tt{d3w}}}'', ''{{d6 hi0 tt{d6}}}'', ''{{d3 hi0 tt{d3}}}'', ''{{d3s hi0 tt{d3s}}}'', ''{{d3m hi0 tt{d3m}}}'', ''{{d3d hi0 tt{d3d}}}'' |
|{{tt{sh}}} |>|padding-top:0.5em;padding-bottom:0.5em;{{ws sh{{{sh hi0{Box-shadow}}}}}}                      |

===/%

%/+++(~TwmlCompositeClasses)![Composite classes &darr;|show Composite classes][Composite classes &uarr;|hide Composite classes]
|col1 thick1 bold1|k
|!Class               |>|!Effect                                                                                           |
|{{{z}}}              |>|{{lf{Includes ''{{hitt2{s}}}'' and ''{{hitt2{med}}}'' &rArr;}}} {{ib{<html><div class="s med hi0 sh">Medium<br>line-height</div></html>}}} |
|{{tt{pretts//{{n{«n»}}}//}}} |>|{{lf{Includes ''{{hitt2{pref}}}'', ''{{hitt2{tt}}}'', ''{{hitt2{s}}}'', ''{{hitt2{med}}}'', ''{{hitt2{ws}}}'', {{hitt2{''b''//«n»//}}}; background-colors ''{{hi0 sh tt{0}}}'', ''{{hi1 tt{1}}}'', ''{{hi2 tt{2}}}'', ''{{hi3 tt{3}}}'', ''{{hi4 tt{4}}}'', ''{{hi5 tt{5}}}'', ''{{hi6 tt{6}}}'' &rArr;}}} {{ib{<html><div class="sh" style="padding:0.5em 0.25em 0.75em 0.25em;"><span class="pretts1">Color <i>«n»</i> = 1</span></div></html>}}} |
|{{tt{pre//{{n{«n»}}}//}}} |>|{{lf{Includes {{hitt2{''pretts''//«n»//}}}, {{hitt2{''d''//«xx»//}}}, ''{{hitt2{r}}}'', ''{{hitt2{scroll}}}'' &rArr;}}} {{ib{<html><div class="sh" style="padding:0.5em 0.25em 0.75em 0.25em;"><span class="pre1">Color <i>«n»</i> = 1</span></div></html>}}} |
|{{tt{hi//{{n{«n»}}}//}}} |Includes ''{{hitt2{hws}}}'' and {{hitt2{''b''//«n»//}}} &rArr; {{ib{<html><div class="sh" style="padding:0.25em;"><span class="hi1">Color <i>«n»</i> = 1</span></div></html>}}} | {{ib{<html><div class="sh" style="padding:0.25em;"><span class="hi1">&mdash; <i>with</i> <b><code>hi1</code></b> &mdash;</span> &nbsp; <span class="b1">&mdash; <i>with only</i> <b><code>b1</code></b> &mdash;</span></div></html>}}} |
|{{tt{high//«n»//}}}   |>|Includes {{hitt2{''hi''//«n»//}}}, {{hitt2{''d''//«xx»//}}}, ''{{hitt2{r}}}'' &rArr; {{ib{<html><div class="sh" style="padding:0.25em;"><span class="high1">Color <i>«n»</i> = 1</span></div></html>}}} |
|{{tt{hitt//{{n{«n»}}}//}}} |>|Includes {{hitt2{''high''//«n»//}}} and ''{{hitt2{tt}}}'' &rArr; {{ib{<html><div class="sh" style="padding:0.25em;"><span class="hitt1 ">Color <i>«n»</i> = 1</span></div></html>}}} |
|{{tt{tape//{{n{«n»}}}//}}} |>|Includes ''{{hitt2{hws}}}'', {{hitt2{''b''//«n»//}}}, and border-colors {{hitt2{//«yy»//}}} &rArr; {{ib{<html><div class="sh" style="padding:0.25em;"><span class="tape0 tt"><b>0</b></span>, <span class="tape1 tt"><b>1</b></span>, <span class="tape2 tt"><b>2</b></span>, <span class="tape3 tt"><b>3</b></span>, <span class="tape4 tt"><b>4</b></span>, <span class="tape5 tt"><b>5</b></span>, <span class="tape6 tt"><b>6</b></span>, </div></html>}}} |
|{{tt{left//{{n{«n»}}}//}}} |Includes ''{{hitt2{lf}}}'', a coloring scheme ''{{{0}}}''&ndash;''{{{6}}}'' for foreground (//«n»//) and right border (//«yy»//), /%|
%/
{{lf{ and some extra padding at the right side &rArr;}}} {{ib{@@float:left;{{ib sh{{{left0{''{{tt{0}}}''}}}}}}@@,}}} {{ib{@@float:left;{{ib sh{{{left1{''{{tt{1}}}''}}}}}}@@,}}} {{ib{@@float:left;{{ib sh{{{left2{''{{tt{2}}}''}}}}}}@@,}}} {{ib{@@float:left;{{ib sh{{{left3{''{{tt{3}}}''}}}}}}@@,}}} {{ib{@@float:left;{{ib sh{{{left4{''{{tt{4}}}''}}}}}}@@,}}} {{ib{@@float:left;{{ib sh{{{left5{''{{tt{5}}}''}}}}}}@@,}}} {{ib{@@float:left;{{ib sh{{{left6{''{{tt{6}}}''}}}}}}@@&nbsp;}}} |vertical-align:middle; //see// [[Beneficial writer's blocks]] |
/%

%/
{{lift{
!!!Numerical color codes for background, foreground, and borders
|col1 thick1|k
|Background {{tt{//«n»//}}} |''{{hi0 tt sh{0}}}'' = white    |''{{hi1 tt{1}}}'' = 1F          |''{{hi2 tt{2}}}'' = 2P          |''{{hi3 tt{3}}}'' = 3P          |''{{hi4 tt{4}}}'' = 1W |''{{hi5 tt{5}}}'' = 2W |''{{hi6 tt{6}}}'' = 3W |
|Foreground {{tt{//«n»//}}} |''{{b3s hws tt fwhi{0}}}'' = 3S |''{{b1s hws tt fwhi{1}}}'' = 1S |''{{b2m hws tt fwhi{2}}}'' = 2M |''{{b3m hws tt fwhi{3}}}'' = 3M |''{{b1l hws tt fwhi{4}}}'' = 1L |''{{b2s hws tt fwhi{5}}}'' = 2S |''{{b3s hws tt fwhi{6}}}'' = 3S |
|>|>|>|>|>|>|>|!|
|Border {{tt{//«xx»//}}}    |''{{hi3 tt{0}}}'' = 3P          |''{{b1l hws tt fwhi{1}}}'' = 1L |''{{b3l hws tt{3}}}'' = 3L      |''{{b3l hws tt{3}}}'' = 3L      |''{{hi1 tt{4}}}'' = 1F |''{{hi3 tt{5}}}'' = 3P |''{{hi3 tt{6}}}'' = 3P |
|Border {{tt{//«yy»//}}}    |''{{hi3 tt{0}}}'' = 3P          |''{{b1l hws tt fwhi{1}}}'' = 1L |''{{b2l hws tt{2}}}'' = 2L      |''{{b3l hws tt{3}}}'' = 3L      |''{{hi1 tt{4}}}'' = 1F |''{{hi2 tt{5}}}'' = 2P |''{{hi3 tt{6}}}'' = 3P |
}}}/%

%/
{{lift{
!!!Default colors
|col1 thick1|k
|{{tt{//«n»//}}} = ''{{{5}}}''  |padding-top:0.35em;padding-bottom:0.5em;{{lf{''{{pretts{pretts}}}'', ''{{pre{pre}}}'', ''{{hi tt{hi}}}'', ''{{high tt{high}}}'', ''{{hitt{hitt}}}'',}}} {{ib hws sh{{{left5{''{{tt{left}}}''}}}}}} |
|{{tt{//«n»//}}} = ''{{{6}}}''  |''{{tape tt s{tape}}}'' |
}}}
===/%

%/+++(~TwmlSpecialClasses)![Special classes &darr;|show Special classes][Special classes &uarr;|hide Special classes]
|col1 thick1 bold1|k
|!Class    |!Effect                                                                                           |
|{{{kbd}}} |Keyboard key: {{hitt{"""{{kbd tt{K}}}"""}}} &rArr; {{kbd tt{K}}} |
|{{{II}}}  |2px {{II{underline}}}: {{hitt{"""{{kbd II tt{''K''}}}"""}}} &rArr; {{kbd II tt{''K''}}} |
|{{{III}}} |3px {{III{underline}}}: {{hitt{"""{{kbd III b6 f3d tt{''K''}}}"""}}} &rArr; {{kbd III b6 f3d tt{''K''}}} |
|{{{IV}}}  |4px {{IV{underline}}}: {{hitt{"""{{kbd IV b6 f3 tt{''K''}}}"""}}} &rArr; {{kbd IV b6 f3 tt{''K''}}} |
===/%

%/<html><a name="TableClasses"></a></html>+++(~TwmlTableClasses)![Table classes &darr;|show Table classes][Table classes &uarr;|hide Table classes]
|col1 thick1 bold1|k
|!class |!Effect |
|{{{full}}}   |Full width table |
|{{{middle}}} |Center all cells vertically //(CSS property// {{hitt s{vertical-align: middle;}}}//)// |
Default layout as far as borders, margins and paddings are concerned:
{{lf{{{pre{
"""|col1 bold1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib{
|col1 bold1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
}}}/%

%/{{block clear{Less borders:
{{lf{{{pre{
"""|"""''{{high2{open}}}'' col1 bold1"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib up{

|open col1 bold1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
}}}}}}/%

%/{{block clear{Borderless, no margin above and below the table:
{{lf{{{pre{
"""|"""''{{high2{bare}}}'' col1 bold1"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib up{

|bare col1 bold1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
}}}}}}/%

%/{{block clear{The same, but no padding of cell content except for the right side:
{{lf{{{pre{
"""|"""''{{high2{plain}}}''"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib {

|plain col1 bold1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
}}}}}}/%

%/{{block clear{No padding at all:
{{lf{{{pre{
"""|"""''{{high2{raw}}}'' col1 bold1"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib{

|raw col1 bold1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
}}}}}}/%

%/{{block clear{Absolute default layout:
{{lf up{
{{pre{
"""| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c"""
}}}}}}{{lf{


{{h1 hup{&rArr;}}}}}}{{ib up{
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c
}}}}}}/%

%/{{block clear{Columns with colored background (''{{hitt2{col1}}}'', ''{{hitt2{col2}}}''):
{{lf up{{{pre{
"""|"""''{{high2{col1}}}''"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib hup{
|col1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c
}}}}}}/%

%/{{block clear{Columns with thick right border (''{{hitt2{thick1}}}'', ''{{hitt2{thick2}}}''):
{{lf up{{{pre{
"""|"""''{{high2{thick1}}}''"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib hup{
|thick1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c
}}}}}}/%

%/{{block clear{Columns with bold text (''{{hitt2{bold1}}}'', ''{{hitt2{bold2}}}''):
{{lf up{{{pre{
"""|"""''{{high2{bold1}}}''"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib hup{
|bold1|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c
}}}}}}/%

%/{{block clear{Rows with colored background (''{{hitt2{even}}}'', ''{{hitt2{odd}}}''):
{{lf up{{{pre{
"""|"""''{{high2{even}}}''"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib hup{
|even|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c
}}}}}}/%

%/{{block clear{Keep in mind that the //second// table row is considered to be the //first odd// row, as the very //first// row is usually a header row.}}}/%

%/
Caption left aligned:
{{lf up{{{pre{
"""|"""''{{high2{capl}}}''"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib hup{
|capl|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c
}}}/%

%/
{{block clear{Caption above table:
{{lf up{{{pre{
"""|"""''{{high2{capt}}}''"""|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c"""
}}}}}}{{lf{


{{h1{&rArr;}}}}}}{{ib lift{
|capt|k
| !A | !B |
|  1 | {{{one}}} |
|  2 | {{{two}}} |
|*** |c
}}}}}}/%

%/
See also [[Beneficial writer's blocks]] and [[Table tricks]].
===
{{pre{
(0 &lt;&lt;eval [=[(1 &lt;&lt;eval [=[(2 &lt;&lt;eval [=[(3)]={{fred{\\}}}]>{{fred{\\}}}>)]={{fred{\}}}]>{{fred{\}}}>)]=]>>)  {{f2{&rArr;}}}  ''(0 <<eval [=[(1 <<eval [=[(2 <<eval [=[(3)]=\\]>\\>)]=\]>\>)]=]>>)''
{{f2{"""   |      ^^^   |      ^^^   |      ^^^   ^^^^^   | ^^^^  | ^^^ |
   |            |            |      ___________   |       |     |
   |            |            +--------------------+       |     |
   |            |      _________________________________  |     |
   |            +-----------------------------------------+     |
   |      _____________________________________________________ |
   +------------------------------------------------------------+"""}}}
}}}
Getagt met ''{{high3 rr sans z{systemConfig}}}'':
* [[NestedSlidersPlugin]] met bijbehorende [[NestedSlidersPluginInfo]]
* [[InlineJavascriptPlugin]] with accompanying [[InlineJavascriptPluginInfo]]
* [[MatchTagsPlugin]] met bijbehorende [[MatchTagsPluginInfo]]
* [[PreviewPlugin]] met bijbehorende [[PreviewPluginInfo]]
* [[SnapshotPlugin]] met bijbehorende [[SnapshotPluginInfo]]
* [[ExtraMacros]] --met bijbehorende [[ExtraMacrosInfo]]--
* [[ParseParamsPatch]]
* [[DisableWikiLinksPlugin]]
* [[config ToggleRightSidebar]]
* [[config DisableWikiLinksPlugin]]
* [[ShowPopupPlugin]] met bijhorende [[ShowPopupPluginInfo]]
* [[CollapseTiddlersPlugin]]
* [[SectionLinksPlugin]]
* [[ToolbarPatch]]
* [[ExtraCommands]]
* [[GetFaviconAndFonts]]
* [[GotoPlugin]] met bijbehorende [[GotoPluginInfo]]
* [[SimpleSearchPlugin]]
* [[BreadcrumbsPlugin]] met bijbehorende [[BreadcrumbsPluginInfo]]
* [[{External switches}]]
* [[UnsavedChangesPlugin]]
* [[{Internal switches}]]
* [[displayDefaultTiddlersPatch]]
* [[!InitDevlog]]
* [[config ToggleLeftSidebar]]
Getagt met ''{{high3 rr sans z{transclusion}}}'':
* [[ToggleRightSidebar]]
* [[ToggleReadOnly]]
* [[ToggleSliders]]
* [[{}]]
* [[ReplaceTiddlerTitle]]
* [[ShowDocumentInfo]]
* [[ShowPlugins]]
* [[ShowTabsForTags]]
* [[HideTiddlerTags]]
* [[RefreshPageDisplay]]
* [[WithholdTiddlerTags]]
* [[NextTiddler]]
* [[WithholdTiddlerTagging]]
* [[BreadcrumbsCommand]]
* [[ToggleBreadcrumbs]]
* [[ToggleLeftSidebar]]/%

%/
Beide lijstjes geven afzonderlijk de volgorde weer waarin deze tiddlers aan mijn ~TiddlyWiki's zijn toegevoegd. De eerste had ik in 2009 opgenomen. Na 2020 zijn [[config ToggleRightSidebar]] t/m [[displayDefaultTiddlersPatch]] en alle transclusions behalve [[ToggleRightSidebar]] erbij gekomen. Zie ook {{t{<<tiddler ShowPlugins>>}}} en {{t{<<tiddler ShowDocumentInfo with: "deze samenvatting">>}}}.

Om onbedoelde wijzigingen te voorkomen heb ik het aanvankelijk 'lege' ~TiddlyWiki-bestand naar alleen-lezen omgebogen met behulp van de one-liner:
{{pre{
perl -pe "BEGIN {binmode(STDOUT)} s/readOnly = {{fred{false}}}/readOnly = {{fblu t{true}}}/; s/{{fred{false}}} : config/{{fblu t{readOnly}}} : config/;"
}}}
{{lf vrr praem sans{''{{h3 fbla{De tags}}}''{{s{@@line-height:1.4em;<<allTags>>@@}}}}}} <<div [=[{{ib pl1em{''{{h3 sans{De categorieën}}}''
Hoewel deze site voornamelijk Nederlandstalig is, heb ik voor de tags Engelse trefwoorden gekozen, opdat ook bezoekers die het Nederlands niet machtig zijn meteen kunnen aflezen welke [[tiddlers|Tiddler]] voor hen interessant zouden kunnen zijn en de moeite waard om even door Google Translate te halen. Bovendien zijn mijn tiddlers op die manier wat eenvoudiger uitwisselbaar met eventuele andere wereldpublieke [[TiddlyWiki]]'s, mocht het daar ooit van komen.
;{{n{T{{sc{ags beginnend met een punt}}} ({{high3 rr z{''{{sans{.}}}''//«subject»//}}})}}}
:verwijzen naar tiddlers die gaan over onderwerpen waarvoor deze site is aangelegd.
;{{n{T{{sc{ags beginnend met een slash}}} ({{high3 rr z{''{{sans{/}}}''//«subject»//}}})}}}
:verwijzen naar tiddlers die iets te maken hebben met de site zelf (inrichting, onderhoud, bediening).
;{{n{T{{sc{ags beginnend met een tilde}}} ({{high3 rr z{''{{sans{~}}}''//«subject»//}}})}}}
:zijn tijdelijke tags die verwijzen naar waarschijnlijk eveneens tijdelijke tiddlers. Voor zover deze hier voorkomen, moeten ze uiteindelijk worden verwijderd.
;{{n{O{{sc{verige tags}}}}}}
:behoren tot de generieke mechanismen van de ~TiddlyWiki-omgeving. Voor mij als schrijver en redacteur bevatten ze technische informatie die van belang kan zijn, maar de lezers kunnen deze tags geheel negeren. Vandaar dat ik de inhoudelijk of redactioneel interessante tags ter onderscheid van een prefix {{hitt3 z{''.''}}}, {{hitt3 z{''/''}}} of {{hitt3 z{''~''}}} heb voorzien, zodat deze automatisch bovenaan (punt en slash) of juist helemaal onderaan (tilde) de lijst komen te staan.

{{h3 sans{''Bijzonderheden''}}}
De vetgedrukte tags links hiernaast zijn tevens uitgevoerd als zelfstandige tiddler. Zulke tiddlers zijn niet met hun eigen tag getagd, maar mogelijk wel met andere tags. De cursief gedrukte tags hiernaast zijn geen tiddlers, al is het niet uitgesloten dat ik sommige hiervan later alsnog tot tiddler bevorder.

Ik streef ernaar de meer specifieke tags boven de minder specifieke tags in het {{sc{tags}}}-blokje van de tiddler te plaatsen.
}}}]=]>>
!!C, Pascal, PL/I
Over één grammaticale onvolkomenheid in C zijn de makers van C in hun boek{{ref{&#x200a;[[[1]|##01]]}}} heel open: de syntaxis van {{tt t{if}}}-statements kan op tweeërlei wijze worden uitgelegd, zodat onduidelijk is wat bij wat hoort. Het gaat om deze specificatie:

<<eval [=[{{ml2em mr1em pref tt fblu{
//statement//     $--> //labeledStmt//
               $| //expressionStmt//
               $| //compoundStmt//
               $| //selectionStmt//
               $| //iterationStmt//
               $| //jumpStmt//
//selectionStmt// $--> ''{{fbla{if (}}}'' //expression// ''{{fbla{)}}}'' //statement//
               $| ''{{fbla{if (}}}'' //expression// ''{{fbla{)}}}'' //statement// ''{{fbla{else}}}'' //statement//
               $| ''{{fbla{switch (}}}'' //expression// ''{{fbla{)}}}'' //statement//
}}}]=] fblu>>
De nonterminal //{{sans fblu{selectionStmt}}}// kan volgens deze productieregels op twee manieren worden herschreven:

[img[data/images/dangling-else.png]]

Het resultaat is twee keer dezelfde sequentie van dezelfde taalcomponenten, maar met een verschillende betekenis. In het linker schema hoort de {{tt t{else}}}-tak bij het geneste {{tt t{if}}}-statement. Rechts is de {{tt t{else}}}-tak onderdeel van het omvattende {{tt t{if}}}-statement en heeft de binnengelegen {{tt t{if}}} geen {{tt t{else}}}-tak. Wat is nu de juiste interpretatie? Om deze ambiguïteit op te lossen is buiten het formele stelsel van productieregels voorgeschreven dat de {{tt t{else}}} altijd bij de meest nabije {{tt t{if}}} aan de linkerkant hoort. Om de rechter betekenis te krijgen moet de geneste {{tt t{if}}} met behulp van accolades worden ingepakt tot een compound statement: ''{{hitt z{{ if ( {{fblu n{//expression//}}} ) {{fblu n{//statement//}}} """}"""}}}''.

Buiten veel op de syntaxis van C gebaseerde talen vertonen ook Pascal en PL/I (inclusief afgeleiden daarvan zoals SAS en Rexx) deze tekortkoming. Of moet ik het een feature noemen?/%

%/
!!ALGOL 60
ALGOL 60, de inspirerende voorloper van PL/I (1964), Pascal (1970) en C (1973), is wèl eenduidig wat de aanhechting van {{tt t{else}}} betreft. De opzet van de hierboven uitgestalde constructies is [[in ALGOL syntactisch ongeldig|Een eenduidigheidje in ALGOL 60]]. Alleen via een compound statement valt een {{tt t{if}}}-statement in de {{tt t{then}}}-tak te nesten. Oftewel:
* Linker betekenis: {{pref hitt z{''if'' //booleanExpr// ''then'' {{fora{__{{fbla{''{{b2p{begin}}} if'' //booleanExpr// ''then'' //unconditionalStmt// ''else'' //statement// ''{{b2p{end}}}''}}}__}}}}}}
* Rechter betekenis: {{pref hitt z{''if'' //booleanExpr// ''then'' {{fora{__{{fbla{''{{b2p{begin}}} if'' //booleanExpr// ''then'' //unconditionalStmt// ''{{b2p{end}}}''}}}__}}} ''else'' //statement//}}}
Enerzijds is dat lekker expliciet, ander&shy;zijds is er wat vaker extra aankleding nodig dan in C, Pascal of PL/I. Zeker weten doe ik het niet, maar ik vermoed dat het loslaten van de restrictie bij het ontwerp van de latere talen een bewuste keuze is geweest om de programmeur enige toets&shy;aanslagen te besparen./%

%/
!!Lua, Basic
In Lua heeft het {{tt t{if}}}-statement de volgende vorm:

<<eval [=[{{ml2em mr1em pref tt fgre{
''{{fbla{if}}}'' //expression// ''{{fbla{then}}}'' //block//
$(''{{fbla{elseif}}}'' //expression// ''{{fbla{then}}}'' //block//$) $___$0
$(''{{fbla{else}}}'' //block//$)$0
''{{fbla{end}}}''
}}}
waarbij:
:{{pref tt fgre{//block// $--> //statement// $___$0 //returnStmt//$0
}}}]=] fgre>>/%

%/Omdat begin en eind van ieder {{tt t{if}}}-statement afgebakend is met ''{{hitt{if}}}'' en ''{{hitt{end}}}'', kan in ieder //{{sans fgre{block}}}// probleemloos één {{tt t{if}}}-statement worden ingevuld zonder dat er verwarring over de grenzen van een en ander kan ontstaan. In Basic werkt het net zo (waarbij het {{tt t{if}}}-statement zelfs eindigt met het nog wat indringender ''{{hitt{end if}}}'')./%

%/
!!Python, Nim
Bij Python en Nim geeft inspringing aan hoe codesegmenten in elkaar genest zijn. Dus daar zullen evenmin twijfels over de interpretatie rijzen.

----
|plain |k
|<html><a name="01">[1]</a></html> |<<tiddler Bibliografie##K&R>> Ook in [[PDF-vorm|https://colorcomputerarchive.com/repo/Documents/Books/The%20C%20Programming%20Language%20(Kernighan%20Ritchie).pdf]] te vinden. Van de [[gepubliceerde errata|https://gist.github.com/ttilley/1159475]] heb ik kennisgenomen. |
/% macrovariables macrovariabelen %/Macro variables may have a global or a local scope. 'Local' means that the variable concerned only exists during the expansion and execution of a macro that houses that variable in its own symbol table. If there's also a global variable with the same name, that one is temporarely ignored.

There is one global symbol table for all global macro variables. Besides that, each macro stores its own local macro variables in its own local symbol table. Without such variables, there is no symbol table for that macro.{{ref{[[[1]|##1]]}}}

In many cases it's immediately clear whether a macro variable is local or not. When declared as local inside a macro definition, it is local. Macro parameters are local as well. When declared as global inside a macro definition, it is global. When defined outside a macro definition, it is global too. In this article, I will label these variables as LVAR and GVAR respectively.

There are many other cases where you can't tell at a single glance whether a variable is local or global, since it depends on the circumstances. Especially nested macros complicate the demarcation of the scopes. For such situations, I'll distinguish ~CVARs, ~FVARs and ~SVARs. This is the resulting typology:/%
%/
<html><pre>
<span style="color:white; background-color:gray"> <b>MVAR</b> </span>  <i>macro variable</i>
  &Delta;
  &#x251C;&#x2500;&#x2500;<span style="color:white; background-color:green"> <b>LVAR</b> </span>  <font color="green"><i>explicitly local macro variable</i></font>
  &#x2502;
  &#x251C;&#x2500;&#x2500;<span style="color:white; background-color:darkorange"> <b>CVAR</b> </span>  <font color="darkorange"><i>'contextual' macro variable, scope depends on context</i></font>
  &#x2502;    &Delta;
  &#x2502;    &#x251C;&#x2500;&#x2500;<span style="color:white; background-color:red"> <b>FVAR</b> </span>  <font color="red"><i>'founding' macro variable, is willing to build its own home</i></font>
  &#x2502;    &#x2514;&#x2500;&#x2500;<span style="color:white; background-color:#b47"> <b>SVAR</b> </span>  <font color="#bb4477"><i>'seeking' macro variable, keeps on searching for a place to live</i></font>
  &#x2502;
  &#x2514;&#x2500;&#x2500;<span style="color:white; background-color:#aa0"> <b>GVAR</b> </span>  <font color="#aaaa00"><i>explicitly global macro variable</i></font>
</pre</html>/%

%/
These five types are discussed in the next sections. The logic of assignments and retrievals is also presented in diagrams according to the following legend:/%
%/
:[img[Legend|data/images/SAS/SAS scope legend.png]]/%

%/
Wanting this explanation to be comprehensive but without redundency, I'll present just two nested macros:
<html><pre>
%macro <b>INNER</b>(...);
  ...
%mend INNER;

%macro <b>OUTER</b>;
  <b>%INNER</b>(...)
%mend OUTER;

<b>%OUTER</b>
</pre></html>/%

%/The reader should be able to extrapolate or simplify this arrangement by himself.
!!~LVARs and ~GVARs
~LVARs are stored in the current macro's own symbol table, and their value is retrieved from it. If such a table does not exist already, it is created when a new LVAR is defined (just a reference to a macro variable does not define it). ~GVARs are stored in the global symbol table, and their value is retrieved from that one. There is always a global symbol table./%
%/
:[img[Scope of LVAR and GVAR|data/images/SAS/SAS scope LVAR and GVAR.png]]/%

%/
!!~CVARs
A CVAR is retrieved from the closest symbol table that contains that macro variable, to start with the current macro's own local symbol table, then the local table of the nearest enclosing macro if any, then the local one of the second nearest enclosing macro if any, and so on up to the global symbol table./%
%/
:[img[Scope of CVAR|data/images/SAS/SAS scope CVAR.png]]/%

%/
!!~FVARs
The value of an FVAR is stored in the closest of all symbol tables containing that FVAR. If there is no such table, then the macro variable is stored in the current macro's own symbol table. If that table doesn't exist yet, it is created./%
%/
:[img[Scope of FVAR|data/images/SAS/SAS scope FVAR.png]]/%

%/
!!~SVARs
The value of an SVAR is stored in the closest of all symbol tables containing that SVAR. If there is no such table, then the macro variable is stored in the closest existing symbol table (in the last resort, the global symbol table).
:[img[Scope of SVAR|data/images/SAS/SAS scope SVAR.png]]/%
%/
Actually, the rules are slightly more complicated.{{ref{[[[2]|##2]]}}}/%

%/
!!Which type in which case?
The code example below covers most (if not all) situations you may have to deal with:
<html><pre>
%macro <b>INNER</b>(<span style="color:white; background-color:green"> LVAR1 </span>);
  %local <span style="color:white; background-color:green"> LVAR2 </span>;
  %global <span style="color:white; background-color:#aa0"> GVAR1 </span>;
  %let <span style="color:white; background-color:red"> FVAR1 </span> = ...;
  %put <span style="color:white; background-color:darkorange"> &=CVAR1 </span>;

  data ...;
    ... = symget(<span style="color:white; background-color:darkorange">'CVAR2'</span>);
    call symput(<span style="color:white; background-color:#b47">'SVAR1'</span>, ...);
    call symputx(<span style="color:white; background-color:#b47">'SVAR2'</span>, ...);
    call symputx(<span style="color:white; background-color:red">'FVAR2'</span>, ..., 'F');
    call symputx(<span style="color:white; background-color:#aa0">'GVAR2'</span>, ..., 'G');
    call symputx(<span style="color:white; background-color:green">'LVAR3'</span>, ..., 'L');
  run;

  proc sql;
    select ...
      into <span style="color:white; background-color:red"> :FVAR3 </span>
      from ...
      ;
  quit;
%mend INNER;

%macro <b>OUTER</b>;
  <b>%INNER</b>(...)
%mend OUTER;

<b>%OUTER</b>
</pre></html>/%

%/
One recommendation to conclude with: make the scope explicit where possible! That may spare you a lot of headache.

----
<html><a name="1">[1]</a></html>&nbsp; That's how it is depicted in the SAS Institute's own learning material for the official SAS certification exams. This would imply that there is no such thing as an empty local symbol table. The //SAS Help and Documentation// however speaks about a symbol table being empty when the macro has no local variables. From the programmer's perspective, it makes no difference. So let's be pragmatic for this occasion: consider //empty symbol table// = //no symbol table//.

<html><a name="2">[2]</a></html>&nbsp; ‘SAS Products’ > ‘Base SAS’ > ‘SAS 9.4 Macro Language Reference’ > ‘Understanding and Using the Macro Facility’ > ‘Scopes of Macro Variables’ > ‘Special Cases of Scope with the CALL SYMPUT Routine’ in the //SAS Help and Documentation// states:
<<<
Two rules control where CALL SYMPUT creates its variables: 
#CALL SYMPUT creates the macro variable in the current symbol table available while the DATA step is executing, provided that symbol table is not empty. If it is empty (contains no local macro variables), usually CALL SYMPUT creates the variable in the closest nonempty symbol table.
#However, there are three cases where CALL SYMPUT creates the variable in the local symbol table, even if that symbol table is empty:
**Beginning with SAS Version 8, if CALL SYMPUT is used after a PROC SQL, the variable will be created in a local symbol table.
**If the macro variable SYSPBUFF is created at macro invocation time, the variable will be created in the local symbol table.
**If the executing macro contains a computed %GOTO statement, the variable will be created in the local symbol table. A computed %GOTO statement is one that uses a label that contains an & or a % in it. That is, a computed %GOTO statement contains a macro variable reference or a macro call that produces a text expression. (...)
The symbol table that is currently available to a DATA step is the one that exists when SAS determines that the step is complete. (SAS considers a DATA step to be complete when it encounters a RUN statement, a semicolon after data lines, or the beginning of another step.)
<<<
The first case of rule 2 is the implication of PROC SQL creating some local macro variables SQL//<xxxxx>//. These rules don't only apply to the CALL SYMPUT routine, but to all SVAR situations in general.
//Tiddler// is de naam die wordt gegeven aan een eenheid van [[MicroContent]] in [[TiddlyWiki]]. Tiddlers zijn alom aanwezig in ~TiddlyWiki. Behalve de boodschap waar het uiteindelijk om begonnen is, zijn ook metadata (inhoudsopgaven, opmaakdefinities) en plugins met ~JavaScript uitgevoerd als tiddlers.

'Other systems have analogous concepts with more prosaic names: like "items", "entries", "entities". Even though "tiddler" is undoubtedly a silly name it at least has the virtue of being confusingly distinctive rather than confusingly generic.' Aldus [[Jeremy Ruston|http://www.tiddlywiki.com/]].
<<tiddler ReplaceTiddlerTitle with: "TiddlyWiki (TW)">>Een //wiki// (Hawaïaans voor 'vlug') is een webapplicatie waarmee webdocumenten gezamenlijk kunnen worden bewerkt. Gebruikers kunnen pagina's maken, bewerken, en onderling koppelen. Met dank aan Ward Cunningham.

[[TiddlyWiki|https://tiddlywiki.com/]] ('~LuttelVlug'), bedacht door [[Jeremy Ruston|https://jermolene.com/about]], wijkt op een paar punten fundamenteel af van het klassieke wikiconcept. Een ~TiddlyWiki-site bestaat niet uit aparte webpagina's, maar uit één pagina waarin tekstblokjes, [[tiddlers|Tiddler]] genaamd, met [[MicroContent]] kunnen worden geprojecteerd. De gehele ~TiddlyWiki-inhoud, -opmaak en -verwerkingslogica is opgeborgen in één ~{{z{HTML}}}-bestand. Een webserver is niet nodig, maar wel mogelijk. ~TiddlyWiki is niet echt geschikt voor gezamenlijke bewerking. De typische rolverdeling is: één schrijver schrijft, en het publiek (misschien alleen bestaand uit de schrijver zelf) leest. Zie ook de [[Engelse|https://en.wikipedia.org/wiki/TiddlyWiki]] en [[Nederlandse|https://nl.wikipedia.org/wiki/TiddlyWiki]] Wikipedia-pagina.

[['Een jaar of wat'|Hoe verder gekomen, hoe langer te gaan]] bouwt in technische zin voort op een reeks van eerdere publicaties begonnen in 2009, toen TW 2.5.0 de nieuwste versie was. [[Nadien|https://tiddlywiki.com/#History%20of%20TiddlyWiki]] heeft Ruston  TW grootser en geheel van de grond af aan herbouwd ("TiddlyWiki5 is a reboot of TiddlyWiki for the next 25 years"), zodat we nu (maart 2023) bij TW 5.2.5 zijn. Voor velen was dat een onoverkomelijke breuk met het verleden. Vandaar dat er destijds een afsplitsing heeft plaatsgevonden onder de noemer [[TiddlyWiki Classic|https://classic.tiddlywiki.com/]]. Die staat nu op versie 2.9.3. Ook ik draag de ballast van een voorgeschiedenis met me mee en heb weinig zin in herontwerp en -bouw van mijn bestaande TW's. Voor een nieuwe TW houd ik het dan eveneens maar bij klassiek.

TW community:
* [[Official hub for the TiddlyWiki community|https://tiddlywiki.org/]] met de [[TiddlyWiki 5 Discourse discussion group for end users|https://talk.tiddlywiki.org/]] 
* [[TiddlyWiki Classic (version 2.x.x) discussion group|https://groups.google.com/g/tiddlywikiclassic/]]

<<slider chkTWToevoegingen TW-toevoegingen "Toevoegingen aan deze TW ↕" "toon/verberg lijst van toevoegingen aan deze TiddlyWiki">>
/%
!info
|Name|ToggleBreadcrumbs|
|Source|http://www.TiddlyTools.com/#ToggleBreadcrumbs|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|enable/disable display of breadcrumbs (uses BreadcrumbsPlugin)|
Usage
<<<
{{{
<<tiddler ToggleBreadcrumbs>>
<<tiddler ToggleBreadcrumbs with: label tip>>
}}}
<<<
Example
<<<
{{{<<tiddler ToggleBreadcrumbs>>}}}
<<tiddler ToggleBreadcrumbs##show with: "show breadcrumbs">>
<<<
!end
!show
<<tiddler {{
	if (config.options.chkShowBreadcrumbs===undefined) config.options.chkShowBreadcrumbs=true;
'';}}>><<option chkShowBreadcrumbs>><<tiddler {{
	var chk=place.lastChild;
	if (!chk.coreOnChange) { // only once
		chk.coreOnChange=chk.onchange;
		chk.onchange=function() {
			if (this.coreOnChange) this.coreOnChange.apply(this,arguments);
			this.checked=config.options.chkShowBreadcrumbs;
			if (config.macros.breadcrumbs) config.macros.breadcrumbs.refresh();
		};
	}
'';}}>> $1
!end

%/<<tiddler {{var src='ToggleBreadcrumbs'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with:	{{'$1'!='$'+'1'?'$1':'show breadcrumbs'}}
	{{'$2'!='$'+'2'?'$2':'toggle breadcrumbs display'}}>>
/%
!info
|Name|ToggleLeftSidebar|
|Source|http://www.TiddlyTools.com/#ToggleLeftSidebar|
|Version|2.0.0//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide left sidebar (MainMenu)|
Usage
<<<
{{{
<<tiddler ToggleLeftSidebar>>
<<tiddler ToggleLeftSidebar with: label tooltip>>
}}}
Try it: <<tiddler ToggleLeftSidebar##show
	with: {{config.options.chkShowLeftSidebar?'◄':'►'}}>>
<<<
Configuration:
<<<
copy/paste the following settings into a tiddler tagged with <<tag systemConfig>> and then modify the values to suit your preferences:
{{{
config.options.chkShowLeftSidebar=true;
config.options.txtToggleLeftSideBarLabelShow="►";
config.options.txtToggleLeftSideBarLabelHide="◄";
}}}
<<<
!end
!show
<<tiddler {{
	var co=config.options;
	if (co.chkShowLeftSidebar===undefined) co.chkShowLeftSidebar=true;
	var mm=document.getElementById('mainMenu');
	var ww=document.getElementById('wwMain');       // extra
	var da=document.getElementById('displayArea');
	if (mm) {
		mm.style.display=co.chkShowLeftSidebar?'block':'none';
		ww.style.marginLeft=co.chkShowLeftSidebar?'220px':'20px';     // Meindert's choice
/*		da.style.marginLeft=co.chkShowLeftSidebar?'':'1em';  */
		da.style.marginLeft=co.chkShowLeftSidebar?'':'0';    // Meindert's choice
	}
'';}}>><html><nowiki><a href='javascript:;' title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var co=config.options;
	var opt='chkShowLeftSidebar';
	var show=co[opt]=!co[opt];
	var mm=document.getElementById('mainMenu');
	var ww=document.getElementById('wwMain');       // extra
	var da=document.getElementById('displayArea');
	if (mm) {
		mm.style.display=show?'block':'none';
		ww.style.marginLeft=show?'220px':'20px';  // Meindert's choice
/*		da.style.marginLeft=show?'':'1em';        */
		da.style.marginLeft=show?'':'0';          // Meindert's choice
	}
	saveOptionCookie(opt);
	var labelShow=co.txtToggleLeftSideBarLabelShow||'&#x25BA;';
	var labelHide=co.txtToggleLeftSideBarLabelHide||'&#x25C4;';
	if (this.innerHTML==labelShow||this.innerHTML==labelHide) 
		this.innerHTML=show?labelHide:labelShow;
	this.title=(show?'hide':'show')+' left sidebar';
	var sm=document.getElementById('storyMenu');
	if (sm) config.refreshers.content(sm);
	return false;
">$1</a></html>
!end
%/<<tiddler {{
	var src='ToggleLeftSidebar';
	src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
	var co=config.options;
	var labelShow=co.txtToggleLeftSideBarLabelShow||'&#x25BA;';
	var labelHide=co.txtToggleLeftSideBarLabelHide||'&#x25C4;';
	'$1'!='$'+'1'?'$1':(co.chkShowLeftSidebar?labelHide:labelShow);
}} {{
	var tip=(config.options.chkShowLeftSidebar?'hide':'show')+' left sidebar';
	'$2'!='$'+'2'?'$2':tip;
}}>>
/%
|Name|ToggleReadOnly|
|Source|http://www.TiddlyTools.com/#ToggleReadOnly|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|transclusion|
|Description|enable/disable global read-only state without reloading your document|

Usage: 
	<<tiddler ToggleReadOnly>> OR
	<<tiddler ToggleReadOnly with: label tip>>

!show
<html><nowiki><span class='button' style='cursor:pointer'
	onclick="this.getElementsByTagName('input')[0].click();" title="$2">
<input type='checkbox' style="margin:0;padding:0;" onclick="
	window.readOnly=this.checked;
	window.showBackstage=!window.readOnly;
	config.macros.option.propagateOption('chkHttpReadOnly','checked',window.readOnly,'input');
	if(showBackstage && !backstage.area) backstage.init();
	backstage.button.style.display=showBackstage?'block':'none';
	backstage.hide();
	story.switchTheme(config.options.txtTheme);
	refreshAll(); story.refreshAllTiddlers(true); // FORCE RE-DISPLAY
	return false;
">$1</span></html><<tiddler {{
	var chk=place.lastChild.getElementsByTagName('input')[0];
	chk.checked=window.readOnly;
'';}}>>
!end

%/<<tiddler ToggleReadOnly##show with:
	{{"$1"=="$"+"1"?"read-only":"$1"}}
	{{"$2"=="$"+"2"?"enable/disable editing functions":"$2"}}
>>
/%
!info
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|2.0.0//a//|
|Author|Eric Shulman, modified by [[Meindert Meindertsma]]|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide right sidebar (SideBarOptions)|
Usage
<<<
{{{
<<tiddler ToggleRightSidebar>>
<<tiddler ToggleRightSidebar with: label tooltip>>
}}}
Try it: <<tiddler ToggleRightSidebar##show
	with: {{config.options.chkShowRightSidebar?'►':'◄'}}>>
<<<
Configuration:
<<<
copy/paste the following settings into a tiddler tagged with <<tag systemConfig>> and then modify the values to suit your preferences:
{{{
config.options.chkShowRightSidebar=true;
config.options.txtToggleRightSideBarLabelShow="◄";
config.options.txtToggleRightSideBarLabelHide="►";
}}}
<<<
!end
!show
<<tiddler {{
	var co=config.options;
	if (co.chkShowRightSidebar===undefined) co.chkShowRightSidebar=true;
	var sb=document.getElementById('sidebar');
	var hd=document.getElementById('header');       // extra
	var da=document.getElementById('displayArea');
	if (sb) {
		sb.style.display=co.chkShowRightSidebar?'block':'none';
		hd.style.marginRight=co.chkShowRightSidebar?'':'0';    // Meindert's choice
/*		da.style.marginRight=co.chkShowRightSidebar?'':'1em';  */
		da.style.marginRight=co.chkShowRightSidebar?'':'0';    // Meindert's choice
	}
'';}}>><html><nowiki><a href='javascript:;' title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var co=config.options;
	var opt='chkShowRightSidebar';
	var show=co[opt]=!co[opt];
	var sb=document.getElementById('sidebar');
	var hd=document.getElementById('header');       // extra
	var da=document.getElementById('displayArea');
	if (sb) {
		sb.style.display=show?'block':'none';
		hd.style.marginRight=show?'':'0';    // Meindert's choice
/*		da.style.marginRight=show?'':'1em';  */
		da.style.marginRight=show?'':'0';    // Meindert's choice
	}
	saveOptionCookie(opt);
	var labelShow=co.txtToggleRightSideBarLabelShow||'&#x25C4;';
	var labelHide=co.txtToggleRightSideBarLabelHide||'&#x25BA;';
	if (this.innerHTML==labelShow||this.innerHTML==labelHide) 
		this.innerHTML=show?labelHide:labelShow;
	this.title=(show?'hide':'show')+' right sidebar';
	var sm=document.getElementById('storyMenu');
	if (sm) config.refreshers.content(sm);
	return false;
">$1</a></html>
!end
%/<<tiddler {{
	var src='ToggleRightSidebar';
	src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
	var co=config.options;
	var labelShow=co.txtToggleRightSideBarLabelShow||'&#x25C4;';
	var labelHide=co.txtToggleRightSideBarLabelHide||'&#x25BA;';
	'$1'!='$'+'1'?'$1':(co.chkShowRightSidebar?labelHide:labelShow);
}} {{
	var tip=(config.options.chkShowRightSidebar?'hide':'show')+' right sidebar';
	'$2'!='$'+'2'?'$2':tip;
}}>>
/%
!info
|Name|ToggleSliders|
|Source|http://www.TiddlyTools.com/#ToggleSliders|
|Version|2.0.0//a//|
|Author|Eric Shulman, modified by //Meindert Meindertsma// -- see comment at bottom|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|toggle (expand/collapse) all sliders in a tiddler (or ID'd DOM element)|
Usage
<<<
{{{
<<tiddler ToggleSliders with: elementID expandlabel collapselabel tooltip>>
}}}
*''elementID'' is one of:
**"" (empty quotes) = the current tiddler
**''here'' = the current container
**''ID'' = specific DOM element ID (e.g., "mainMenu")
*''expandlabel'' (optional)<br>alternative link text to display when sliders are closed 
*''collapselabel'' (optional)<br>alternative link text to display when sliders opened (collapselabel) 
*''tooltip'' (optional)<br>tooltip to display when hovered
<<<
Example
<<<
{{{
<<tiddler ToggleSliders with: "" "open all" "close all" "Open/collapse all sliders in this tiddler">>
}}}
with sample sliders:
{{{
<<slider chkExample ToggleSliders::Slider1 Example1 Example1>>
<<slider chkExample ToggleSliders::Slider2 Example2 Example2>>
Slider1: |This is example slider 1|
Slider2: |This is example slider 2|
}}}
<<tiddler ToggleSliders##show with: "" "open all" "close all" "Open/collapse all sliders in this tiddler">>
<<slider chkExample1 ToggleSliders::Slider1 Example1 Example1>>
<<slider chkExample2 ToggleSliders::Slider2 Example2 Example2>>
<<<
!end

!show
<html><a href="javascript:;" class="TiddlyLink" title="$4"
onclick="
	if ('$1'=='here') var here=this.parentNode.parentNode.parentNode.parentNode; // container
	else if ('$1'!='$'+'1' && '$1'.length) here=document.getElementById('$1'); // ID
	else var here=story.findContainingTiddler(this); // tiddler
	if (!here) return false;
	var elems=here.getElementsByTagName('*');
	var state=(this.innerHTML.toLowerCase()=='$2')?'none':'block';
	for (var e=0; e<elems.length; e++) { var p=elems[e];
		if (p.className!='sliderPanel' || p.style.display!=state) continue;
		if (p.button) window.onClickNestedSlider({target:p.button}); // see NestedSlidersPlugin
		else p.previousSibling.onclick();
	}
	this.innerHTML=state=='none'?'$3':'$2';
	return false;
">$2</a><nowiki></html>
!end
%/<<tiddler {{ var src='ToggleSliders'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with:	"$1"
		{{"$2"!='$'+'2'?"$2":'expand'}}
		{{"$3"!='$'+'3'?"$3":'collapse'}}
		{{"$4"!='$'+'4'?"$4":'toggle sliders'}}
>>/%

Corrections 2021-02-05
* Usage section: fourth argument added
* Example section: slice keys 'Example1' and 'Example2' replaced with 'Slider1' and 'Slider2'
* !show section: title attribute of <a> element parametrized
* Last call of tiddler macro: double brackets around $1 and singlequotes around $2, $3, $4 replaced with doublequotes 

%/
|~ViewToolbar|collapseTiddler collapseOthers _closeTiddler closeOthers +editTiddler > snapshotSave permalink fields references jump|
|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|
/***
Addition to the original macro: mark ''{{hi{{{{_}}}}}}'' puts command label in class {{hitt{markedCommand}}}./%

%/
!!toolbar
***/
//{{{
config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	for(var t=0; t<params.length; t++) {
		var c = params[t];
		switch(c) {
		case '>':
			var btn = createTiddlyButton(place,this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore);
			addClass(btn,"moreCommand");
			var e = createTiddlyElement(place,"span",null,"moreCommand");
			e.style.display = "none";
			place = e;
			break;
		default:
			var className = "";
			switch(c.substr(0,1)) {
			case "+":
				className = "defaultCommand";
				c = c.substr(1);
				break;
			case "-":
				className = "cancelCommand";
				c = c.substr(1);
				break;
			case "_":
				className = "markedCommand";
				c = c.substr(1);
				break;
			}
			if(c in config.commands)
				this.createCommand(place,c,tiddler,className);
			break;
		}
	}
};
//}}}
The Windows Script Host (version 5.7) lacks{{{ Try...Catch...Finally }}}blocks, but thanks to the OOP facilities of ~VBScript you can simulate such a functionality by yourself without messing around with{{{ On Error }}}statements. The essence of the trick is: a runtime error inside an event just interrupts the event, not the entire script. Let's see how to exploit this phenomenon. The script below
<html><pre>
<font color=purple><b>Class MyBlock</b></font>
<font color=red>  <b>Private Sub Class_Initialize</b>                             ' <---------------- <i>Try</i>
    WScript.Echo "Starting..."
    Dim i : i = 1 / 0
    WScript.Echo "Should not see this."
  <b>End Sub</b></font>
<font color=green>  <b>Private Sub CatchError</b> : If Err.Number = 0 Then Exit Sub ' <---------------- <i>Catch</i>
    Select Case Err.Number
      Case 11 WScript.Echo "Division by zero handled!"
      Case Else WScript.Echo Unhandled error " & Err.Number & " occurred."
    End Select
  <b>End Sub</b></font>
<font color=blue>  <b>Private Sub Class_Terminate</b> : CatchError                 ' <---------------- <i>Finally</i>
    WScript.Echo "Done."
  <b>End Sub</b></font>
<font color=purple><b>End Class</b></font>

Dim goMyBlock : Set goMyBlock = New <b>MyBlock</b> : Set goMyBlock = Nothing
</pre></html>/%
%/does the following:
* {{{Set goMyBlock = New MyBlock }}}=> new event
* automatic object constructor call{{{ Class_Initialize}}}
* {{{WScript.Echo "Starting..."}}}
* {{{i = 1 / 0}}}, raising error 11, aborting{{{ Class_Initialize}}} and returning to main program
* {{{Set goMyBlock = Nothing }}}=> new event
* automatic object destructor call{{{ Class_Terminate}}}
* call{{{ CatchError}}}
* {{{WScript.Echo "Division by zero handled!" }}}because of error 11
* end of{{{ CatchError}}}, so returning to{{{ Class_Terminate}}}
* {{{WScript.Echo "Done."}}}
* end of{{{ Class_Terminate}}}, so returning to main program
* end of script
An anonymous{{{ MyBlock }}}instance will do the job as well, so you can spare yourself a variable and a few keystrokes by replacing the last line in the above example with:
<html><pre>
With New <b>MyBlock</b> : End With
</pre></html>/%
%/See also [[ERRORLEVEL / exit code / return code in VBScript]].

(Based on http://my.opera.com/Lee_Harvey/blog/2007/04/21/try-catch-finally-in-vbscript-sure)
!!!IPA
;Standaard lettertype in deze ~TiddlyWiki:
:{{_{'t Rovaal Digitaal = [&#x0259;&#x0306;t &#x0280;ova&#x02D0;&#x026B; di&#x0263;ita&#x02D0;&#x026B;]
't RD = [&#x0259;&#x0306;t &#x025C;&#x0279;de&#x02D0;]}}}
;Lettertype met behoorlijke ondersteuning van Unicode {{n{(class="uniserif")}}}:
:{{uniserif{'t Rovaal Digitaal = [&#x0259;&#x0306;t &#x0280;ova&#x02D0;&#x026B; di&#x0263;ita&#x02D0;&#x026B;]
't RD = [&#x0259;&#x0306;t &#x025C;&#x0279;de&#x02D0;]}}}
;Idem wat groter {{n{(class="uniserif h6")}}}:
:{{uniserif h6{'t Rovaal Digitaal = [&#x0259;&#x0306;t &#x0280;ova&#x02D0;&#x026B; di&#x0263;ita&#x02D0;&#x026B;]
't RD = [&#x0259;&#x0306;t &#x025C;&#x0279;de&#x02D0;]}}}
;Idem nog wat groter {{n{(class="uniserif h4")}}}:
:{{uniserif h4{'t Rovaal Digitaal = [&#x0259;&#x0306;t &#x0280;ova&#x02D0;&#x026B; di&#x0263;ita&#x02D0;&#x026B;]
't RD = [&#x0259;&#x0306;t &#x025C;&#x0279;de&#x02D0;]}}}/%

%/
!!!Combining diacritical marks
Letter ''j'' met U+0301: {{hi6 r sh{''Jíj&#x0301;''}}}
/***
|Name|UnsavedChangesPlugin|
|Source|http://www.TiddlyTools.com/#UnsavedChangesPlugin|
|Version|3.3.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|show droplist of tiddlers that have changed since the last time the document was saved|
Display a list of tiddlers that have been changed since the last time the document was saved.  The list includes all new/modified tiddlers as well as those changed with "minor edits" enabled and any tiddlers that you import during the session, regardless of their modification date.
!!!!!Usage
<<<
{{{
<<unsavedChanges panel>> or <<unsavedChanges>>
}}}
{{indent{
the ''panel'' keyword displays a 'control panel' interface containing a droplist of unsaved tiddlers and a 'goto' button, along with a command link to 'save changes'.  Depending upon what other plugins are installed, several additional elements will also be displayed: When [[NestedSlidersPlugin]] is installed, the entire control panel is contained within a ''SLIDER''.  When [[LoadTiddlersPlugin]] is installed, a ''REVERT'' button is added.  When [[SaveAsPlugin]] is installed, a ''SAVE AS'' link is added.  When [[UploadPlugin]] is installed, an ''UPLOAD'' (or ''save to web'') link is added.  When [[TrashPlugin]] is installed and there are tiddlers tagged with<<tag Trash>>, an ''EMPTY TRASH'' link is added.
}}}
{{{
<<unsavedChanges list separator>>
}}}
{{indent{
the ''list'' keyword displays a simple space-separated list of unsaved tiddlers without any other command links.  You can specify an optional ''separator'' value that can be used in place of the default space character.  For example, you can specify {{{"<br>"}}} as the separator in order to display each link, one per line.
}}}
{{{
<<unsavedChanges command label tip>>
}}}
{{indent{
the ''command'' keyword displays a single 'command link' that, when clicked, displays a ~TiddlyWiki popup containing the list of unsaved tiddlers, the 'save changes' command and, depending upon what other plugins are installed, additional commands for 'save as', 'upload', and 'empty trash' (similar to the panel display described above).

You can specify optional ''label'' and ''tip'' parameters in the macro to customize the command link text and tooltip.  The default label for the command link is: "There %1 %0 unsaved tiddler%2...", where:
* %0 is automatically replaced with the number of unsaved changes
* %1 is either "is" (if changes=1) or "are" (if changes>1)
* %2 is either blank (if changes=1) or "s" (if changes>1)
resulting in the text: //"There is 1 unsaved tiddler...", "There are 2 unsaved tiddlers...", etc.//
}}}
<<<
!!!!!Examples
<<<
^^//note: the following examples will not display any output unless you have already created/modified tiddlers in the current document.//^^
{{{<<unsavedChanges>>}}}
<<unsavedChanges>>
----
{{{<<unsavedChanges command>>}}}
<<unsavedChanges command>>
----
{{{<<unsavedChanges list>>}}}
<<unsavedChanges list>>
----
{{{<<unsavedChanges list "<br>">>}}}
<<unsavedChanges list "<br>">>
<<<
!!!!!Revisions
<<<
2011.11.27 3.3.6 in panel(), command(), and list(), check for null 'place' (maybe caused if tiddlers are modified by a plugin during startup 'init' handling)
2011.04.29 3.3.5 in panel(), use custom label (if provided).  Also, removed "small" style from panel commands so surrounding CSS font size will be used.
2010.12.05 3.3.4 display 'save as...' command even if readOnly
2009.03.02 3.3.3 fix handling for titles that contain HTML special chars (lt,gt,quot,amp)
2008.09.02 3.3.2 cleanup popup list output generation and added timestamps/sizes to popup display
2008.08.23 3.3.1 added optional custom 'label' and 'tip' params to 'command' mode and defined default values for mode, label, tip, and separator as object properties for I18N/L10N-readiness.
2008.08.21 3.3.0 complete re-write of rendering and refresh processing to support multiple instances and automatic self-refresh (no longer depends upon core refresh notifications)
2008.08.21 3.2.0 added 'command' option for link+popup as alternative to 'control panel' interface
2008.04.22 3.1.2 use SaveAsPlugin instead of obsolete NewDocumentPlugin to add "save as" link
2007.12.22 3.1.1 hijack removeTiddler() instead of low-level deleteTiddler() to correct tracking and refresh handling issues.  in saveTiddler(), check for 'tiddler rename' (title!=newtitle) and adjust list accordingly.
2007.12.21 3.1.0 added support for {{{<<unsavedChanges list separator>>}}} usage to unsaved tiddlers as a simple list of links, embedded in tiddler content (e.g., [[MainMenu]])
2007.12.20 3.0.0 rewrite to track ALL changed tiddlers, including imports and minor edits, regardless of saved modification dates.  Also, rewrote display logic to directly refresh macro output instead of triggering a page refresh.  The entire process is MUCH more efficient now.
2007.08.02 2.0.0 converted from inline script
2007.01.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.UnsavedChangesPlugin= {major: 3, minor: 3, revision: 6, date: new Date(2011,12,27)};

config.macros.unsavedChanges = {
	changed: [], // list of currently unsaved tiddler titles
	defMode: "panel",
	defSep: " ",
	defLabel: "There %1 %0 unsaved tiddler%2",
	defTip: "view a list of unsaved tiddler changes",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var wrapper=createTiddlyElement(place,"span",null,"unsavedChanges");
		wrapper.setAttribute("mode",params[0]||this.defMode);
		wrapper.setAttribute("sep",params[1]||this.defSep); // for 'list' mode
		wrapper.setAttribute("label",params[1]||this.defLabel); // for 'command' mode
		wrapper.setAttribute("tip",params[2]||this.defTip); // for 'command' mode
		this.render(wrapper);
	},
	render: function(wrapper) {
		removeChildren(wrapper); // make sure its empty
		if (!this.changed.length) return; // no changes = no output
		switch (wrapper.getAttribute("mode")) {
			case "command": this.command(wrapper); break;
			case "list": this.list(wrapper); break;
			case "panel": default: this.panel(wrapper); break;
		}
	},
	refresh: function() {
		var wrappers=document.getElementsByTagName("span");
		for (var w=0; w<wrappers.length; w++)
			if (hasClass(wrappers[w],"unsavedChanges"))
				this.render(wrappers[w]);
	},
	list: function(place) { // show simple list of unsaved tiddlers
		if (!place) return;
		wikify("[["+this.changed.join("]]"+place.getAttribute("sep")+"[[")+"]]",place);
	},
	command: function(place) { // show command link with popup list
		if (!place) return;
		var c=this.changed.length;
		var txt=place.getAttribute("label").format([c,c==1?'is':'are',c==1?'':'s']);
		var tip=place.getAttribute("tip");
		var action=function(ev) { if (!ev) var ev=window.event;
			var p=Popup.create(this); if (!p) return false;
			var d=createTiddlyElement(p,"div");
			d.style.whiteSpace="normal"; d.style.width="auto"; d.style.padding="2px";
			// gather pretty links for changed tiddlers
			var list=[]; var item=" &nbsp;[[%1 - %0 (%2 bytes)|%0]]&nbsp; ";
			for (var i=config.macros.unsavedChanges.changed.length-1; i>=0; i--) {
				var tid=store.getTiddler(config.macros.unsavedChanges.changed[i]);
				if (!tid) continue;
				var when=tid.modified.formatString('YYYY.0MM.0DD 0hh:0mm:0ss');
				list.push(item.format([tid.title,when,tid.text.length]));
			}
			wikify("@@white-space:nowrap;"+list.join("<br>")+"@@",d);
			var t="\n----\n";
			t+="@@white-space:nowrap;display:block;text-align:center; &nbsp;";
			if (!readOnly) {
				t+="<<saveChanges>>";
				t+=config.macros.saveAs?" | <<saveAs>>":"";
				t+=config.macros.upload?" | <<upload>>":"";
				t+=(config.macros.emptyTrash&&store.getTaggedTiddlers("Trash").length)?" | <<emptyTrash>>":"";
			} else {
				t+=config.macros.saveAs?"<<saveAs>>":"";
			}
			t+="&nbsp; @@";
			wikify(t,d);
			Popup.show();
			ev.cancelBubble=true; if(ev.stopPropagation)ev.stopPropagation();
			return(false);
		}
		createTiddlyButton(place,txt,tip,action,"button");
	},
	panel: function(place) { // show composite droplist+buttons+commands
		if (!place) return;
		// gather changed tiddlers (in reverse order by date - most recent first)
		var tids=[]; for (var i=this.changed.length-1; i>=0; i--)
			{ var t=store.getTiddler(this.changed[i]); if (t) tids.push(t); }
		tids.sort(function(a,b){return a.modified<b.modified?-1:(a.modified==b.modified?0:1);});
		// generate droplist items
 		var list=[]; var item='<option value="%0">%1 - %0 (%2 bytes)</option>';
		for (var i=tids.length-1; i>=0; i--) {
			var when=tids[i].modified.formatString('YYYY.0MM.0DD 0hh:0mm:0ss');
			list.push(item.format([tids[i].title.htmlEncode(),when,tids[i].text.length]));
		}
		// display droplist, buttons, and command links
		var out=''; var c=this.changed.length;
		var NSP=config.formatters.findByField("name","nestedSliders");
		var summary=place.getAttribute("label").format([c,c==1?'is':'are',c==1?'':'s']);
		out+=NSP?'+++(unsaved)['+summary+'|'+this.defTip+']...':(summary+"\n");
		out+='<html><form style="display:inline"><!--\
			--><select size="1" name="list" \
				title="select a tiddler to view" \
				onchange="var v=this.value; if (v.length) story.displayTiddler(null,v);"><!--\
			-->'+list.join('')+'<!--\
			--></select><!--\
			--><input type="button" value="goto" onclick="this.form.list.onchange();">';
		if (config.macros.loadTiddlers)  {
			out+='<input type="button" value="revert" \
				title="import the last saved version of this tiddler" \
				onclick="var v=this.form.list.value; if (!v.length) return; \
					var t=\'<\'+\'<loadTiddlers [[tiddler:\'+v+\']] \'; \
					t+=document.location.href; \
					t+=\' confirm force noreport>\'+\'>\'; \
					var e=document.getElementById(\'executeRevert\'); \
					if (e) e.parentNode.removeChild(e); \
					e=document.createElement(\'span\'); \
					e.id=\'executeRevert\'; \
					wikify(t,e);">';
		}
		out+='</form></html>';
		out+='\n{{nowrap{';
		if (!readOnly) {
			out+="<<saveChanges>>";
			out+=config.macros.saveAs?" | <<saveAs>>":"";
			out+=config.macros.upload?" | <<upload>>":"";
			out+=(config.macros.emptyTrash&&store.getTaggedTiddlers("Trash").length)?" | <<emptyTrash>>":"";
		} else {
			out+=config.macros.saveAs?"<<saveAs>>":"";
		}
		out+='}}}';
		out+=NSP?'===':'';
		wikify(out,place);
	}
};

// hijack store.saveTiddler() to track changes to tiddlers
if (store.showUnsaved_saveTiddler==undefined) {
	store.showUnsaved_saveTiddler=store.saveTiddler;
	store.saveTiddler=function(title,newtitle) {
		if (title!=newtitle) {
			var i=config.macros.unsavedChanges.changed.indexOf(title);
			if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove old from list
		} 
		var i=config.macros.unsavedChanges.changed.indexOf(newtitle);
		if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove new title from list
		config.macros.unsavedChanges.changed.push(newtitle); // add new title to END of list
		var t=this.showUnsaved_saveTiddler.apply(this,arguments);
		if (!this.notificationLevel) config.macros.unsavedChanges.refresh();
		return t;
	}
}

// hijack store.removeTiddler() to track changes to tiddlers
if (store.showUnsaved_removeTiddler==undefined) {
	store.showUnsaved_removeTiddler=store.removeTiddler;
	store.removeTiddler=function(title) {
		var i=config.macros.unsavedChanges.changed.indexOf(title);
		if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove from list
		this.showUnsaved_removeTiddler.apply(this,arguments);
		if (!this.notificationLevel) config.macros.unsavedChanges.refresh();
	}
}

// hijack store.setDirty() function to reset change list after file save
// note: do NOT hijack the prototype function.  This hijack should only be applied to
// the main 'store' instance only (i.e., don't refresh when loading temporary store
// as part of ImportTiddlers processing)
if (store.showUnsaved_setDirty==undefined) {
	store.showUnsaved_setDirty=store.setDirty;
	store.setDirty = function(flag) {
		var refresh=this.isDirty() && !flag; // 'dirty' to 'clean', force a refresh...
		this.showUnsaved_setDirty.apply(this,arguments); // but change the flag first.
		if (refresh) {
			config.macros.unsavedChanges.changed=[]; // clear changed list
			config.macros.unsavedChanges.refresh();
		}
	}
}
//}}}
How to make an argument of a ~VBScript subroutine or function optional? In ~VBScript, the {{{Optional}}} keyword, which allows some arguments to be left out in Visual Basic, is not implemented. This means that you must declare every argument that you want to use. This limitation can be worked around, however, by letting an Array simulate a variable-length argument list.

It is also possible to implement keyword arguments by a Dictionary or an Array. In the example below the Array-based approach is applied for both the optional positional parameters ({{{sZero}}}, {{{iOne}}}, {{{rTwo}}} and {{{bThree}}}) and the keyword parameters ({{{sAlpha}}} and {{{iBeta}}}):
{{{
' Script : MandOptKey.vbs
' Purpose: Example of a subroutine with positional arguments (mandatory plus
'          optional) and keyword arguments
' Author : Meindert Meindertsma
' Date   : 2013-01-19

Option Explicit

'---- Main ----'
BeFlexible "First test", Array(), Array()
WScript.Echo ""

BeFlexible "Second test", _
           Array("Zero", 1), _
           Array("Alpha", "Aleph")
WScript.Echo ""

BeFlexible "Third test", _
           Array("Zero", 1, 2.2, True), _
           Array("Alpha", "Aleph", "Beta", 2)
WScript.Echo ""

BeFlexible "Fourth test", _
           Array("Zero", 1, 2.2, True), _
           Array("Alpha", "Aleph", "Beta")
WScript.Echo ""

Dim goMapping
Set goMapping = ArrayToDictionary(Array("Alpha", "Aleph", "Beta", 2))
BeFlexible "Fifth test", _
           Array("Zero", 1, 2.2, True), _
           DictionaryToArray(goMapping)
WScript.Echo ""

'---- A flexible subroutine ----'
Sub BeFlexible(sMandatory, vaOptional, vaKeyed)
  '---- Defaults for optional and keyword arguments ----'
  Dim sZero, iOne, rTwo, bThree
  sZero  = "(blank)"
  iOne   = 0
  rTwo   = 0.0
  bThree = False

  Dim sAlpha, iBeta
  sAlpha = "(blank)"
  iBeta  = 0

  '---- Read optional arguments ----'
  If UBound(vaOptional) >= 0 Then sZero  = vaOptional(0)
  If UBound(vaOptional) >= 1 Then iOne   = vaOptional(1)
  If UBound(vaOptional) >= 2 Then rTwo   = vaOptional(2)
  If UBound(vaOptional) >= 3 Then bThree = vaOptional(3)

  '---- Read keyword arguments ----'
  Dim oMapping
  Set oMapping = ArrayToDictionary(vaKeyed)
  If oMapping.Exists("Alpha") Then sAlpha = oMapping("Alpha")
  If oMapping.Exists("Beta" ) Then iBeta  = oMapping("Beta" )

  '---- Write all subroutine parameters ----'
  WScript.Echo "sMandatory = " & sMandatory
  WScript.Echo "sZero      = " & sZero
  WScript.Echo "iOne       = " & iOne
  WScript.Echo "rTwo       = " & rTwo
  WScript.Echo "bThree     = " & bThree
  WScript.Echo "sAlpha     = " & sAlpha
  WScript.Echo "iBeta      = " & iBeta
End Sub

'---- Convert Array to Dictionary object ----'
Function ArrayToDictionary(vaKeyed)
  Dim oMapping, i
  Set oMapping = CreateObject("Scripting.Dictionary")

  For i = 1 to UBound(vaKeyed) Step 2
    oMapping.Add vaKeyed(i - 1), vaKeyed(i)
  Next

  Set ArrayToDictionary = oMapping
End Function

'---- Convert Dictionary object to Array ----'
Function DictionaryToArray(oMapping)
  Dim i, j, vKey, vaArray()
  i = 0

  For Each vKey In oMapping.Keys
    j = i + 1
    Redim Preserve vaArray(j)
    vaArray(i) = vKey
    vaArray(j) = oMapping(vKey)
    i = j + 1
  Next

  DictionaryToArray = vaArray
End Function
}}}
The third invocation of {{{BeFlexible}}} gives (with Dutch regional settings):
{{{
sMandatory = Third test
sZero      = Zero
iOne       = 1
rTwo       = 2,2
bThree     = True
sAlpha     = Aleph
iBeta      = 2
}}}
Since ~VBScript does not support Dictionary object literals, the use of an Array with key/value pairs seems to be more practical at invocations of the subroutine or function.
Paragraaf 3.3.1 top-down in Welsh Rarebit-notatie:

<<eval [=[{{ml2em mr1em pref tt fblu{
//arithmeticExpr//       $--> //simpleArithmeticExpr//
                      $| //ifClause// //simpleArithmeticExpr// ''{{fbla{else}}}'' //arithmeticExpr//
//ifClause//             $--> ''{{fbla{if}}}'' //booleanExpr// ''{{fbla{then}}}''
//simpleArithmeticExpr// $--> //term//
                      $| //addingOperator// //term//
                      $| //simpleArithmeticExpr// //addingOperator// //term//
//term//                 $--> //factor//
                      $| //term// //multiplyingOperator// //factor//
//factor//               $--> //primary//
                      $| //factor// ''{{fbla{&uarr;}}}'' //primary//
//primary//              $--> //unsignedNumber//
                      $| //variable//
                      $| //functionDesignator//
                      $| ''{{fbla{(}}} ''//arithmeticExpr// ''{{fbla{)}}}''
//addingOperator//       $--> ''{{fbla{+}}}'' $| ''{{fbla{-}}}''
//multiplyingOperator//  $--> ''{{fbla{&times;}}}'' $| ''{{fbla{/}}}'' $| ''{{fbla{&#xf7;}}}''
}}}]=]>>
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span>&nbsp; (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<div class='toolbar toolbar2' macro='toolbar gotoTiddlerTop'></div>
<!--}}}-->
WikiWoord
KiwiWoord
[[WiwiKoord]]

[img[data/images/wiki.gif]]

|w40pct h30em|k
|background-image:url('data/images/wiki.gif');|
/%
!info
|Name|WithholdTiddlerTagging|
|Source|fork of Eric Shulman's HideTiddlerTags|
|Version|2.0.1//b//|
|Author|[[Meindert Meindertsma]]|
|License|(see HideTiddlerTags)|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|hide only the tiddler's 'tagging' display|
Usage:
<<<
{{{
<<tiddler WithholdTiddlerTagging>>
<<tiddler WithholdTiddlerTagging with: TiddlerTitle>>
}}}
<<<
!end
!show
<<tiddler {{
	var title="$1";
	if (title=='$'+'1') {
		var here=story.findContainingTiddler(place);
		if (here) title=here.getAttribute('tiddler');
	}
	var t=story.getTiddler(title); if (t) {
		var e=t.getElementsByTagName('*');
		for (var i=0; i<e.length; i++)
			if (hasClass(e[i],'tagging'))
				e[i].style.display='none';
	}
'';}}>>
!end
%/<<tiddler {{
	var src='WithholdTiddlerTagging';
	src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with: [[$1]]>>
/%
!info
|Name|WithholdTiddlerTags|
|Source|fork of Eric Shulman's HideTiddlerTags|
|Version|2.0.1//a//|
|Author|[[Meindert Meindertsma]]|
|License|(see HideTiddlerTags)|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|hide only the tiddler's 'tagged' display|
Usage:
<<<
{{{
<<tiddler WithholdTiddlerTags>>
<<tiddler WithholdTiddlerTags with: TiddlerTitle>>
}}}
<<<
!end
!show
<<tiddler {{
	var title="$1";
	if (title=='$'+'1') {
		var here=story.findContainingTiddler(place);
		if (here) title=here.getAttribute('tiddler');
	}
	var t=story.getTiddler(title); if (t) {
		var e=t.getElementsByTagName('*');
		for (var i=0; i<e.length; i++)
			if (hasClass(e[i],'tagged') && !hasClass(e[i],'pseudo'))
				e[i].style.display='none';
	}
'';}}>>
!end
%/<<tiddler {{
	var src='WithholdTiddlerTags';
	src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with: [[$1]]>>
XML (eXtendable Markup Language) is tegenwoordig //de// standaard voor gegevensuitwisseling, leesbaar voor zowel machine als mens. Ondanks het feit dat het een vereenvoudiging is van SGML (Standard Generalized Markup Language), kunnen er ongelofelijk dikke boeken met een hoge informatiedichtheid per bladzijde over worden geschreven. Op deze plaats zullen slechts enkele essenties aan bod komen.

Een gegeven kan worden ingepakt in begin- en eindtags, waarmee iets over de aard van dat gegeven wordt gezegd. Het resulterende pakket wordt een ~XML-element genoemd:
{{{
<question>To be or not to be?</question>
}}}
Een ~XML-element kan op zijn beurt, eventueel samen met andere ~XML-elementen, weer worden ingepakt tot een groter geheel:
{{{
<scene> ... <question>To be or not to be?</question> ... </scene>
}}}
Op deze manier ontstaan geneste structuren. Daarnaast is er nog een andere manier om gegevens op te bergen, namelijk als attribuut in de tag zelf:
{{{
<question type="rhetorical" speaker="Hamlet">To be or not to be?</question>
}}}
Dat is een van de punten waarop XML wordt bekritiseerd: wanneer moet je informatie insluiten tussen de tags, en wanneer als attribuut in de begintag opnemen? Bovenstaand voorbeeld had net zo goed op onderstaande wijze kunnen worden uitgewerkt:
{{{
<question>
  <type>rhetorical</type>
  <speaker>Hamlet</speaker>
  <spoken>To be or not to be?</spoken>
</question>
}}}
Merk op dat hier ook iets aan de layout is gedaan, om het voor het menselijk oog wat toegankelijker te maken. Voor een ~XML-parser hebben de extra spaties en regelovergangen geen betekenis.

Omdat XML in zijn totaliteit zo complex is en de leesbaarheid voor mensen ook niet overhoudt, zijn er bevattelijker alternatieven bedacht. Zie [[XML, YAML en JSON]] voor een vergelijking met twee andere populaire formaten.
![[XML]]
{{{
<!DOCTYPE glossary PUBLIC "-//OASIS//DTD DocBook V3.1//EN">
  <glossary><title>example glossary</title>
    <GlossDiv><title>S</title>
      <GlossList>
        <GlossEntry ID="SGML" SortAs="SGML">
          <GlossTerm>Standard Generalized Markup Language</GlossTerm>
          <Acronym>SGML</Acronym>
          <Abbrev>ISO 8879:1986</Abbrev>
          <GlossDef>
            <para>A meta-markup language, used to create markup
languages such as DocBook.</para>
            <GlossSeeAlso OtherTerm="GML">
            <GlossSeeAlso OtherTerm="XML">
          </GlossDef>
          <GlossSee OtherTerm="markup">
        </GlossEntry>
      </GlossList>
    </GlossDiv>
  </glossary>
}}}
![[YAML]]
{{{
---
glossary:
  title: example glossary
  GlossDiv:
    title: S
    GlossList:
      GlossEntry:
        ID: SGML
        SortAs: SGML
        GlossTerm: Standard Generalized Markup Language
        Acronym: SGML
        Abbrev: ISO 8879:1986,
        GlossDef:
          para:
            A meta-markup language, used to create markup
            languages such as DocBook.
          GlossSeeAlso:
          - GML
          - XML
        GlossSee: markup
}}}
![[JSON]]
{{{
{
  "glossary": {
    "title": "example glossary",
    "GlossDiv": {
      "title": "S",
      "GlossList": {
        "GlossEntry": {
          "ID": "SGML",
          "SortAs": "SGML",
          "GlossTerm": "Standard Generalized Markup Language",
          "Acronym": "SGML",
          "Abbrev": "ISO 8879:1986",
          "GlossDef": {
            "para": "A meta-markup language, used to create markup languages such as DocBook.",
            "GlossSeeAlso": ["GML", "XML"]
          },
          "GlossSee": "markup"
        }
      }
    }
  }
}
}}}
Zolang een ~JSON-uitdrukking geen commentaar bevat (tussen ''{{{/*}}}'' en ''{{{*/}}}''), is het tevens een geldige (flow style) ~YAML-uitdrukking.
YAML ("YAML Ain't Markup Language", oorspronkelijk "Yet Another Markup Language", spreek uit //jemmel//) is een lichtgewicht data-serialisatieformaat, dat vooral mikt op leesbaarheid en schrijfbaarheid voor mensen, maar zich tevens goed leent voor machinale verwerking. Een ~YAML-document oogt vaak niet veel anders dan een boodschappenlijstje:
{{{
- 2 kilo peren
- 1 perforator
- 1 piano
- half pond nougat
- 3 pakken Brinta
}}}
YAML kent drie soorten bouwstenen: scalaire waarden (strings, getallen e.d.), sequences (arrays) en mappings (hashes); gegevenstypen die //agile// programmeertalen zoals [[Perl]], Python, PHP, [[Ruby]] en ~JavaScript gemeen hebben. Bovenstaand voorbeeld is een sequence van strings. Een mapping is een verzameling van sleutel/waarde-paren. Overal waar een scalaire waarde kan voorkomen, kan ook een sequence of een mapping worden geplaatst, wat geneste constructies mogelijk maakt:
{{{
---
naam: mw. Donkersloot
boodschappen:
- 2 kilo peren
- 1 perforator
- 1 piano
- half pond nougat
- 3 pakken Brinta
opmerking: tussen de middag bezorgen
---
naam: dhr. Vliegenthart
boodschappen:
- overgordijnen
- 3 kilo Engelse drop (zonder blauwe)
- 65 g uien
- dakpannen
- 1 waterpomptang
- varkenshaasje
- boek:
    auteur: W.F. Hermans
    titel: Ik heb altijd gelijk
- 2 NCRV-gidsen  # moeten waarschijnlijk wel actueel zijn!
---
naam: mw. De Wit
boodschappen: [2 ons katenspek, 1 stuks Nieuwe Revu, luiwagen, 1 ossetong]
}}}
Dit zijn drie logische ~YAML-documenten, herkenbaar aan de "''{{{---}}}''"-markeringen, in &eacute;&eacute;n stream. Het tweede document bevat op het hoogste niveau een mapping met de sleutels ''{{{naam}}}'' en ''{{{boodschappen}}}'', waarbij ''{{{boodschappen}}}'' een sequence als waarde heeft. Het zevende item in deze sequence is een mapping met &eacute;&eacute;n element ''{{{boek}}}'', dat als waarde een mapping met twee elementen heeft.

Het inspringen is een essentieel onderdeel van YAML: dit geeft aan hoe de nesting in elkaar steekt. Naast deze zogeheten //block style// kent YAML ook nog een //flow style//, welke hierboven bij de boodschappen voor mevrouw De Wit is toegepast. En het boek voor meneer Vliegenthart had evengoed aldus kunnen worden gespecificeerd:
{{{
- boek: {auteur: W.F. Hermans, titel: Ik heb altijd gelijk}
}}}
Alle regelinhoud achter het ''{{{#}}}''-teken is commentaar en wordt door de ~YAML-parser genegeerd. De opmerking over de actualiteit van de ~NCRV-gidsen is dus alleen voor menselijke waarneming bedoeld. Komen er in een string tekens voor die in die context als ~YAML-token zouden kunnen worden opgevat, dan zijn deze voor een dergelijke interpretatie af te schermen door de gehele string tussen enkele of dubbele aanhalingstekens te zetten.

Hoewel YAML toch net iets complexer is dan hier gesuggereerd, is het oneindig veel eenvoudiger dan [[XML]], wat in 2001 ook de uitdrukkelijke opzet van de bedenkers (Clark Evans, Brian Ingerson alias Ingy d&ouml;t Net, en Oren ~Ben-Kiki) was. Nadien is het accent wat verschoven van document-markup naar data-serialisatie, vandaar de nieuwe betekenis die aan het ~YAML-acroniem is gegeven. YAML wordt bovendien veel gebruikt voor configuratiebestanden, met name bij Ruby-applicaties. Zie de [[officiële YAML-website|http://www.yaml.org/]], en voor een vergelijking met andere populaire formaten de tiddler [[XML, YAML en JSON]].
''{{up1px sans{<<showPopup tiddler:[[} Zichtbaarheid van Python-variabelen]] label: "Bundel ↘">>}}}''

<<tiddler [[{}::togglesliders]]>> Zoals de meeste procedurele talen tegenwoordig werkt ook Python met //lexical scoping//. Dat houdt in, dat de plaats waar een variabele in de broncode voorkomt de scope ervan bepaalt.{{ref{[[[1]|##1]]}}} In het Nederlands wordt ook wel van 'bereik' of 'zichtbaarheid' gesproken. Python kent vier scopes. Tijdens de uitvoering van een programma geldt voor het opzoeken van de juiste variabelen de zogenaamde ''LEGB''-regel:{{ref{[[[2]|##2]]}}}/%
%/
* {{_{@@bgcolor:#ffe2b7;{{hws{''L''ocal scope}}}@@: Lokale variabelen van een functie, d.w.z. alle functieparameters en -- voor zover niet als {{tt t{nonlocal}}} of {{tt t{global}}} gedeclareerd -- alle variabelen waar binnen de functie een waarde aan is toegekend. Lokale variabelen zijn van buitenaf niet waarneembaar, maar van binnenuit wel (zie volgende punt 'Enclosing scope').
&nbsp; &nbsp; &nbsp; Of een variabele als lokaal moet worden opgevat, wordt in compilatietijd bepaald, terwijl de daadwerkelijke aanmaak ervan pas tijdens de uitvoering geschiedt. De consequentie hiervan is, dat de constructie ''{{pref hitt z{if False: answer = 42}}}'' binnen een functiedefinitie wel declareert dat een eventuele variabele met de naam {{tt t{answer}}} lokaal is (als dat niet al eerder duidelijk was gemaakt), maar deze niet creëert wanneer ze nog niet bestaat.
&nbsp; &nbsp; &nbsp; De ingebouwde functie {{tt t{locals}}} produceert, indien aangeroepen vanuit een functie, een dictionary van alle strikt lokale variabelen van die functie plus de binnen de functie aangesproken niet-lokale variabelen (zie ook weer het volgende punt). Wanneer {{tt t{locals}}} wordt aangeroepen op moduleniveau, is de uitkomst gelijk aan die van de eveneens ingebouwde functie {{tt t{globals}}}.}}}
* @@bgcolor:#ffffb5;{{hws{''E''nclosing scope}}}@@: Lokale variabelen van nul of meer omvattende functies. Doorgaans worden er geen functies binnen een andere functie gedefinieerd, maar het komt wel voor. Meer dan één omvattende functie is echter een zeldzaamheid. Vanuit een binnenliggende functie bekeken worden dergelijke variabelen 'niet-lokaal' oftewel 'nonlocal' genoemd.{{ref{[[[3]|##3]]}}}
* {{_{@@bgcolor:#e0f5e9;{{hws{''G''lobal scope}}}@@: Globale variabelen die binnen een module zijn gedefinieerd door er een waarde aan te toe te kennen. De term 'globaal' is nogal pretentieus, want verschillende modules kunnen elkaars variabelen niet direct zien. De module {{tt t{sys}}} bijvoorbeeld bevat een globale variabele {{tt t{argv}}} (__arg__ument __v__ector). Na ''{{pref hitt z{import sys}}}'' in het hoofdprogramma is {{tt t{argv}}} van daaruit niet direct zichtbaar, maar wel via de gekwalificeerde naam ''{{pref hitt z{sys.argv}}}'' te benaderen (zie ook [[Geneste Python-modules]]). Was er voor ''{{pref hitt z{from sys import argv}}}'' gekozen, dan zou daarmee een nieuwe globale variabele {{tt t{argv}}}, die verwijst naar hetzelfde object als de gelijknamige variabele in {{tt t{sys}}}, aan de huidige module zijn toegevoegd.
&nbsp; &nbsp; &nbsp; De ingebouwde functie {{tt t{globals}}} produceert een dictionary van alle globale variabelen in de module waarin deze functie is aangeroepen. Ook als de aanroep van {{tt t{globals}}} plaatsvindt in een functie, zijn de geretourneerde variabelen die van de module waarin de desbetreffende functie gedefinieerd was.}}}
* @@bgcolor:#d6e6f3;{{hws{''B''uilt-in scope}}}@@: De in Python ingebouwde variabelen. Voor het merendeel betreft dit classes en functies.{{ref{[[[4]|##4]]}}}/%
%/
Het toekennen van een waarde aan een lokale of globale variabele kan op verschillende manieren:
* via een toekenningsstatement of -expressie
* via een {{tt t{import}}}-statement
* via een {{tt t{from}}}-statement/%
%/
In onderstaande schema is de zichtbaarheid van een aantal denkbeeldige en bestaande variabelen in beeld gebracht. De binnenste functie ziet alleen de zwarte variabelenamen. De gekleurde variabelenamen zijn afgedekt door de gelijknamige zwarte en daardoor vanuit die functie niet meer rechtstreeks bereikbaar.

{{ml3em hdn{[img[data/images/Python-scopes-LEGB.png]]}}}

Op moduleniveau ziet het blikveld er anders uit:

{{ml3em hdn{[img[data/images/Python-scopes-GB.png]]}}}

Globale en ingebouwde variabelen die door meer nabije variabelen zijn afgedekt kunnen via een klein omweggetje alsnog worden benaderd. Globale variabelen zijn daarbij bovendien te muteren, te creëren en te verwijderen. +++(~Python_omweg1)[Voorbeeld 1: &darr;|show][Voorbeeld 1: &uarr;|hide]
{{lf w55pct pre{
{{fgre{"""# Script: detour.py
# Date  : 2023-06-28, Meindert Meindertsma

#---- charlie and other globals ----#"""}}}"""
import sys
"""''"""m = sys.modules[__name__]"""''"""

charlie = 2
yankee  = 25
print("m: charlie   =", charlie)
print("m: yankee    =", yankee)

def f():
    charlie = True
    print("f: charlie   =", charlie)
    print("f: m.charlie =", """''m.charlie''""")
    print("f: m.yankee  =", """''m.yankee''""")
    """''m.charlie''""" += 1
    del """''m.yankee''"""
    """''m.zulu''""" = 26
    print("f: m.charlie =", """''m.charlie''""")
    print("f: m.zulu    =", """''m.zulu''""")

f()
print("m: charlie   =", charlie)
try: print("m: yankee    =", yankee)
except Exception as e: print("Error:", e)
print("m: zulu      =", zulu)
"""
{{fgre{"""#---- divmod ----#"""}}}"""
divmod = 0
print("\nm: divmod                      =", divmod)
print("m: __builtins__.divmod         =", """''"""__builtins__.divmod"""''""")
print("m: __builtins__.divmod(42, 11) =", """''"""__builtins__.divmod"""''(42, 11))
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w40pct{{{pre{
''Uitvoer''
"""
m: charlie   = 2
m: yankee    = 25
f: charlie   = True
f: m.charlie = 2
f: m.yankee  = 25
f: m.charlie = 3
f: m.zulu    = 26
m: charlie   = 3
Error: name 'yankee' is not defined
m: zulu      = 26

m: divmod                      = 0
m: __builtins__.divmod         = <built-in function divmod>
m: __builtins__.divmod(42, 11) = (3, 9)"""
}}}/%

%/In plaats van de eerste twee uitvoerbare programmaregels hadden onderstaande regels op dezelfde wijze van dienst kunnen zijn:
{{pre{
import inspect
''m = inspect.getmodule(type("", (), {}))''
}}}/%

%/Mocht je {{tt t{"""__builtins__"""}}} hebben afgedekt (een heel slecht idee&#x200a;!&#x200a;), dan is die gemakkelijk terug te halen, mits je dat tijdig doet:
{{pre low{
{{z{{{fgre{"""# Script: detour-to-builtins.py
# Date  : 2023-07-10, Meindert Meindertsma"""}}}
"""
print("__builtins__ =", __builtins__)

__builtins__ = 1                         """{{fgre{# 1st sabotage}}}"""
print("__builtins__ =", __builtins__)

import """''builtins''""" as __builtins__          """{{fgre{# 1st repair}}}"""
print("__builtins__ =", __builtins__)

def f(): print("__builtins__ =", __builtins__)
f()

__builtins__ = 2                         """{{fgre{# 2nd sabotage}}}"""
print("__builtins__ =", __builtins__)

def g(): print("__builtins__ =", __builtins__)

import """''builtins''""" as __builtins__          """{{fgre{# 2nd repair}}}"""
print("__builtins__ =", __builtins__)
g()
"""}}}
}}}/%
%/Met het eerste herstel via ''{{pref hitt z{import builtins as """__builtins__"""}}}'' komt het programma er nog genadig vanaf. Het tweede herstel komt te laat: de schade is al aangericht in de definitie van functie {{tt t{g}}}. De boel klapt met de foutmelding {{hitt z{TypeError: 'int' object is not subscriptable}}} in de aangeroepen {{tt t{g}}}-functie op de daarin vervatte {{tt t{print}}}-aanroep. Python probeerde op dat punt kennelijk de operatie ''{{pref hitt z{2['print']}}}'' uit te voeren.{{ref{[[[5]|##5]]}}}
}}}
{{clear block{}}}
===  +++(~Python_omweg2)[Voorbeeld 2: &darr;|show][Voorbeeld 2: &uarr;|hide]
{{lf w55pct pre{
{{fgre{"""# Script: detour-to-globals.py
# Date  : 2023-06-29, Meindert Meindertsma"""}}}
"""
charlie = 2
yankee  = 25
print("m: charlie      =", charlie)
print("m: yankee       =", yankee)

def f():
    charlie = True
    """''m = globals()''"""
    print('f: charlie      =', charlie)
    print('f: m["charlie"] =', """''m["charlie"]''""")
    print('f: m["yankee"]  =', """''m["yankee"]''""")
    """''m["charlie"]''""" += 1
    del """''m["yankee"]''"""
    """''m["zulu"]''""" = 26
    print('f: m["charlie"] =', m["charlie"])
    print('f: m["zulu"]    =', m["zulu"])

f()
print("m: charlie      =", charlie)
try: print("m: yankee       =", yankee)
except Exception as e: print("Error:", e)
print("m: zulu         =", zulu)"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w40pct{{{pre{
''Uitvoer''
"""
m: charlie      = 2
m: yankee       = 25
f: charlie      = True
f: m["charlie"] = 2
f: m["yankee"]  = 25
f: m["charlie"] = 3
f: m["zulu"]    = 26
m: charlie      = 3
Error: name 'yankee' is not defined
m: zulu         = 26"""
}}}/%

%/De programmeur mag dus wijzigingen in de dictionary van globale variabelen aanbrengen. Doe zoiets echter nooit met de dictionary die door de {{tt t{locals}}}-functie wordt aangeleverd. De Python-documentatie zegt daarover:
>''Note'': The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
}}}
{{clear block{}}}
=== Met niet-lokale variabelen kunnen zulke trucs niet worden uitgevoerd.

Buiten de vier genoemde scopes zijn er nog drie aparte gebieden waar de omringende code geen zicht op de interne identifiers van zo'n gebied heeft:
* @@bgcolor:#ffe2f2;{{hws{Comprehensionvariabelen}}}@@ zoals {{tt t{X}}} in ''{{pref hitt z{[X for X in I]}}}''.
* @@bgcolor:#ffe2f2;{{hws{Exceptionvariabelen}}}@@ zoals {{tt t{X}}} in ''{{pref hitt z{except E as X}}}''.
* @@bgcolor:#ffe2f2;{{hws{Classattributen}}}@@ in een {{tt t{class}}}-blok en @@bgcolor:#ffe2f2;{{hws{objectattributen}}}@@. Via gekwalificeerde namen ({{pref hitt z{//qualifier//''.''//attribute//}}}) zijn deze echter wel van buitenaf benaderbaar, inclusief de mogelijkheid er een andere waarde aan toe te kennen, nieuwe attributen in het leven te roepen of bestaande weg te gooien. Bedenk dat een module ook een object is. Het hier beschreven patroon is inderdaad net zo goed op modules van toepassing. Maar omgekeerd delen nonmodule-objecten niet in alle verworvenheden van modules. Zo blijken de binnen een class gedefinieerde functies en methods blind voor de attributen van die class, zie [[Zichtbaarheid van classattributen in Python]]. Die attributen moeten via een functieparameter -- meestal {{tt t{self}}} genoemd -- worden gekwalificeerd. Het valt ook op de volgende manier te verwoorden: de attributen van modules zijn volwaardige variabelen en de attributen van andersoortige objecten zijn dat niet.{{ref{[[[6]|##6]]&#x200a;[[[7]|##7]]&#x200a;[[[8]|##8]]}}}/%
%/
{{_{
Als 'globaal' je nog niet globaal genoeg is, kun je je eigen variabelen nog een graadje kosmopolitischer maken door ze in de module {{tt t{"""__builtins__"""}}} op te nemen. Een wat gewaagde en gelukkig nogal geschuwde kunstgreep, die ik alleen maar toepas in deze +++(~Python_KosmopolitischeVariabelen)[demonstratie. &darr;|show][demonstratie. &uarr;|hide]
{{lf w55pct{{{pre{
{{fgre{"""# Script: kilroy.py
# Date  : 2023-07-12, Meindert Meindertsma"""}}}
"""
__builtins__."""''look''""" = lambda: print("Kilroy was here", end=" ")
print(look.__class__)
"""''look''"""()
print()

import even_here
print("too")"""
}}}De inhoud van {{sans t{even_here.py}}} is niet meer dan:
{{pre{
''look''()
}}}}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w40pct{{{pre{
''Uitvoer''
"""
<class 'function'>
Kilroy was here
Kilroy was here too"""
}}}Het maakt niet uit waar de variabele aan {{tt t{"""__builtins__"""}}} wordt toegevoegd, in het hoofdprogramma of een van de geladen modules, het resultaat is dat die variabele voortaan vanuit iedere module direct bereikbaar is.
}}}
{{clear block{}}}
===
}}}
Evenmin erg populair zijn de eerder vermelde omwegfoefjes om afdekkingen te omzeilen. Vaker zie je de volgende constructies. Python kent twee declaraties waarmee een binnen de functie voorkomende naam vooraf als de naam van een globale of niet-lokale variabele is aan te merken:/%
%/
* {{_{{{hitt z{''global'' //namelist//}}}: alle in //namelist// genoemde variabelen zijn globaal. Deze declaratie moet vóór het eerste voorkomen van elk van deze variabelen in de functie worden opgenomen (gebruikelijk is om dat meteen maar aan het begin van de functie te doen), en wordt in compilatietijd verwerkt (het levert een syntax error op als de declaratie niet op de goede plaats staat). Het heeft geen zin om de declaratie voorwaardelijk te maken (bijvoorbeeld met ''{{pref hitt z{if False: global alpha}}}''), want louter de aanwezigheid van de declaratie in de code is al voldoende om de betrokken variabele(n) als globaal te doen gelden.
&nbsp; &nbsp; &nbsp; De aldus gedeclareerde variabelen hoeven niet te bestaan en worden bij afwezigheid ook niet door de declaratie gecreëerd. Pas bij een eerste waardetoekenning aan zo'n variabele (binnen of buiten de functie, maakt niet uit) wordt deze op moduleniveau aangemaakt.}}}
* {{hitt z{''nonlocal'' //namelist//}}}: alle in //namelist// genoemde variabelen zijn niet-lokaal. Deze declaratie moet vóór het eerste voorkomen van elk van deze variabelen in de functie worden opgenomen (gebruikelijk is om dat meteen maar aan het begin van de functie te doen). Evenals het {{tt t{global}}}-statement wordt deze declaratie in compilatietijd verwerkt, met alle genoemde consequenties van dien. Toch is er één belangrijk verschil: de betrokken variabelen moeten //wel// reeds bestaan&#x200a;!/%
%/
Zulke declaraties heb je alleen nodig als je binnen een functie de waarde van een erbuiten gelegen variabele wilt //veranderen//. Voor het alleen uitlezen van externe variabelen kun je op de ''LEGB''-regel vertrouwen. Bedenk hierbij ook het volgende. Stel dat {{tt t{kilo}}} en {{tt t{lima}}} in onderstaande functie {{tt t{f}}} globale variabelen zijn:
{{{
def f()
    kilo[2]   = 7
    lima.mike = kilo
f()
}}}
Na aanroep van deze functie is de waarde van deze variabelen niet gewijzigd. Beide verwijzen na de toekenningen namelijk nog steeds naar dezelfde objecten. Alleen de //inhoud// van die objecten is veranderd. Daartoe werden de variabelen slechts uitgelezen om de betrokken objecten te achterhalen, waarvan vervolgens alleen de waarden van hun index {{tt t{2}}} resp. attribuut {{tt t{mike}}} werden aangepast. Een {{tt t{global}}}-statement is hier dus helemaal niet nodig.

Hieronder worden de {{tt t{global}}}- en {{tt t{nonlocal}}}-statements nog wat nader aan de tand gevoeld./%

%/
+++(~Python_globals)!![Globals &darr;|show][Globals &uarr;|hide]
{{lf vrl pl1em prhem{
|tt |k
| !{{serif{Functie}}} f | !"""__main__""" |
|                       |__alpha__        |
|bravo                  |__bravo__        |
|charlie                |                 |
|&nbsp;                 |                 |
|&nbsp;                 |                 |
|                       |__foxtrot__      |
}}}{{lf vrl pl1em prhem{
|sans|k
|tt |k
| !{{serif{Functie}}} g | !"""__main__""" |
|                       |__alpha__        |
|__bravo__ &rarr;       |__bravo__        |
|&nbsp;                 |                 |
|__delta__ &rarr;       |''{{z b2m fwhi rr{{{h6{+}}}}}}'' __delta__ |
|&nbsp;                 |                 |
|__foxtrot__ &rarr;     |__foxtrot__ ''{{z bred fwhi rr{{{h6{&times;}}}}}}'' |
}}}{{lf vrl pl1em vrr pr1em{
|sans|k
|tt |k
| !{{serif{Functie}}} i | !"""__main__""" |
|                       |__alpha__        |
|__bravo__ &rarr;       |__bravo__        |
|&nbsp;                 |                 |
|&nbsp;                 |__delta__        |
|__echo__ &rarr;        |''{{z b2m fwhi rr{{{h6{+}}}}}}'' __echo__ |
|&nbsp;                 |                 |
}}}<<div [=[{{block plhem{De globale variabelen die in het script worden gemanipuleerd zijn in nevenstaande tabellen onderstreept. De overige genoemde variabelen zijn lokaal. De functies ''{{hitt{g}}}'' en ''{{hitt{i}}}'' muteren de globale variabele __{{tt t{bravo}}}__. Functie ''{{hitt{g}}}'' creëert bij de eerste aanroep bovendien een globale variabele __{{tt t{delta}}}__, en functie ''{{hitt{i}}}'' een globale variabele __{{tt t{echo}}}__. Bij een volgende aanroep worden deze variabelen bijgewerkt. Functie ''{{hitt{g}}}'' verwijdert de globale variabele __{{tt t{foxtrot}}}__, zodat functie ''{{hitt{h}}}'' deze niet meer aantreft.

De functies ''{{hitt{g}}}'' en ''{{hitt{h}}}'' bevatten een {{tt t{global}}}-statement. Dit statement herstelt de globale variabele __{{tt t{foxtrot}}}__ niet. In functie ''{{hitt{i}}}'' is de omwegtruc voor het bereiken van globale variabelen gebruikt.}}}]=]>>{{clear block{
{{lf w55pct pre{
{{fgre{"""# Script: change-globals.py
# Date  : 2023-06-28, Meindert Meindertsma"""}}}
"""
alpha   = 42
bravo   = 21
foxtrot =  3


def f():
    print("\nf():")
    print("  alpha   =", alpha)
    try: """{{fred{"""print("  bravo   =", bravo)"""}}}""" 
    except Exception as e: print("  Error:", e)
    bravo = 20
    print("  bravo   =", bravo)
    charlie = 0
    print("  charlie =", charlie)"""
{{fgre{"""#    """''{{b2{global charlie}}}''"""
#    ==> SyntaxError: name 'charlie' is used prior to global declaration"""}}}"""
    charlie = alpha + bravo
    print("  charlie =", charlie)

f()
print("  bravo   =", bravo)
try: """{{fred{"""print("  charlie =", charlie)"""}}}"""
except Exception as e: print("  Error:", e)


def g():
    print("\ng():")
    print("  alpha   =", alpha)
    """''{{b2{global bravo, delta, foxtrot}}}''"""
           """{{fgre{# must be declarated as global before using them}}}"""
    print("  bravo   =", bravo)
    print("  foxtrot =", foxtrot)
    del foxtrot
    delta = alpha + bravo
    bravo += 1
    print("  bravo   =", bravo)
    print("  delta   =", delta)

g()
print("  delta   =", delta)


def h():
    print("\nh():")
    try: """{{fred{"""print("  echo    =", echo)"""}}}"""
    except Exception as e: print("  Error:", e)
    """''{{b2{global foxtrot}}}''"""
    try: """{{fred{"""print("  foxtrot =", foxtrot)"""}}}"""
    except Exception as e: print("  Error:", e)

h()

"""
''import sys
this = sys.modules["""__name__"""]
print(f"\nThis is {this}.")''
"""
def i():
    print("\ni():")
    print("  bravo =", """''this.bravo''""")
    this.bravo += 1
    this.echo   = 7
    print("  bravo =", """''this.bravo''""")

i()
print("  bravo =", bravo)
print("  echo  =", echo)


print("\nGlobals:")
for k, v in sorted(globals().copy().items()):
    print(f"  {k:15s} = {v}")"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w40pct pre{
''Uitvoer''
"""
f():
  alpha   = 42
  Error: cannot access local variable 'bravo' where it is not associated with a value
  bravo   = 20
  charlie = 0
  charlie = 62
  bravo   = 21
  Error: name 'charlie' is not defined

g():
  alpha   = 42
  bravo   = 21
  foxtrot = 3
  bravo   = 22
  delta   = 63
  delta   = 63

h():
  Error: name 'echo' is not defined
  Error: name 'foxtrot' is not defined

This is <module '__main__' from 'C:\\Users\\demsm\\+data\\Knutselhoekje\\Python\\scope\\change-globals.py'>.

i():
  bravo = 22
  bravo = 23
  echo  = 7
  bravo = 23
  echo  = 7

Globals:
  __annotations__ = {}
  __builtins__    = <module 'builtins' (built-in)>
  __cached__      = None
  __doc__         = None
  __file__        = C:\Users\demsm\+data\Knutselhoekje\Python\scope\change-globals.py
  __loader__      = <_frozen_importlib_external.SourceFileLoader object at 0x000001E6805C5090>
  __name__        = __main__
  __package__     = None
  __spec__        = None
  alpha           = 42
  bravo           = 23
  delta           = 63
  echo            = 7
  f               = <function f at 0x000001E6807789A0>
  g               = <function g at 0x000001E680779760>
  h               = <function h at 0x000001E680779800>
  i               = <function i at 0x000001E6807798A0>
  sys             = <module 'sys' (built-in)>
  this            = <module '__main__' from 'C:\\Users\\demsm\\+data\\Knutselhoekje\\Python\\scope\\change-globals.py'>"""
}}}{{clear block{}}}}}}/%

%/
===
+++(~Python_nonlocals)!![Nonlocals &darr;|show][Nonlocals &uarr;|hide]
{{lf vrl pl1em vrr pr1em{
|sans|k
|tt |k
| !{{serif{Functie}}} f3 | !{{serif{Functie}}} f2 | !{{serif{Functie}}} f1 | !"""__main__""" |
|&nbsp;                  |&nbsp;                  |&nbsp;                  |__alpha__        |
|&nbsp;                  |&nbsp;                  |bravo                   |__bravo__        |
|&nbsp;                  |charlie                 |charlie                 |__charlie__      |
|&nbsp;                  |(delta) &rarr;          |delta                   |__delta__        |
|(echo) &rarr;           |&nbsp;                  |echo                    |__echo__         |
|                        |                        |                        |__foxtrot__      |
}}}<<div [=[{{block plhem{De globale variabelen die in het script worden gemanipuleerd zijn in nevenstaande tabellen onderstreept, en de niet-lokale tussen haakjes gezet. De overige genoemde variabelen zijn lokaal. Functie ''{{hitt{f2}}}'' muteert de lokale variabele {{tt t{delta}}} van functie ''{{hitt{f1}}}''. Functie ''{{hitt{f3}}}'' doet hetzelfde met de lokale variabele {{tt t{echo}}} van functie ''{{hitt{f1}}}''.}}}]=]>>{{clear block{
{{lf w55pct pre{
{{fgre{"""# Script: change-nonlocals.py
# Date  : 2023-06-29, Meindert Meindertsma"""}}}
"""
alpha   = 0
bravo   = 0
charlie = 0
delta   = 0
echo    = 0
foxtrot = 0

print("  alpha   =", alpha)
print("  bravo   =", bravo)
print("  charlie =", charlie)
print("  delta   =", delta)
print("  echo    =", echo)
print("  foxtrot =", foxtrot)

def f1():
    print("\nf1():")
    bravo   = 1
    charlie = 1
    delta   = 1
    echo    = 1
    print("  alpha   =", alpha)
    print("  bravo   =", bravo)
    print("  charlie =", charlie)
    print("  delta   =", delta)
    print("  echo    =", echo)
    print(" ", locals())

    def f2():
        print("\nf2():")
"""{{fgre{"""#        """''{{b2{nonlocal delta, foxtrot}}}''"""
#        ==> SyntaxError: no binding for nonlocal 'foxtrot' found
#            So:
#            - Globals are not nonlocals
#            - Unlike globals, you cannot create nonlocals"""}}}"""
        """''{{b2{nonlocal delta}}}''"""
        charlie = 2
        print("  alpha   =", alpha)
        print("  bravo   =", bravo)
        print("  charlie =", charlie)
        print("  delta   =", delta)
        delta += 1
        print("  delta   =", delta, "(!)")
        print("  echo    =", echo)
        print(" ", locals())

        def f3():
            print("\nf3():")
            """''{{b2{nonlocal echo}}}''"""
            print("  alpha   =", alpha)
            print("  bravo   =", bravo)
            print("  charlie =", charlie)
            print("  delta   =", delta)
            print("  echo    =", echo)
            echo += 1
            print("  echo    =", echo, "(!)")
            print(" ", locals())

        return f3

    return f2

g = f1()
h = g()
h()
g()
h()
g()
f1()

print("\nGlobal values:")
print("  alpha   =", alpha)
print("  bravo   =", bravo)
print("  charlie =", charlie)
print("  delta   =", delta)
print("  echo    =", echo)
print("  foxtrot =", foxtrot)"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w40pct pre{
''Uitvoer''
"""
  alpha   = 0
  bravo   = 0
  charlie = 0
  delta   = 0
  echo    = 0
  foxtrot = 0

f1():
  alpha   = 0
  bravo   = 1
  charlie = 1
  delta   = 1
  echo    = 1
  {'charlie': 1, 'bravo': 1, 'delta': 1, 'echo': 1}

f2():
  alpha   = 0
  bravo   = 1
  charlie = 2
  delta   = 1
  delta   = 2 (!)
  echo    = 1
  {'charlie': 2, 'bravo': 1, 'delta': 2, 'echo': 1}

f3():
  alpha   = 0
  bravo   = 1
  charlie = 2
  delta   = 2
  echo    = 1
  echo    = 2 (!)
  {'bravo': 1, 'charlie': 2, 'delta': 2, 'echo': 2}

f2():
  alpha   = 0
  bravo   = 1
  charlie = 2
  delta   = 2
  delta   = 3 (!)
  echo    = 2
  {'charlie': 2, 'bravo': 1, 'delta': 3, 'echo': 2}

f3():
  alpha   = 0
  bravo   = 1
  charlie = 2
  delta   = 3
  echo    = 2
  echo    = 3 (!)
  {'bravo': 1, 'charlie': 2, 'delta': 3, 'echo': 3}

f2():
  alpha   = 0
  bravo   = 1
  charlie = 2
  delta   = 3
  delta   = 4 (!)
  echo    = 3
  {'charlie': 2, 'bravo': 1, 'delta': 4, 'echo': 3}

f1():
  alpha   = 0
  bravo   = 1
  charlie = 1
  delta   = 1
  echo    = 1
  {'charlie': 1, 'bravo': 1, 'delta': 1, 'echo': 1}

Global values:
  alpha   = 0
  bravo   = 0
  charlie = 0
  delta   = 0
  echo    = 0
  foxtrot = 0"""
}}}{{clear block{}}}}}}/%

%/
===

----
|plain |k
|<html><a name="1">[1]</a></html>|In tegenstelling tot //dynamic scoping//, waarin de plaats waar de desbetreffende code wordt //uitgevoerd// de scope bepaalt. Zo hebben de [[macrovariabelen van SAS|The scope of macro variables]] een dynamische scope. |
|<html><a name="2">[2]</a></html>|<<tiddler Bibliografie##Lutz>><br>In het Nederlands zou je het de ''LOGI''-regel kunnen noemen: Lokaal -- Omvattend -- Globaal -- Ingebouwd. |
|<html><a name="3">[3]</a></html>|In Lua wordt van 'upvalues' gesproken. Zie ook https://craftinginterpreters.com/closures.html. |
|<html><a name="4">[4]</a></html>|Om precies te zijn, in Python 3.11 heb ik 96 ingebouwde classes en 45 functies gevonden. Alle 96 classes zijn 'callable'. Van deze 96 zijn er 70 een {{tt t{BaseException}}} of subclass hiervan. Alleen de overige 26 zijn in de officiële Python-documentatie als [['ingebouwde functie'|Ingebouwde 'functies' in Python]] aangemerkt. Verder wordt de functie {{t{{{{__build_class__}}}}}} daar niet genoemd. |
|<html><a name="5">[5]</a></html>|In eerste instantie tracht Python het gezochte attribuut uit een module op te halen en in tweede instantie de gelijknamige sleutel uit een dictionary. Zie het programma {{pref sans t{detour-to-builtins-makeshifts.py}}} in de [[downloads|Python-scopescripts (downloads)]] en ook de [[inleiding tot geneste modules|Geneste Python-modules##Inleiding]]. |
|<html><a name="6">[6]</a></html>|Verwar met name functie-attributen niet met lokale variabelen van die functie. |
|<html><a name="7">[7]</a></html>|Bij classes staat daar wel wat tegenover: overerving van attributen in subclasses en beschikbaarheid van attributen in instances van een class. |
|<html><a name="8">[8]</a></html>|Comprehension- en exceptionvariabelen zijn daarentegen wel degelijk volwaardig. In bijvoorbeeld de list-comprehension ''{{pref hitt z{[(lambda: 2 * X)() for X in [10, 20, 30]]}}}'' weet de lambda de buiten de functie gelegen variabele {{tt t{X}}} moeiteloos te vinden, zodat er een list {{pref tt t{[20, 40, 60]}}} resulteert. |
{{hws u2 d2 b2p plhem prhem f2d h4 sans{Vervolg op [[Zichtbaarheid van Python-variabelen]]}}} ''{{up1px sans{<<showPopup tiddler:[[} Zichtbaarheid van Python-variabelen]] label: "Bundel ↘">>}}}''

Classattributen passen niet helemaal in het vierscopesmodel zoals beschreven in [[Zichtbaarheid van Python-variabelen]]. Zoals daar al aangestipt zijn de binnen een class gedefinieerde functies en methods blind voor de attributen van die class. Die attributen moeten via een functieparameter -- meestal {{tt t{self}}} genoemd -- worden gekwalificeerd. Binnen de definitie van een class, in het {{tt t{class}}}-blok, gedragen de attributen zich wel als lokale variabelen. Zie de toekenningen binnen de class aan de attributen {{tt t{bravo}}}, {{tt t{charlie}}}, {{tt t{delta}}} en {{tt t{echo}}}. Die zijn alle vier gebaseerd op de 'lokale variabele' {{tt t{alpha}}} met de waarde {{tt t{100}}}:
{{lf w50pct pre{
{{fgre{"""# Script: classy.py
# Date  : 2023-07-07, Meindert Meindertsma"""}}}
"""
alpha = 10
bravo = 2 * alpha
print("alpha            =", alpha)
print("bravo            =", bravo)

class C:
    alpha   = 10 * alpha
    bravo   =  2 * alpha
    charlie =  3 * alpha
    delta   =  4 * alpha
    echo    =  5 * alpha

    print("\nC : alpha        =", alpha)
    print("C : bravo        =", bravo)
    print("C : charlie      =", charlie)
    print("C : delta        =", delta)
    print("C : echo         =", echo)

    @classmethod
    def cm("""''cls''"""):
"""{{fgre{"""#        nonlocal charlie
#        => SyntaxError: no binding for nonlocal 'charlie' found"""}}}"""
        global charlie
        charlie     = 30
        cls.charlie += 1
        print("cm: alpha        =", alpha)
        print("cm: bravo        =", bravo)
        print("cm: charlie      =", charlie)
        print("cm: cls.alpha    =", """''cls''""".alpha)
        print("cm: cls.bravo    =", """''cls''""".bravo)
        print("cm: cls.charlie  =", """''cls''""".charlie)

    def im("""''self''"""):
"""{{fgre{"""#        nonlocal delta
#        => SyntaxError: no binding for nonlocal 'delta' found"""}}}"""
        global delta
        delta      = 40
        self.delta += 1
        print("im: alpha        =", alpha)
        print("im: bravo        =", bravo)
        print("im: charlie      =", charlie)
        print("im: delta        =", delta)
        print("im: self.alpha   =", """''self''""".alpha)
        print("im: self.bravo   =", """''self''""".bravo)
        print("im: self.charlie =", """''self''""".charlie)
        print("im: self.delta   =", """''self''""".delta)

    @staticmethod
    def sm():
"""{{fgre{"""#        nonlocal echo
#        => SyntaxError: no binding for nonlocal 'echo' found"""}}}"""
        global echo
        echo = 50
        print("sm: alpha        =", alpha)
        print("sm: bravo        =", bravo)
        print("sm: charlie      =", charlie)
        print("sm: delta        =", delta)

o = C()

print("\nC.cm =", C.cm)
C.cm()
print("charlie          =", charlie)

print("\nC.im =", C.im)
C.im(C)
print("delta            =", delta)

print("\no.im =", o.im)
o.im()
print("delta            =", delta)

print("\nC.sm =", C.sm)
C.sm()
print("echo             =", echo)

print("\no.sm =", o.sm)
o.sm()
print("echo             =", echo)"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w45pct{{{pre{
''Uitvoer''
"""
alpha            = 10
bravo            = 20

C : alpha        = 100
C : bravo        = 200
C : charlie      = 300
C : delta        = 400
C : echo         = 500

C.cm = <bound method C.cm of <class '__main__.C'>>
cm: alpha        = 10
cm: bravo        = 20
cm: charlie      = 30
cm: cls.alpha    = 100
cm: cls.bravo    = 200
cm: cls.charlie  = 301
charlie          = 30

C.im = <function C.im at 0x000001B9BA059A80>
im: alpha        = 10
im: bravo        = 20
im: charlie      = 30
im: delta        = 40
im: self.alpha   = 100
im: self.bravo   = 200
im: self.charlie = 301
im: self.delta   = 401
delta            = 40

o.im = <bound method C.im of <__main__.C object at 0x000001B9BA05F910>>
im: alpha        = 10
im: bravo        = 20
im: charlie      = 30
im: delta        = 40
im: self.alpha   = 100
im: self.bravo   = 200
im: self.charlie = 301
im: self.delta   = 402
delta            = 40

C.sm = <function C.sm at 0x000001B9BA059B20>
sm: alpha        = 10
sm: bravo        = 20
sm: charlie      = 30
sm: delta        = 40
echo             = 50

o.sm = <function C.sm at 0x0000023399C19B20>
sm: alpha        = 10
sm: bravo        = 20
sm: charlie      = 30
sm: delta        = 40
echo             = 50"""
}}}}}}{{clear block{}}}
Onderstaand voorbeeld laat zien dat de attributen van omvattende classes niet als een soort van niet-lokale variabelen worden opgevat. Integendeel, ze worden vanuit dat perspectief gewoonweg niet waargenomen. De class {{tt t{C.C2}}} baseert de waarde van het classattribuut {{tt t{charlie}}} daardoor op de globale variabele {{tt t{bravo}}} (=&nbsp;{{tt t{20}}}), niet op het over het hoofd geziene {{tt t{C.bravo}}} (=&nbsp;{{tt t{200}}}). Alleen vanuit {{tt t{C}}} kan worden afgedwongen dat de attributen van {{tt t{C}}} meespelen, in dit geval bij de bepaling van {{tt t{C.C2.delta}}} op basis van {{tt t{C.bravo}}}.
{{lf w50pct pre{
{{fgre{"""# Script: classy-nested.py
# Date  : 2023-07-09, Meindert Meindertsma"""}}}
"""
alpha = 10
bravo = 20
print("alpha             =", alpha)
print("bravo             =", bravo)
print()

class C:
    alpha = 10 * alpha
    bravo =  2 * alpha
    print("C: alpha          =", alpha)
    print("C: bravo          =", bravo)
    print("C: locals()       =", locals())

    class C2:
        charlie = int(1.5 * bravo)
        print("C.C2: alpha       =", alpha)
        print("C.C2: bravo       =", bravo)
        print("C.C2: charlie     =", charlie)
        print("C.C2: locals()    =", locals())

    C2.delta = 2 * bravo
    print("C: C2.delta       =", C2.delta)
    print("C: locals()       =", locals())

print("\nglobal nondunders =", { 
    k: v for k, v in globals().items()
    if k[0] != "_" or k in ("__module__", "__qualname__") })
print("C.alpha           =", C.alpha)
print("C.bravo           =", C.bravo)
try: print("C.C2.alpha        =", C.C2.alpha)
except Exception as e: print(f"C.C2: {type(e).__name__}: {e}")
try: print("C.C2.bravo        =", C.C2.bravo)
except Exception as e: print(f"C.C2: {type(e).__name__}: {e}")
print("C.C2.charlie      =", C.C2.charlie)
print("C.C2.delta        =", C.C2.delta)"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w45pct{{{pre{
''Uitvoer''
"""
alpha             = 10
bravo             = 20

C: alpha          = 100
C: bravo          = 200
C: locals()       = {'__module__': '__main__', '__qualname__': 'C', 'alpha': 100, 'bravo': 200}
C.C2: alpha       = 10
C.C2: bravo       = 20
C.C2: charlie     = 30
C.C2: locals()    = {'__module__': '__main__', '__qualname__': 'C.C2', 'charlie': 30}
C: C2.delta       = 400
C: locals()       = {'__module__': '__main__', '__qualname__': 'C', 'alpha': 100, 'bravo': 200, 'C2': <class '__main__.C.C2'>}

global nondunders = {'alpha': 10, 'bravo': 20, 'C': <class '__main__.C'>}
C.alpha           = 100
C.bravo           = 200
AttributeError: type object 'C2' has no attribute 'alpha'
AttributeError: type object 'C2' has no attribute 'bravo'
C.C2.charlie      = 30
C.C2.delta        = 400"""
}}}}}}{{clear block{}}}
De classattributen doen klaarblijkelijk slechts halfslachtig mee met het [[LEGB-spel|Zichtbaarheid van Python-variabelen]]. Bovendien op een nogal eigenzinnige wijze. Want wat gebeurt er wanneer je bovenstaande logica onderbrengt binnen een functie? Ik heb dat eens uitgeprobeerd, en omwille van de patroonherkenning heb ik de constructie van hierboven uitgebreid met een nog een dieper geneste class {{tt t{C3}}} en een aan class {{tt t{C}}} nevengeschikte class {{tt t{D}}}. Dat levert een verrassende voorstelling op:
{{lf w50pct pre{
{{fgre{"""# Script: classy-deeper-nested-in-function.py
# Date  : 2023-07-09, Meindert Meindertsma"""}}}
"""
import sys
from inspect import getclosurevars

def p(name, obj):
    if len(sys.argv) > 1:
        print(f"{name}:")
        cv = getclosurevars(obj)
        for item in dir(cv):
            if item in ("builtins", "globals", "nonlocals", "unbound"):
                print(f"        {item:9s} =", getattr(cv, item))


alpha = -10
bravo = -20
print("alpha             =", alpha)
print("bravo             =", bravo)

def f():
    alpha = 10
    bravo = 20
    print("\nf: alpha          =", alpha)
    print("f: bravo          =", bravo)
    print()

    class C:
        alpha = 10 * alpha
        bravo =  2 * alpha
        print("C: alpha          =", alpha)
        print("C: bravo          =", bravo)
        print("C: locals()       =", locals())
        p("C: closurevars of f", f)

        class C2:
            charlie = int(1.5 * bravo)
            print("C.C2: alpha       =", alpha)
            print("C.C2: bravo       =", bravo)
            print("C.C2: charlie     =", charlie)
            print("C.C2: locals()    =", locals())
            p("C.C2: closurevars of f", f)

            class C3:
                echo = int(2.5 * bravo)
                print("C.C2.C3: alpha    =", alpha)
                print("C.C2.C3: bravo    =", bravo)
                try: print("C.C2.C3: charlie  =", charlie)
                except Exception as e:
                    print(f"C.C2.C3: {type(e).__name__}: {e}")
                print("C.C2.C3: echo     =", echo)
                print("C.C2.C3: locals() =", locals())
                p("C.C2.C3: closurevars of", f)

        C2.delta = 2 * bravo
        print("C: C2.delta       =", C2.delta)
        print("C: locals()       =", locals())
        p("C: closurevars of f", f)

    class D:
        alpha = 10 * alpha
        print("D: alpha          =", alpha)
    del D

    local_c_object = C()
    print("\nlocal nondunders  =", { 
        k: v for k, v in locals().items()
        if k[0] != "_" or k in ("__module__", "__qualname__") })
    p("C: closurevars of", f)
    print("C.alpha           =", C.alpha)
    print("C.bravo           =", C.bravo)
    try: print("C.C2.alpha        =", C.C2.alpha)
    except Exception as e: print(f"{type(e).__name__}: {e}")
    try: print("C.C2.bravo        =", C.C2.bravo)
    except Exception as e: print(f"{type(e).__name__}: {e}")
    print("C.C2.charlie      =", C.C2.charlie)
    print("C.C2.delta        =", C.C2.delta)
    try: print("C.C2.C3.alpha     =", C.C2.C3.alpha)
    except Exception as e: print(f"{type(e).__name__}: {e}")
    try: print("C.C2.C3.bravo     =", C.C2.C3.bravo)
    except Exception as e: print(f"{type(e).__name__}: {e}")
    try: print("C.C2.C3.charlie   =", C.C2.C3.charlie)
    except Exception as e: print(f"{type(e).__name__}: {e}")
    try: print("C.C2.C3.delta     =", C.C2.C3.delta)
    except Exception as e: print(f"{type(e).__name__}: {e}")
    print("C.C2.C3.echo      =", C.C2.C3.echo)
    print("local_c_object    =", local_c_object)

    return local_c_object

global_c_object = f()
print("\nglobal nondunders =", { 
        k: v for k, v in globals().items()
        if k[0] != "_" or k in ("__module__", "__qualname__") })"""
}}}<<divlf 0.75% [=[<html><img src="core/transparent.png" alt="white" width=100%></html>]=]>>{{lf w45pct{{{pre{
''Uitvoer''
"""
alpha             = -10
bravo             = -20

f: alpha          = 10
f: bravo          = 20

C: alpha          = -100
C: bravo          = -200
C: locals()       = {'__module__': '__main__', '__qualname__': 'f.<locals>.C', 'alpha': -100, 'bravo': -200}
C.C2: alpha       = 10
C.C2: bravo       = 20
C.C2: charlie     = 30
C.C2: locals()    = {'__module__': '__main__', '__qualname__': 'f.<locals>.C.C2', 'charlie': 30}
C.C2.C3: alpha    = 10
C.C2.C3: bravo    = 20
C.C2.C3: NameError: name 'charlie' is not defined
C.C2.C3: echo     = 50
C.C2.C3: locals() = {'__module__': '__main__', '__qualname__': 'f.<locals>.C.C2.C3', 'echo': 50}
C: C2.delta       = -400
C: locals()       = {'__module__': '__main__', '__qualname__': 'f.<locals>.C', 'alpha': -100, 'bravo': -200, 'C2': <class '__main__.f.<locals>.C.C2'>}
D: alpha          = -100

local nondunders  = {'alpha': 10, 'C': <class '__main__.f.<locals>.C'>, 'local_c_object': <__main__.f.<locals>.C object at 0x000001D0649CB150>, 'bravo': 20}
C.alpha           = -100
C.bravo           = -200
AttributeError: type object 'C2' has no attribute 'alpha'
AttributeError: type object 'C2' has no attribute 'bravo'
C.C2.charlie      = 30
C.C2.delta        = -400
AttributeError: type object 'C3' has no attribute 'alpha'
AttributeError: type object 'C3' has no attribute 'bravo'
AttributeError: type object 'C3' has no attribute 'charlie'
AttributeError: type object 'C3' has no attribute 'delta'
C.C2.C3.echo      = 50
local_c_object    = <__main__.f.<locals>.C object at 0x000001D0649CB150>

global nondunders = {'sys': <module 'sys' (built-in)>, 'getclosurevars': <function getclosurevars at 0x000001D0649CEFC0>, 'p': <function p at 0x000001D0643EA020>, 'alpha': -10, 'bravo': -20, 'f': <function f at 0x000001D0646489A0>, 'global_c_object': <__main__.f.<locals>.C object at 0x000001D0649CB150>}"""
}}}/%

%/Bovenstaande uitvoer wordt verkregen wanneer het programma zonder argumenten is aangeroepen. Zijn er wel een of meer argumenten meegegeven, dan wordt er vijf keer een naar blijkt identiek overzichtje van de closure-variabelen afgedrukt:
{{pre{
//context//: closurevars of f:"""
        builtins  = {'print': <built-in function print>, 'locals': <built-in function locals>, 'Exception': <class 'Exception'>, 'type': <class 'type'>}
        globals   = {'p': <function p at 0x000001BE365289A0>, 'f': <function f at 0x000001BE36529760>, 'alpha': -10, 'bravo': -20, '__name__': '__main__'}
        nonlocals = {}
        unbound   = {'C3', 'items', 'charlie', 'C2', 'echo', 'delta'}"""
}}} met achtereenvolgens //context// = {{hitt z{C}}}, {{hitt z{C.C2}}}, {{hitt z{C.C2.C3}}}, {{hitt z{C}}} en {{hitt z{f}}}. Gezien de [[grillen|Een niet zo geweldige introspectie van Python]] van {{tt t{inspect.getclosevars}}} kan deze rapportage maar beter lichtelijk gezouten worden geconsumeerd.}}}{{clear block{}}}/%

%/
Hoe dit te verklaren? Ik houd het voorlopig maar bij een niet erg bevredigende beeldspraak: kennelijk hebben class­definities een leesbril nodig. En die hebben ze helaas niet. Globale variabelen kunnen binnen zo'n definitie wel worden gezien. Lokale variabelen niet, wanneer ze te dichtbij liggen zoals vanuit de niveaus van de classes {{tt t{C}}} en {{tt t{D}}} gezien. Pas op diepere niveaus, {{tt t{C2}}} en {{tt t{C3}}} in dit geval, krijgt Python de lokale variabelen scherp in beeld en dekken deze de eventele gelijknamige variabelen buiten de lokale scope af.

Natuurlijk heb ik eveneens gekeken hoe het waarnemingsvermogen zich hield bij geneste functies, en wel de constructie {{sans t{"""{f: {f2: {C: {C2: {C3}}}, D}}"""}}} in het programma {{pref sans t{classy-deeper-nested-in-nested-functions.py}}} (zie [[downloads|Python-scopescripts (downloads)]]). In deze opstelling blijken ook de lokale variabelen van {{tt t{f}}} (dus niet-lokaal vanuit {{tt t{f2}}} gezien) nog te dichtbij voor {{tt t{C}}} en {{tt t{D}}}. Bijgevolg houden deze classes het dus nog steeds bij de globale variabelen. Daarentegen zien {{tt t{C2}}} en {{tt t{C3}}} de lokale variabelen van {{tt t{f2}}} wel. Variabelen van {{tt t{f}}} worden alleen door deze dieper gelegen classes waargenomen voor zover ze niet zijn afgedekt door de lokale variabelen van {{tt t{f2}}}.

Overigens is binnen de functies en methods van classes de gewone [[LEGB-regel|Zichtbaarheid van Python-variabelen]] (waarin de eigen attributen zoals aan het begin gezegd dus niet meedoen) weer van toepassing. Zie naast {{sans t{classy.py}}} ook {{pref sans t{classy-in-function.py}}} en {{pref sans t{classy-nested-in-nested-functions-the-methods.py}}}.
//{{{
config.options.chkDisableWikiLinks = true;
config.options.chkDisableNonExistingWikiLinks = true;
//}}}
//{{{
config.options.chkShowLeftSidebar = true;
config.options.txtToggleLeftSideBarLabelShow = "▶";
config.options.txtToggleLeftSideBarLabelHide = "◀";
//}}}
//{{{
config.options.chkShowRightSidebar = true;
config.options.txtToggleRightSideBarLabelShow = "◀";
config.options.txtToggleRightSideBarLabelHide = "▶";
//}}}
/***
!!displayDefaultTiddlers
***/
//{{{
Story.prototype.displayDefaultTiddlers = function()
{
	this.displayTiddlers(null, store.filterTiddlers(store.getTiddlerText("DefaultTiddlers").replace(
		/^/, config.options.chkShowNews ? "Nieuws " : ""
	)));
};
//}}}
/***
!!chkShowBreadcrumbs
***/
//{{{
var script = document.createElement("script");
script.type = "text/javascript";
script.src = 'chkShowBreadcrumbs=false.js';
document.getElementsByTagName("head")[0].appendChild(script);
if (config.macros.breadcrumbs) config.macros.breadcrumbs.refresh();
//}}}
/***
!!chkFix{{f1s{{}}}Left{{f1s{,}}}Right{{f1s{"""}"""}}}Sidebar
***/
//{{{
config.options.chkFixLeftSidebar  = true;
config.options.chkFixRightSidebar = true;
//}}}
/***
!!chkShowNews
***/
//{{{
var newsExpiring = new Date(2022, 7, 23);                     // Fill in: year, month - 1, day of month
config.options.chkShowNews = newsExpiring - new Date() >= 0;  // Don't touch this formula
//}}}
/***
<script>return newsExpiring.toString()</script> //minus// <script>return new Date().toString()</script> =
:<script>return (newsExpiring - new Date()).toString()</script> milliseconds
:<script>return Math.floor((newsExpiring - new Date()) / 1000).toString()</script> seconds
:<script>return Math.floor((newsExpiring - new Date()) / (1000 * 60)).toString()</script> minutes
:<script>return Math.floor((newsExpiring - new Date()) / (1000 * 60 * 60)).toString()</script> hours
:<script>return Math.floor((newsExpiring - new Date()) / (1000 * 60 * 60 * 24)).toString()</script> days
***/
!!Small buttons for tiddler hopping and en bloc slider toggling
{{{
up0: {{up empty{{{button s{$1}}}}}}
0: {{empty{{{button s{$1}}}
upnext: {{up{{{button s{<<tiddler NextTiddler with: $1 $2>>}}}}}}
next: {{button s{<<tiddler NextTiddler with: $1 $2>>}}}
uptogglesliders: {{up{{{button s{''<<tiddler ToggleSliders with: "" "&darr;&darr;" "&uarr;&uarr;" "Expand (&darr;&darr;) or collapse (&uarr;&uarr;) all sliders in this tiddler">>''}}}}}}
togglesliders: {{button s{''<<tiddler ToggleSliders with: "" "&darr;&darr;" "&uarr;&uarr;" "Expand (&darr;&darr;) or collapse (&uarr;&uarr;) all sliders in this tiddler">>''}}}
}}}
/%
up0: {{up empty{{{button s{$1}}}}}}
0: {{empty{{{button s{$1}}}
upnext: {{up{{{button s{<<tiddler NextTiddler with: $1 $2>>}}}}}}
next: {{button s{<<tiddler NextTiddler with: $1 $2>>}}}
uptogglesliders: {{up{{{button s{''<<tiddler ToggleSliders with: "" "&darr;&darr;" "&uarr;&uarr;" "Expand (&darr;&darr;) or collapse (&uarr;&uarr;) all sliders in this tiddler">>''}}}}}}
togglesliders: {{button s{''<<tiddler ToggleSliders with: "" "&darr;&darr;" "&uarr;&uarr;" "Expand (&darr;&darr;) or collapse (&uarr;&uarr;) all sliders in this tiddler">>''}}}
%/
{{sans ls{
* [[ITERATIE versus RECURSIE]]
----
* [[Journal 2023-12-16 (Saturday): Iterecursions]]
* [[From single recursion to iteration]]
* [[Applying tail-call optimalization]]
* [[From multiple recursion to iteration]]
}}}
{{sans ls{
* [[Iteratiemechanismen]]
----
* [[Iteratiestatements in Python]]
* [[Simulaties van for...in...-statement]]
* [['Invariant state' in Lua]]
* [['Iterabiliteit' in Python]]
* [[7 iteriolen in Python|data/documents/iteriolen.pdf]]
* [[Het samenspel van iter en __getitem__ in Python]]
* [[Provider à la Python-iterator]]
* [[Provider à la Python-generator]]
* [[Geïntegreerde provider/deliverer/pilot à la Ruby]]
* [[Pilot à la Lua]]
* [[Slices in Python]]
}}}
{{sans ls{
* [[Reguliere expressies]]
* [[Reguliere expressies in Python]]
}}}
{{sans ls{
* [[Classes|TW Showroom: Classes]]
* [[Checklists|TW Showroom: Checklists]]
}}}
{{sans ls{
* [[Na sampi-nul]]
----
* [[Stapelingen op ANSI C]]
* [[Stapelingen op Lua 5.1]]
* [[Stapelingen op Python 3.3]]
* [[Stapelingen op Ruby 1.8]]
}}}
{{sans ls{
* [[Zichtbaarheid van Python-variabelen]]
----
* [[Geneste Python-modules]]
* [[Zichtbaarheid van classattributen in Python]]
* [[Een niet zo geweldige introspectie van Python]]
* [[Python-scopescripts (downloads)]]
}}}
Tiddlers die naar deze tiddler verwijzen, zijn nog niet af.
Kapitale bewondering verdienen de Ouden die de vaste verhouding van omtrek en diameter van alle cirkels onderkend en gepreciseerd hebben. Ze begonnen met ''3''... daarna ''3 en een beetje''... vervolgens ''22/7'' (twee decimalen nauwkeurig, door Archimedes in de 3e eeuw v.Chr.)... dan ''377/120'' (drie decimalen nauwkeurig, door Ptolemeüs in de 2e eeuw n.Chr.)... een beetje buiten het westerse gezichtsveld ''355/113'' (zes decimalen nauwkeurig, door Zu Chongzhi [{{stix{祖沖之}}}] in de 5e eeuw n.Chr.)... en na de zestien decimalen nauwkeurigheid wat dichter bij huis door al-K&#x0101;sh&#x012b; (14e eeuw) wist de westerse wetenschap het voortouw weer op te pakken. William Jones gaf de verhouding in 1706 aan met de Griekse letter ''{{stix{&pi;}}}'', wat gemeengoed werd toen Leonhard Euler deze notatie in 1737 overnam. De jacht op meer decimalen (inclusief een niet zo briljante poging in Indiana om de waarde wettelijk te bepalen) duurt nog altijd voort en kent geen einde totdat de mensheid en andere intelligenties het opgeven.

Eén ding is tot 2001 nogal onopgemerkt gebleven. Toen trok Bob Palais ineens aan de bel met {{stix{[[π is wrong!|http://www.math.utah.edu/~palais/pi.pdf]]}}} (zie ook [[hier|http://www.math.utah.edu/~palais/pi.html]]), negen jaar later gevolgd door het [[The Tau Manifesto|https://tauday.com/tau-manifesto]] van Michael Hartl. De kern van de boodschap is: ''de wezenlijke verhouding is die tussen de omtrek en de //straal//''. Palais' vader duidde die verhouding aan met {{sans{''//&pi;//''@@position:relative;left:-0.37em;''//&pi;//'',@@}}}een wat minder geslaagd typografisch knutselwerkje. Mij had in eerste instantie de ''{{stix{&#x03e1;}}}'' (de wat obscure Griekse letter //sampi//, die iets van een scheve //pi// weg heeft en nu eindelijk eens een grote rol zou kunnen gaan spelen) wel wat geleken, Thomas Colignatus heeft in 2008 nog ''{{stix{&Theta;}}}'' (//Thèta//) voorgesteld, maar de keus voor ''{{stix{&tau;}}}'' (//tau//) lijkt inmiddels al gemaakt, met alle overbelasting van deze letter van dien. De ''{{stix{&#x05ea;}}}'' (//tav//), ''{{stix{&#x062a;}}}'' (//teh//) en ''//{{stix{&#x057a;}}}//'' (Armeense //peh//) hebben het nakijken. Vooral laatstgenoemde of anders de alternatieve //pi//-vorm ''{{stix{&piv;}}}'' zou ik eigenlijk wel heel toepasselijk hebben gevonden, als de niet of nauwelijks onderscheidende naam van de letter niet in de weg zat.

Ik dwaal een beetje af. Wat wordt er nu eigenlijk beter met ''{{stix{&tau;}}}''&#x200a;? Eén voorbeeld op deze plek, de identiteit van Euler:
:{{h4{//e//^^ {{widen1{//i//{{stix{&pi;}}}}}}^^ = &minus;1}}}
Een logisch uitvloeisel van Eulers formule //e//^^ {{widen1{//i//{{stix{&phi;}}}}}}^^ = cos {{stix{&phi;}}} + //i// sin {{stix{&phi;}}}. Ik zat werkelijk perplex toen deze identiteit tijdens het eerstejaarsvak //a1// werd opgedist: drie exotische wiskundige constanten die niets met elkaar te maken leken te hebben zomaar verminenigd in één formule! Velen roemen deze formule als de mooiste binnen de wiskunde. Ze is het echter niet (we zien hier zogezegd slechts de Boze Koningin). De schoonste (Sneeuwwitje) is:
:{{h4{//e//^^ {{widen1{//i//{{stix{&tau;}}}}}}^^ = 1}}}
Niks geen negativiteit meer, holistischer kun je het niet hebben. {{stix widenq{&#x201b;&Epsilon;&nu; &tau;&omicron; &pi;&alpha;&nu;}}}, oftewel //alles is één//, zoals de Grieken zeiden. En al is het discutabel of {{pref{&ell;n (&minus;1) = &half; {{widen1{//i//{{stix{&tau;}}}}}}}}} nu werkelijk fraaier is dan {{pref{&ell;n (&minus;1) = {{widen1{//i//{{stix{&pi;}}}}}}}}}, het feit dat &ell;n 1 niet alleen gelijk is aan 0 maar ook de imaginaire oplossing {{widen1{//i//{{stix{&tau;}}}}}} heeft, springt er zo toch wel weer eleganter uit.

Veel pijn bij het gebruik van ''{{stix{&pi;}}}'' zit in de verschillende referenties voor omtrek en [[hoek|Hoeken]]: de omtrek is gebaseerd op de diameter van de cirkel en de in radialen uitgedrukte hoek op de straal. Op die manier sluipt er steeds een factor ''2'' of een ander schoonheidsfoutje in de formules. Vervanging van de radiaaleenheid door een twee keer zo grote hoekmaat lijkt op het eerste gezicht misschien een alternatief voor overschakelen op ''{{stix{&tau;}}}'', maar de formule van Euler wordt er lelijker van en zijn identiteit natuurlijk niet beter.

----

Korte samenvatting van bovenstaande begrippen en een lijstje van websites./%

%/
!!//e// -- het grondtal van de natuurlijke logaritme
:{{h4{//e// = lim (^^ ^^1 + ^^1^^/~~//n// ~~)^^ //n//^^ = 2,718281828. . .
{{pref up{      ^^//n//&rarr;&infin;^^}}}}}}
{{block up{(Nee, de repetitie van decimalen die je hier ziet, is slechts plaatselijk: de tiende decimaal is een ''4''.) Enkele markante eigenschappen:}}}
:{{block up h4{"""__"""@@position:relative;left:-0.8em;{{hup{d}}}@@@@position:relative;left:-0.2em;top:0.3em;//e^^ x ^^// = //e^^ x^^// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{{hup fgra{~~de exponentiële functie is gelijk aan de afgeleide ervan~~}}}@@
{{hup{d//x//}}}}}}
:{{h4{&nbsp; &nbsp; &nbsp; &nbsp; ~~&nbsp; &infin;~~
{{hup{//e^^ x^^// = &sum; &nbsp; &nbsp;{{up{{{hup{//x^^ n^^//}}}@@position:relative;left:-1.5em;"""___"""@@@@position:relative;left:-2.8em;top:1.1em;//n//!@@}}}{{hup fgra{~~Taylorreeks~~}}}
&nbsp; &nbsp; &nbsp; &nbsp;^^ //n//=0^^}}}}}}
:{{ib h4{<br>{{up{&ell;n //x// = {{h4{&int;}}} &nbsp;{{up{{{hup{1}}}@@position:relative;left:-0.9em;"""__"""@@@@position:relative;left:-1.8em;top:1.1em;//x//@@@@position:relative;left:-1.2em;top:0.4em;d//x//@@}}}{{hup fgra{~~de natuurlijk logaritme ^^//e//^^log //x// is gelijk aan de primitieve functie van //x//^^&minus;1^^~~}}}
&nbsp; &nbsp; &nbsp; &nbsp;}}}}}}
/%

%/{{block up{
!!//i// -- de imaginaire eenheid
:{{h4{//i// = &radic;(&minus;1)
@@position:relative;top:0.4em;//i//^^ 2^^ = &minus;1@@}}}/%

%/
!!//&tau;// -- de verhouding tussen omtrek en straal van een cirkel
:{{h4{{{stix{&tau;}}} = 2{{stix{&pi;}}} = //cirkelomtrek// / //cirkelstraal// = 6,283185307. . .
@@position:relative;top:0.4em;{{stix{&pi;}}} = //cirkelomtrek// / //cirkeldiameter// = 3,141592653. . .@@}}}/%

%/
!!//a1// -- Analyse I voor eerstejaarsstudenten aan de TH Delft
Timmermanswiskunde voor civielen en geodeten. Daarnaast waren er in 1972 met meer of minder diepgang:
* //a2// voor werktuigbouw, scheepsbouw, vliegtuigbouw en metaalkunde
* //a3// voor natuurkunde
* //a4// voor mijnbouwkunde en scheikunde
* //a5// voor industriële vormgeving
* //a6// voor elektrotechniek
* //a7// voor bouwkunde
* en kregen wiskundigen meteen de volle laag met //a8// + //a9///%

%/
Overigens staan veel van mijn {{stix{&beta;}}}- en {{stix{&gamma;}}}-boeken nog altijd geordend op het vakkencoderingssysteem van destijds op mijn boekenplanken uitgestald, dus //a// = wiskunde, //b// = mechanica, //c// = natuurkunde, enzovoort./%

%/
!!Links naar Wikipedia
* ''{{stix{&pi;}}}'' in de wiskunde: [[NL|https://nl.wikipedia.org/wiki/Pi_(wiskunde)]] en [[EN|https://en.wikipedia.org/wiki/Pi]]
* ''//e//'' in de wiskunde: [[NL|https://nl.wikipedia.org/wiki/E_(wiskunde)]] en [[EN|https://en.wikipedia.org/wiki/E_(mathematical_constant)]]
* Formule van Euler: [[NL|https://nl.wikipedia.org/wiki/Formule_van_Euler]] en [[EN|https://en.wikipedia.org/wiki/Euler%27s_formula]]
* Identiteit van Euler: [[NL|https://nl.wikipedia.org/wiki/Identiteit_van_Euler]] en [[EN|https://en.wikipedia.org/wiki/Euler%27s_identity]]
* ''{{stix{&tau;}}}'' in de wiskunde: [[NL|https://nl.wikipedia.org/wiki/Tau_(wiskunde)]] en [[EN|https://en.wikipedia.org/wiki/Turn_(angle)#Tau_proposals]]
}}}<<tiddler ReplaceTiddlerTitle with: "//&pi;//, de halve waarheid">>