<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://theportalwiki.com/w/index.php?action=history&amp;feed=atom&amp;title=User%3AWindBOT%2FDocumentation</id>
	<title>User:WindBOT/Documentation - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://theportalwiki.com/w/index.php?action=history&amp;feed=atom&amp;title=User%3AWindBOT%2FDocumentation"/>
	<link rel="alternate" type="text/html" href="https://theportalwiki.com/w/index.php?title=User:WindBOT/Documentation&amp;action=history"/>
	<updated>2026-04-28T13:54:04Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.0</generator>
	<entry>
		<id>https://theportalwiki.com/w/index.php?title=User:WindBOT/Documentation&amp;diff=5139&amp;oldid=prev</id>
		<title>WindPower: Created page with &quot;{{User:WindBOT/Header}}  I am a fully automated bot, but that doesn&#039;t mean that I am not flexible. You can tweak me from the wiki itself by editing [[User:WindBOT/Filters|my filt...&quot;</title>
		<link rel="alternate" type="text/html" href="https://theportalwiki.com/w/index.php?title=User:WindBOT/Documentation&amp;diff=5139&amp;oldid=prev"/>
		<updated>2011-04-26T21:34:24Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;{{User:WindBOT/Header}}  I am a fully automated bot, but that doesn&amp;#039;t mean that I am not flexible. You can tweak me from the wiki itself by editing [[User:WindBOT/Filters|my filt...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{User:WindBOT/Header}}&lt;br /&gt;
&lt;br /&gt;
I am a fully automated bot, but that doesn&amp;#039;t mean that I am not flexible. You can tweak me from the wiki itself by editing [[User:WindBOT/Filters|my filters]]!&lt;br /&gt;
&lt;br /&gt;
== Technical details ==&lt;br /&gt;
I am written in [http://python.org/ Python] (2.6). If you want to modify my code, make sure you know enough Python stuff before continuing.&lt;br /&gt;
&lt;br /&gt;
All code must be placed on [[User:WindBOT/Filters]], and indented by two spaces (for the top-level block). Whitespace determines Python&amp;#039;s code blocks. Although this is not a necessity, try to use 4 spaces per indentation level.&lt;br /&gt;
&lt;br /&gt;
== Filters ==&lt;br /&gt;
=== How to disable a filter ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Wait!&amp;#039;&amp;#039;&amp;#039; Before you disable a filter, consider why you want to disable it. Did it produce an expected result but on a page where such a result is not appropriate? In this case, [[User:WindBOT/Blacklist|blacklist this page]] instead of disabling the filter.&lt;br /&gt;
If I am malfunctioning, chances are that the problem lies in one of [[User:WindBOT/Filters|my filters]]. Thus, instead of completely shutting me down, it would be wiser to disable only the chunk of code that is misbehaving.&lt;br /&gt;
To make me ignore a certain line, add a &amp;quot;#&amp;quot; in front of it:&lt;br /&gt;
  # This line will be ignored&lt;br /&gt;
If there are multiple lines, wrap them inside triple-quotes:&lt;br /&gt;
  &amp;quot;&amp;quot;&amp;quot;This line will be ignored&lt;br /&gt;
  and this one as well&lt;br /&gt;
  and this one is cake&lt;br /&gt;
  and the previous one was a lie but it was still ignored&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
If all else fails, you can simply delete the block of code from the page. I can&amp;#039;t come up with code by myself yet, so I won&amp;#039;t do anything.&lt;br /&gt;
If the problem really is elsewhere, [{{fullurl:Special:Block|wpBlockAddress={{BASEPAGENAMEE}}&amp;amp;wpBlockExpiry=infinite&amp;amp;wpAnonOnly=0&amp;amp;wpEnableAutoblock=0&amp;amp;wpCreateAccount=0&amp;amp;wpBlockReason=Bot%20gone%20crazy:%20}} block the bot].&lt;br /&gt;
&lt;br /&gt;
=== Filter types ===&lt;br /&gt;
I work using filters. They are simply [http://www.penzilla.net/tutorials/python/functions/ Python functions] which take a certain input as argument, and is expected to return a modified version of this input (if the filter changed something) or an identical version (if the filter didn&amp;#039;t change anything). There are multiple types of filters:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Regular filters&amp;#039;&amp;#039;&amp;#039;: These are no-frills, direct filters.&lt;br /&gt;
** &amp;#039;&amp;#039;When to use&amp;#039;&amp;#039;: When no other filter type is adequate. This type of filter can be very destructive if the function is not careful enough.&lt;br /&gt;
** &amp;#039;&amp;#039;Input&amp;#039;&amp;#039;/&amp;#039;&amp;#039;Output&amp;#039;&amp;#039;: Raw Wikitext of a page&lt;br /&gt;
** &amp;#039;&amp;#039;Implementation details&amp;#039;&amp;#039;: Your filter is called only once, over the whole content of the page.&lt;br /&gt;
** &amp;#039;&amp;#039;How to use&amp;#039;&amp;#039;: To register a regular filter, call the &amp;lt;code&amp;gt;addFilter&amp;lt;/code&amp;gt; function: &amp;lt;code&amp;gt;addFilter(myFilter)&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Safe filters&amp;#039;&amp;#039;&amp;#039;: These are Wikitext safe filters.&lt;br /&gt;
** &amp;#039;&amp;#039;When to use&amp;#039;&amp;#039;: Semantics-related filters are a good fit for these. Use them to filter human-readable text.&lt;br /&gt;
** &amp;#039;&amp;#039;Input&amp;#039;&amp;#039;/&amp;#039;&amp;#039;Output&amp;#039;&amp;#039;: Sanitized Wikitext of a page (readable text content), external and internal wikilinks &amp;#039;&amp;#039;&amp;#039;labels&amp;#039;&amp;#039;&amp;#039; (labels only), internal wikilinks URLs only when combined with its label (&amp;lt;nowiki&amp;gt;[[like this]]&amp;lt;/nowiki&amp;gt;).&lt;br /&gt;
** &amp;#039;&amp;#039;Implementation details&amp;#039;&amp;#039;: Your filter is called once over the textual body of the page, then once per link label.&lt;br /&gt;
** &amp;#039;&amp;#039;How to use&amp;#039;&amp;#039;: To register a safe filter, call the &amp;lt;code&amp;gt;addSafeFilter&amp;lt;/code&amp;gt; function: &amp;lt;code&amp;gt;addSafeFilter(myFilter)&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Link filters&amp;#039;&amp;#039;&amp;#039;: These filters act on links within wiki pages.&lt;br /&gt;
** &amp;#039;&amp;#039;When to use&amp;#039;&amp;#039;: When you want to apply filters on links. Note: &amp;#039;&amp;#039;&amp;#039;Use a safe filter&amp;#039;&amp;#039;&amp;#039; if all you want to do is to modify link labels (unless you don&amp;#039;t want to modify the page&amp;#039;s body as well).&lt;br /&gt;
** &amp;#039;&amp;#039;Input&amp;#039;&amp;#039;/&amp;#039;&amp;#039;Output&amp;#039;&amp;#039;: A single link instance. The class definition is given at the bottom of this document.&lt;br /&gt;
** &amp;#039;&amp;#039;Implementation details&amp;#039;&amp;#039;: Your filter is called once per link in the page.&lt;br /&gt;
** &amp;#039;&amp;#039;How to use&amp;#039;&amp;#039;: To register a link filter, call the &amp;lt;code&amp;gt;addLinkFilter&amp;lt;/code&amp;gt; function: &amp;lt;code&amp;gt;addLinkFilter(myFilter)&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Locale filters&amp;#039;&amp;#039;&amp;#039;: These filters act on localization dictionaries.&lt;br /&gt;
** &amp;#039;&amp;#039;When to use&amp;#039;&amp;#039;: When you want to extract only certain parts of translation files.&lt;br /&gt;
** &amp;#039;&amp;#039;Input&amp;#039;&amp;#039;/&amp;#039;&amp;#039;Output&amp;#039;&amp;#039;: N/A&lt;br /&gt;
** &amp;#039;&amp;#039;Implementation details&amp;#039;&amp;#039;: The localization dictionary is a huge dictionary with keys being the string IDs (&amp;lt;code&amp;gt;TF_SPY_BACKSTAB_ENGY_SAP_BUILDING_DESC&amp;lt;/code&amp;gt;, etc.), and each key being another dictionary. This inner dictionary has language names as keys (&amp;lt;code&amp;gt;english&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;romanian&amp;lt;/code&amp;gt;...) and the actual translated string as value.&lt;br /&gt;
** &amp;#039;&amp;#039;How to use&amp;#039;&amp;#039;: Call the &amp;lt;code&amp;gt;languagesFilter&amp;lt;/code&amp;gt; function: &amp;lt;code&amp;gt;languagesFilter(languages, commonto, prefix, suffix, exceptions)&amp;lt;/code&amp;gt; where:&lt;br /&gt;
*** (&amp;#039;&amp;#039;&amp;#039;Required&amp;#039;&amp;#039;&amp;#039;) &amp;lt;code&amp;gt;languages&amp;lt;/code&amp;gt; is the localization dictionary.&lt;br /&gt;
*** (&amp;#039;&amp;#039;&amp;#039;Optional&amp;#039;&amp;#039;&amp;#039;) &amp;lt;code&amp;gt;commonto&amp;lt;/code&amp;gt; filters strings by their translation availability. For example, &amp;lt;code&amp;gt;commonto=[&amp;#039;english&amp;#039;, &amp;#039;french&amp;#039;]&amp;lt;/code&amp;gt; will only keep strings which are available in both &amp;lt;code&amp;gt;french&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;english&amp;lt;/code&amp;gt;.&lt;br /&gt;
*** (&amp;#039;&amp;#039;&amp;#039;Optional&amp;#039;&amp;#039;&amp;#039;) &amp;lt;code&amp;gt;prefix&amp;lt;/code&amp;gt; filters strings by their string ID, which must contain this string as prefix.&lt;br /&gt;
*** (&amp;#039;&amp;#039;&amp;#039;Optional&amp;#039;&amp;#039;&amp;#039;) &amp;lt;code&amp;gt;suffix&amp;lt;/code&amp;gt; filters strings by their string ID, which must contain this string as suffix.&lt;br /&gt;
*** (&amp;#039;&amp;#039;&amp;#039;Optional&amp;#039;&amp;#039;&amp;#039;) &amp;lt;code&amp;gt;exceptions&amp;lt;/code&amp;gt; is a list of keys that should be excluded no matter what.&lt;br /&gt;
&lt;br /&gt;
Filters themselves may be filtered (yeah, really) so that they are only applied to certain articles:&lt;br /&gt;
* Use &amp;lt;code&amp;gt;addSomeTypeOfFilter(myFilter1, myFilter2, myFilter3, ..., language=&amp;#039;de&amp;#039;)&amp;lt;/code&amp;gt; (where &amp;lt;code&amp;gt;addSomeTypeOfFilter&amp;lt;/code&amp;gt; is one of the functions described above) to add &amp;lt;code&amp;gt;myFilter1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;myFilter2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;myFilter3&amp;lt;/code&amp;gt;... as filters that will only be applied on German pages (&amp;lt;code&amp;gt;de&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Filter generators ===&lt;br /&gt;
As previously mentioned, filters are Python functions. However, a lot of filters are similar in function and in purpose. Therefore, declaring a new Python function for each filter would be redundant and cumbersome.&lt;br /&gt;
&lt;br /&gt;
Since functions are first-class variables in Python, you can pass around, edit, and create functions programatically. This is what filter generators are. They take a few argument about your desired filter&amp;#039;s details, and generate a corresponding Python function, which you can then add using the method described above.&lt;br /&gt;
&lt;br /&gt;
Filter generators:&lt;br /&gt;
* &amp;lt;code&amp;gt;dumbReplace(text, replacement)&amp;lt;/code&amp;gt;: This generates a straightforward text replacement filter, which replaces all instance of &amp;lt;code&amp;gt;text&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;replacement&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;dumbReplaces(stuffToReplace)&amp;lt;/code&amp;gt;: The bulk version of &amp;lt;code&amp;gt;dumbReplace&amp;lt;/code&amp;gt;. Generates a text replacement filter with multiple things to replace. &amp;lt;code&amp;gt;stuffToReplace&amp;lt;/code&amp;gt; should be a [http://docs.python.org/tutorial/datastructures.html#dictionaries Python dictionary] of the form:&lt;br /&gt;
&amp;lt;pre&amp;gt;{&lt;br /&gt;
    &amp;#039;text1&amp;#039;: &amp;#039;replacement1&amp;#039;,&lt;br /&gt;
    &amp;#039;text2&amp;#039;: &amp;#039;replacement2&amp;#039;,&lt;br /&gt;
    &amp;#039;text3&amp;#039;: &amp;#039;replacement3&amp;#039;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;regex(regularExpression, replacement)&amp;lt;/code&amp;gt;: This generates a simple [http://www.regular-expressions.info/ regex] filter. To use backreferences in the replacement argument, use &amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt; for group 1, &amp;lt;code&amp;gt;$2&amp;lt;/code&amp;gt; for group 2, etc.&lt;br /&gt;
* &amp;lt;code&amp;gt;regexes(regularExpressions)&amp;lt;/code&amp;gt;: The bulk version of the &amp;lt;code&amp;gt;regex&amp;lt;/code&amp;gt; filter generator. To use backreferences in the replacement argument, use &amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt; for group 1, &amp;lt;code&amp;gt;$2&amp;lt;/code&amp;gt; for group 2, etc. &amp;lt;code&amp;gt;regularExpressions&amp;lt;/code&amp;gt; should be a [http://docs.python.org/tutorial/datastructures.html#dictionaries Python dictionary] of the form:&lt;br /&gt;
&amp;lt;pre&amp;gt;{&lt;br /&gt;
    &amp;#039;regex1&amp;#039;: &amp;#039;replacement1&amp;#039;,&lt;br /&gt;
    &amp;#039;regex2&amp;#039;: &amp;#039;replacement2&amp;#039;,&lt;br /&gt;
    &amp;#039;regex3&amp;#039;: &amp;#039;replacement3&amp;#039;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wordFilter(correctWord, alternateWord1, alternateWord2, ...)&amp;lt;/code&amp;gt;: This generates a filter guaranteed to be applied only to whole words (if used as safe filter), and with wikitext aliases. The first argument, &amp;lt;code&amp;gt;correctWord&amp;lt;/code&amp;gt;, is the &amp;quot;correct&amp;quot; spelling of the word. The rest of the arguments are regular expressions (that only match whole words! You do not need to check for this) which will be replaced with &amp;lt;code&amp;gt;correctWord&amp;lt;/code&amp;gt;. Note that you can (and should) repeat &amp;lt;code&amp;gt;correctWord&amp;lt;/code&amp;gt; as one of the alternate spellings, in order to enforce &amp;lt;code&amp;gt;correctWord&amp;lt;/code&amp;gt;&amp;#039;s capitalization.&lt;br /&gt;
* &amp;lt;code&amp;gt;enforceCapitalization(word1, word2, ...)&amp;lt;/code&amp;gt;: This is effectively the same as &amp;lt;code&amp;gt;wordFilter(word1, word1); wordFilter(word2, word2); ...&amp;lt;/code&amp;gt;. It adds &amp;lt;code&amp;gt;word1&amp;lt;/code&amp;gt; itself as a spelling of &amp;lt;code&amp;gt;word1&amp;lt;/code&amp;gt;, which replaces all instances of &amp;lt;code&amp;gt;word1&amp;lt;/code&amp;gt; by the correctly-capitalized version of it. Note: You &amp;#039;&amp;#039;&amp;#039;do not need&amp;#039;&amp;#039;&amp;#039; to call &amp;lt;code&amp;gt;addSafeFilter&amp;lt;/code&amp;gt; on this one. &amp;lt;code&amp;gt;enforceCapitalization&amp;lt;/code&amp;gt; automatically calls &amp;lt;code&amp;gt;addSafeFilter&amp;lt;/code&amp;gt; by itself, as it is meant to be used only on textual content.&lt;br /&gt;
* &amp;lt;code&amp;gt;associateLocaleWordFilters(languages, fromLang, toLang, targetPageLang)&amp;lt;/code&amp;gt;: This generates word filters for all strings in the localization dictionary &amp;lt;code&amp;gt;languages&amp;lt;/code&amp;gt;, going from language &amp;lt;code&amp;gt;fromLang&amp;lt;/code&amp;gt; to language &amp;lt;code&amp;gt;toLang&amp;lt;/code&amp;gt;. This function automatically adds the generated word filters to the safe filters list. If the &amp;lt;code&amp;gt;targetPageLang&amp;lt;/code&amp;gt; argument is provided, the word filters will be applied only on pages in that language (for example, &amp;lt;code&amp;gt;targetPageLang=&amp;#039;de&amp;#039;&amp;lt;/code&amp;gt; will make the filters only be applied on /de pages).&lt;br /&gt;
&lt;br /&gt;
=== Link class definition ===&lt;br /&gt;
{{User:WindBOT/LinkClass}}&lt;/div&gt;</summary>
		<author><name>WindPower</name></author>
	</entry>
</feed>