<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.antiperfect.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hdridder</id>
	<title>wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.antiperfect.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hdridder"/>
	<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Special:Contributions/Hdridder"/>
	<updated>2026-10-18T00:20:18Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Processes&amp;diff=1735</id>
		<title>Processes</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Processes&amp;diff=1735"/>
		<updated>2026-10-15T12:35:49Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Linux/Unix]]&lt;br /&gt;
&lt;br /&gt;
;ps -aux&lt;br /&gt;
:Full information on all running processes. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND&lt;br /&gt;
root         1  0.0  0.0 191424  4420 ?        Ss    2019  63:30 /usr/lib/systemd/systemd --switched-root --system --deserialize 22&lt;br /&gt;
root         2  0.0  0.0      0     0 ?        S     2019   0:09 [kthreadd]&lt;br /&gt;
root         3  0.0  0.0      0     0 ?        S     2019   5:28 [ksoftirqd/0]&lt;br /&gt;
root         5  0.0  0.0      0     0 ?        S&amp;lt;    2019   0:00 [kworker/0:0H]&lt;br /&gt;
root         7  0.0  0.0      0     0 ?        S     2019   0:05 [migration/0]&lt;br /&gt;
root         8  0.0  0.0      0     0 ?        S     2019   0:00 [rcu_bh]&lt;br /&gt;
root         9  0.1  0.0      0     0 ?        S     2019 341:06 [rcu_sched]&lt;br /&gt;
root        10  0.0  0.0      0     0 ?        S&amp;lt;    2019   0:00 [lru-add-drain]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;kill &amp;lt;pid&amp;gt;&lt;br /&gt;
:Send the TERM signal (usually 9) to the process with PID-&amp;lt;pid&amp;gt;&lt;br /&gt;
;killall &amp;lt;commandname&amp;gt;&lt;br /&gt;
:Kill all processes with the name &amp;lt;commandname&amp;gt; this is the name as shown by ps -ef or ps -aux without any options or parameters.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;nohup &amp;lt;cmd&amp;gt; &amp;amp;&lt;br /&gt;
:Run &amp;lt;cmd&amp;gt; in the background with no connection to the terminal. Closing the terminal does not stop the command from running. All output is sent do a &amp;lt;code&amp;gt;nohup.out&amp;lt;/code&amp;gt; file in the current directory.&lt;br /&gt;
;jobs&lt;br /&gt;
:Show the processes belonging to yours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a command running on your terminal with CRTL-z you pause the process and are returned to the bash prompt.&lt;br /&gt;
;bg&lt;br /&gt;
:Put the process in the background, it starts running again&lt;br /&gt;
;disown&lt;br /&gt;
:Disconnect the process from the parent. You can not close the terminal without stopping the process. You cannot see this process with jobs anymore.&lt;br /&gt;
;ps -u $USER -f&lt;br /&gt;
:Show all processes for your username (-f for full format)&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Gpg&amp;diff=1734</id>
		<title>Gpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Gpg&amp;diff=1734"/>
		<updated>2026-10-09T14:02:19Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: Created page with &amp;quot;GNU Privacy Guard [https://gnupg.org/][https://en.wikipedia.org/wiki/GNU_Privacy_Guard]  ;gpg --list-keys :Show your keys ;gpg --fetch-keys &amp;quot;&amp;lt;URL to keys&amp;gt;&amp;quot; :Import keys ;curl &amp;quot;&amp;lt;URL to keys&amp;gt;&amp;quot; -o &amp;lt;outputfile&amp;gt; :Download keys to outputfile ;gpg --import &amp;lt;file&amp;gt; :import keys from file ;gpg --verify &amp;lt;signature file&amp;gt; &amp;lt;package file&amp;gt; :Verify if the signature file matches the package file. If the file was changed after the signature file was created someone may have tampered it. :I...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;GNU Privacy Guard [https://gnupg.org/][https://en.wikipedia.org/wiki/GNU_Privacy_Guard]&lt;br /&gt;
&lt;br /&gt;
;gpg --list-keys&lt;br /&gt;
:Show your keys&lt;br /&gt;
;gpg --fetch-keys &amp;quot;&amp;lt;URL to keys&amp;gt;&amp;quot;&lt;br /&gt;
:Import keys&lt;br /&gt;
;curl &amp;quot;&amp;lt;URL to keys&amp;gt;&amp;quot; -o &amp;lt;outputfile&amp;gt;&lt;br /&gt;
:Download keys to outputfile&lt;br /&gt;
;gpg --import &amp;lt;file&amp;gt;&lt;br /&gt;
:import keys from file&lt;br /&gt;
;gpg --verify &amp;lt;signature file&amp;gt; &amp;lt;package file&amp;gt;&lt;br /&gt;
:Verify if the signature file matches the package file. If the file was changed after the signature file was created someone may have tampered it.&lt;br /&gt;
:If OK the results has: &amp;lt;code&amp;gt;Good signature from ....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you are sure a key is from a trustworthy person you can trust it in the gpg software directly or from the command-line.&lt;br /&gt;
;gpg --export-ownertrust &amp;gt; trust.txt&lt;br /&gt;
:Export the trust database&lt;br /&gt;
;gpg --import-ownertrust &amp;lt; trust.txt&lt;br /&gt;
:Import into the trust database&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=MariaDB/MySQL&amp;diff=1733</id>
		<title>MariaDB/MySQL</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=MariaDB/MySQL&amp;diff=1733"/>
		<updated>2026-10-04T13:21:51Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Login to password user without plain text password on commandline */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://mariadb.org/ MariaDB] is an open source fork of [http://www.mysql.com/ MySQL]. There are some differences but most are internal, for users the commands and [[SQL]] syntax is exactly the same.&lt;br /&gt;
&lt;br /&gt;
[https://www.phpmyadmin.net/ phpMyAdmin] is a web based GUI for the maintenance of MariaDB and MySQL servers.&lt;br /&gt;
&lt;br /&gt;
=Performance related queries=&lt;br /&gt;
;show status like &#039;Qcache_total_blocks&#039;&lt;br /&gt;
:Fragmentation of the query cache (lower is better)&lt;br /&gt;
;flush query cache&lt;br /&gt;
:Flush the query cache to fix the fragmentation (check if cache sizes need to be changed too)&lt;br /&gt;
&lt;br /&gt;
=User management=&lt;br /&gt;
User data is stored in table mysql.user&lt;br /&gt;
;alter user username@host identified by &#039;password&#039;&lt;br /&gt;
:Change a users password&lt;br /&gt;
;drop user username@host&lt;br /&gt;
:Delete a user&lt;br /&gt;
;grans all privileges on *.* to &#039;user&#039;@&#039;host&#039;;&lt;br /&gt;
:Grant all privileges to all database to a user&lt;br /&gt;
&lt;br /&gt;
=Login to password user without plain text password on commandline=&lt;br /&gt;
Put the password in a protected config file.&lt;br /&gt;
&lt;br /&gt;
 vi ~/.my.cnf&lt;br /&gt;
 [client]&lt;br /&gt;
 password=&amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 chmod 600 ~/.my.cnf&lt;br /&gt;
&lt;br /&gt;
When you want to use a different filename start the mysql-client like&lt;br /&gt;
 mysql --defaults-file=/home/francis/mysql-opts&lt;br /&gt;
&lt;br /&gt;
NOTE: commands can be stored in the history logging. Make sure the log-file (~/.mysql_history) has very restrictive permissions&lt;br /&gt;
&lt;br /&gt;
=Move users from one server to another=&lt;br /&gt;
&lt;br /&gt;
Starting on the source server execute this script&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
PASSWORD=$1&lt;br /&gt;
mysql -B -N -uroot -p${PASSWORD} -e &amp;quot;SELECT CONCAT(&#039;\&#039;&#039;, user,&#039;\&#039;@\&#039;&#039;, host, &#039;\&#039;&#039;) FROM user WHERE user IN (&#039;username1&#039;, &#039;username2&#039;, &#039;username3&#039;)&amp;quot; &amp;gt; users.txt&lt;br /&gt;
while read line&lt;br /&gt;
 do&lt;br /&gt;
  mysql -B -N -uroot -p${PASSWORD} -e &amp;quot;SHOW GRANTS FOR $line&amp;quot;&lt;br /&gt;
 done &amp;lt; users.txt &amp;gt; users.sql&lt;br /&gt;
sed -i &#039;s/$/;/&#039; users.sql&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move the file to the other server and there do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p &amp;lt; users.sql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Set up replication=&lt;br /&gt;
With replication all transactions on the master database server are immediately replicated to the slave database server. So you create a hot copy of the database that can be used in case of a failure of the master server or to offload the master server by executing retrieval queries on the slave.&lt;br /&gt;
&lt;br /&gt;
The slave server logs into the master and checks if the bin-log position differs, if so all transactions after the last binlog-position are redone on the slave.&lt;br /&gt;
&lt;br /&gt;
This procedure is for a large part based on a tutorial found on howtoforge.com [https://www.howtoforge.com/mysql_database_replication]&lt;br /&gt;
&lt;br /&gt;
For multi master replication to 1 slave check [https://mariadb.com/kb/en/multi-source-replication/ this].&lt;br /&gt;
&lt;br /&gt;
==On the master==&lt;br /&gt;
;Edit the my.cnf so it has below lines.&lt;br /&gt;
:The server must be accessible from the slave server and the server-id must be unique in you network&lt;br /&gt;
:The binlog-do-db specifies for which database the binlog is written, one line per database. If omitted for all databases binlog is written except those specified by binlog-ingnore-db.&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 #bind-address            = 127.0.0.1&lt;br /&gt;
 log-bin = /var/log/mysql/mysql-bin.log&lt;br /&gt;
 #binlog-do-db=exampledb&lt;br /&gt;
 binlog-ignore-db       = mysql&lt;br /&gt;
 binlog-ignore-db       = information_schema&lt;br /&gt;
 binlog-ignore-db       = performance_schema&lt;br /&gt;
 binlog-ignore-db       = phpmyadmin&lt;br /&gt;
 server-id=1&lt;br /&gt;
&lt;br /&gt;
;Restart the database server&lt;br /&gt;
 /etc/init.d/mysql restart&lt;br /&gt;
&lt;br /&gt;
;Create a replication user&lt;br /&gt;
 mysql -uroot -p&lt;br /&gt;
 mysql&amp;gt; GRANT REPLICATION SLAVE ON *.* TO &#039;slave_user&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt;some_password&amp;gt;&#039;;&lt;br /&gt;
 mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
;Make sure nothing is changes in the database during backup&lt;br /&gt;
 mysql&amp;gt; USE exampledb;&lt;br /&gt;
 mysql&amp;gt; FLUSH TABLES WITH READ LOCK;&lt;br /&gt;
Or, for all databases;&lt;br /&gt;
 mysql&amp;gt; FLUSH TABLES WITH READ LOCK;&lt;br /&gt;
 mysql&amp;gt; SET GLOBAL read_only = 1;&lt;br /&gt;
;Check status;&lt;br /&gt;
 mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 | File          | Position | Binlog_do_db | Binlog_ignore_db |&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 | mysql-bin.006 | 183      |              |                  |&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
;Dump the database:&lt;br /&gt;
 mysqldump -u root -p&amp;lt;password&amp;gt; --opt exampledb &amp;gt; exampledb.sql&lt;br /&gt;
&lt;br /&gt;
;Unlock the tables&lt;br /&gt;
 mysql -u root -p&amp;lt;password&amp;gt;&lt;br /&gt;
 mysql&amp;gt; UNLOCK TABLES;&lt;br /&gt;
 mysql&amp;gt; quit;&lt;br /&gt;
Or, for all databases;&lt;br /&gt;
 mysql&amp;gt; SET GLOBAL read_only = 0;&lt;br /&gt;
 mysql&amp;gt; UNLOCK TABLES;&lt;br /&gt;
&lt;br /&gt;
==On the slave server==&lt;br /&gt;
&lt;br /&gt;
;Create the slave database&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
CREATE DATABASE exampledb;&lt;br /&gt;
quit;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Load the database dump created on the master&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt; exampledb &amp;lt; /path/to/exampledb.sql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Edit the my.cnf so it has these lines&lt;br /&gt;
:The server-id must be unique in you network&lt;br /&gt;
:The replicate-do-db specifies for which database the binlog on the master is read, one line per database. If omitted for all databases binlog is read.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
server-id=2&lt;br /&gt;
replicate-do-db=exampledb&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Restart the database server&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/init.d/mysql restart&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the following statement the values from SHOW MASTER STATUS above must be used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
STOP SLAVE;&lt;br /&gt;
CHANGE MASTER TO MASTER_HOST=&amp;lt;masterIP&amp;gt;, MASTER_USER=&#039;slave_user&#039;, MASTER_PASSWORD=&#039;&amp;lt;password&amp;gt;&#039;, MASTER_LOG_FILE=&#039;mysql-bin.006&#039;, MASTER_LOG_POS=183; &lt;br /&gt;
START SLAVE;&lt;br /&gt;
quit;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====In case of using GTID for replication====&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
CHANGE MASTER TO master_host= &amp;lt;masterIP&amp;gt;&#039;, master_user=&#039;&amp;lt;slave_user&amp;gt;&#039;, MASTER_PASSWORD=&#039;&amp;lt;password&amp;gt;&#039;, master_use_gtid=current_pos;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SELECT @@GLOBAL.gtid_slave_pos;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Show current GTID position&lt;br /&gt;
;&amp;lt;code&amp;gt;SET GLOBAL gtid_slave_pos = &amp;quot;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Reset counter, slave databases must be in sync with the master.&lt;br /&gt;
&lt;br /&gt;
=Add a database to replication=&lt;br /&gt;
&lt;br /&gt;
Everything must be working fine and log positions up to date. On the slave Read_Master_Log_Pos is the same as the Exec_Master_Log_Pos and the Read_Master_Log_Pos is the same as the masters Position (in show master status).&lt;br /&gt;
&lt;br /&gt;
Then you can do:&lt;br /&gt;
* Slave: Add database to my.cnf (replicate-do-db=&amp;lt;dbname&amp;gt;)&lt;br /&gt;
* Slave: &amp;lt;code&amp;gt;stop slave;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Master: &amp;lt;code&amp;gt;flush tables with read lock;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Master: dump database&lt;br /&gt;
* Master: &amp;lt;code&amp;gt;unlock tables&amp;lt;/code&amp;gt;&lt;br /&gt;
* Slave: Load the database dump&lt;br /&gt;
* Slave: Restart the database server&lt;br /&gt;
Then check the slave status &amp;lt;code&amp;gt;show slave status \G&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Repair replication=&lt;br /&gt;
==On the slave server==&lt;br /&gt;
;Stop replication processes&lt;br /&gt;
 mysql -u root -p&lt;br /&gt;
 mysql&amp;gt; stop slave;&lt;br /&gt;
&lt;br /&gt;
==On the master server==&lt;br /&gt;
Dump the replicated databases including the replication data.&lt;br /&gt;
&amp;lt;code&amp;gt;mysqldump --databases &amp;lt;db1&amp;gt; &amp;lt;db2&amp;gt; --master-data=1 &amp;gt; ../mysql_dump_$(hostname)_$(date +%Y-%m-%d_%H-%M).sql.dump&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==On the slave server==&lt;br /&gt;
;Import the databases&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -uroot -p &amp;lt; &amp;lt;dumpfile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;Restart the slave processes and check the slave status.&lt;br /&gt;
When needed update the slave log-file and position as in the masters &amp;lt;code&amp;gt;show slave status&amp;lt;/code&amp;gt;&lt;br /&gt;
 mysql&amp;gt; CHANGE MASTER TO MASTER_LOG_FILE=&#039;&amp;lt;filename&amp;gt;&#039;, MASTER_LOG_POS=&amp;lt;postition&amp;gt;; &lt;br /&gt;
Then:&lt;br /&gt;
 mysql&amp;gt; start slave;&lt;br /&gt;
 mysql&amp;gt; show slave status \G&lt;br /&gt;
&lt;br /&gt;
This should not show any errors&lt;br /&gt;
&lt;br /&gt;
=Populate and update timezone information=&lt;br /&gt;
Timezone information is required to use functions like CONVERT_TZ. The mysql.time_zone table need to be populated and maintained when the data changes.&lt;br /&gt;
&lt;br /&gt;
On a [[synology]] server following command takes care of this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/volume1/@appstore/MariaDB10/usr/local/mariadb10/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo |mysql -uroot -p mysql&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=MariaDB/MySQL&amp;diff=1732</id>
		<title>MariaDB/MySQL</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=MariaDB/MySQL&amp;diff=1732"/>
		<updated>2026-10-04T13:09:15Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Login to password user without plain text password on commandline */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://mariadb.org/ MariaDB] is an open source fork of [http://www.mysql.com/ MySQL]. There are some differences but most are internal, for users the commands and [[SQL]] syntax is exactly the same.&lt;br /&gt;
&lt;br /&gt;
[https://www.phpmyadmin.net/ phpMyAdmin] is a web based GUI for the maintenance of MariaDB and MySQL servers.&lt;br /&gt;
&lt;br /&gt;
=Performance related queries=&lt;br /&gt;
;show status like &#039;Qcache_total_blocks&#039;&lt;br /&gt;
:Fragmentation of the query cache (lower is better)&lt;br /&gt;
;flush query cache&lt;br /&gt;
:Flush the query cache to fix the fragmentation (check if cache sizes need to be changed too)&lt;br /&gt;
&lt;br /&gt;
=User management=&lt;br /&gt;
User data is stored in table mysql.user&lt;br /&gt;
;alter user username@host identified by &#039;password&#039;&lt;br /&gt;
:Change a users password&lt;br /&gt;
;drop user username@host&lt;br /&gt;
:Delete a user&lt;br /&gt;
;grans all privileges on *.* to &#039;user&#039;@&#039;host&#039;;&lt;br /&gt;
:Grant all privileges to all database to a user&lt;br /&gt;
&lt;br /&gt;
=Login to password user without plain text password on commandline=&lt;br /&gt;
Put the password in a protected config file.&lt;br /&gt;
&lt;br /&gt;
 vi ~/.my.conf&lt;br /&gt;
 [client]&lt;br /&gt;
 password=&amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 chmod 600 ~/.my.cnf&lt;br /&gt;
&lt;br /&gt;
When you want to use a different filename start the mysql-client like&lt;br /&gt;
 mysql --defaults-file=/home/francis/mysql-opts&lt;br /&gt;
&lt;br /&gt;
NOTE: commands can be stored in the history logging. Make sure the log-file (~/.mysql_history) has very restrictive permissions&lt;br /&gt;
&lt;br /&gt;
=Move users from one server to another=&lt;br /&gt;
&lt;br /&gt;
Starting on the source server execute this script&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
PASSWORD=$1&lt;br /&gt;
mysql -B -N -uroot -p${PASSWORD} -e &amp;quot;SELECT CONCAT(&#039;\&#039;&#039;, user,&#039;\&#039;@\&#039;&#039;, host, &#039;\&#039;&#039;) FROM user WHERE user IN (&#039;username1&#039;, &#039;username2&#039;, &#039;username3&#039;)&amp;quot; &amp;gt; users.txt&lt;br /&gt;
while read line&lt;br /&gt;
 do&lt;br /&gt;
  mysql -B -N -uroot -p${PASSWORD} -e &amp;quot;SHOW GRANTS FOR $line&amp;quot;&lt;br /&gt;
 done &amp;lt; users.txt &amp;gt; users.sql&lt;br /&gt;
sed -i &#039;s/$/;/&#039; users.sql&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move the file to the other server and there do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p &amp;lt; users.sql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Set up replication=&lt;br /&gt;
With replication all transactions on the master database server are immediately replicated to the slave database server. So you create a hot copy of the database that can be used in case of a failure of the master server or to offload the master server by executing retrieval queries on the slave.&lt;br /&gt;
&lt;br /&gt;
The slave server logs into the master and checks if the bin-log position differs, if so all transactions after the last binlog-position are redone on the slave.&lt;br /&gt;
&lt;br /&gt;
This procedure is for a large part based on a tutorial found on howtoforge.com [https://www.howtoforge.com/mysql_database_replication]&lt;br /&gt;
&lt;br /&gt;
For multi master replication to 1 slave check [https://mariadb.com/kb/en/multi-source-replication/ this].&lt;br /&gt;
&lt;br /&gt;
==On the master==&lt;br /&gt;
;Edit the my.cnf so it has below lines.&lt;br /&gt;
:The server must be accessible from the slave server and the server-id must be unique in you network&lt;br /&gt;
:The binlog-do-db specifies for which database the binlog is written, one line per database. If omitted for all databases binlog is written except those specified by binlog-ingnore-db.&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 #bind-address            = 127.0.0.1&lt;br /&gt;
 log-bin = /var/log/mysql/mysql-bin.log&lt;br /&gt;
 #binlog-do-db=exampledb&lt;br /&gt;
 binlog-ignore-db       = mysql&lt;br /&gt;
 binlog-ignore-db       = information_schema&lt;br /&gt;
 binlog-ignore-db       = performance_schema&lt;br /&gt;
 binlog-ignore-db       = phpmyadmin&lt;br /&gt;
 server-id=1&lt;br /&gt;
&lt;br /&gt;
;Restart the database server&lt;br /&gt;
 /etc/init.d/mysql restart&lt;br /&gt;
&lt;br /&gt;
;Create a replication user&lt;br /&gt;
 mysql -uroot -p&lt;br /&gt;
 mysql&amp;gt; GRANT REPLICATION SLAVE ON *.* TO &#039;slave_user&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt;some_password&amp;gt;&#039;;&lt;br /&gt;
 mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
;Make sure nothing is changes in the database during backup&lt;br /&gt;
 mysql&amp;gt; USE exampledb;&lt;br /&gt;
 mysql&amp;gt; FLUSH TABLES WITH READ LOCK;&lt;br /&gt;
Or, for all databases;&lt;br /&gt;
 mysql&amp;gt; FLUSH TABLES WITH READ LOCK;&lt;br /&gt;
 mysql&amp;gt; SET GLOBAL read_only = 1;&lt;br /&gt;
;Check status;&lt;br /&gt;
 mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 | File          | Position | Binlog_do_db | Binlog_ignore_db |&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 | mysql-bin.006 | 183      |              |                  |&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
;Dump the database:&lt;br /&gt;
 mysqldump -u root -p&amp;lt;password&amp;gt; --opt exampledb &amp;gt; exampledb.sql&lt;br /&gt;
&lt;br /&gt;
;Unlock the tables&lt;br /&gt;
 mysql -u root -p&amp;lt;password&amp;gt;&lt;br /&gt;
 mysql&amp;gt; UNLOCK TABLES;&lt;br /&gt;
 mysql&amp;gt; quit;&lt;br /&gt;
Or, for all databases;&lt;br /&gt;
 mysql&amp;gt; SET GLOBAL read_only = 0;&lt;br /&gt;
 mysql&amp;gt; UNLOCK TABLES;&lt;br /&gt;
&lt;br /&gt;
==On the slave server==&lt;br /&gt;
&lt;br /&gt;
;Create the slave database&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
CREATE DATABASE exampledb;&lt;br /&gt;
quit;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Load the database dump created on the master&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt; exampledb &amp;lt; /path/to/exampledb.sql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Edit the my.cnf so it has these lines&lt;br /&gt;
:The server-id must be unique in you network&lt;br /&gt;
:The replicate-do-db specifies for which database the binlog on the master is read, one line per database. If omitted for all databases binlog is read.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
server-id=2&lt;br /&gt;
replicate-do-db=exampledb&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Restart the database server&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/init.d/mysql restart&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the following statement the values from SHOW MASTER STATUS above must be used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
STOP SLAVE;&lt;br /&gt;
CHANGE MASTER TO MASTER_HOST=&amp;lt;masterIP&amp;gt;, MASTER_USER=&#039;slave_user&#039;, MASTER_PASSWORD=&#039;&amp;lt;password&amp;gt;&#039;, MASTER_LOG_FILE=&#039;mysql-bin.006&#039;, MASTER_LOG_POS=183; &lt;br /&gt;
START SLAVE;&lt;br /&gt;
quit;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====In case of using GTID for replication====&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
CHANGE MASTER TO master_host= &amp;lt;masterIP&amp;gt;&#039;, master_user=&#039;&amp;lt;slave_user&amp;gt;&#039;, MASTER_PASSWORD=&#039;&amp;lt;password&amp;gt;&#039;, master_use_gtid=current_pos;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SELECT @@GLOBAL.gtid_slave_pos;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Show current GTID position&lt;br /&gt;
;&amp;lt;code&amp;gt;SET GLOBAL gtid_slave_pos = &amp;quot;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Reset counter, slave databases must be in sync with the master.&lt;br /&gt;
&lt;br /&gt;
=Add a database to replication=&lt;br /&gt;
&lt;br /&gt;
Everything must be working fine and log positions up to date. On the slave Read_Master_Log_Pos is the same as the Exec_Master_Log_Pos and the Read_Master_Log_Pos is the same as the masters Position (in show master status).&lt;br /&gt;
&lt;br /&gt;
Then you can do:&lt;br /&gt;
* Slave: Add database to my.cnf (replicate-do-db=&amp;lt;dbname&amp;gt;)&lt;br /&gt;
* Slave: &amp;lt;code&amp;gt;stop slave;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Master: &amp;lt;code&amp;gt;flush tables with read lock;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Master: dump database&lt;br /&gt;
* Master: &amp;lt;code&amp;gt;unlock tables&amp;lt;/code&amp;gt;&lt;br /&gt;
* Slave: Load the database dump&lt;br /&gt;
* Slave: Restart the database server&lt;br /&gt;
Then check the slave status &amp;lt;code&amp;gt;show slave status \G&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Repair replication=&lt;br /&gt;
==On the slave server==&lt;br /&gt;
;Stop replication processes&lt;br /&gt;
 mysql -u root -p&lt;br /&gt;
 mysql&amp;gt; stop slave;&lt;br /&gt;
&lt;br /&gt;
==On the master server==&lt;br /&gt;
Dump the replicated databases including the replication data.&lt;br /&gt;
&amp;lt;code&amp;gt;mysqldump --databases &amp;lt;db1&amp;gt; &amp;lt;db2&amp;gt; --master-data=1 &amp;gt; ../mysql_dump_$(hostname)_$(date +%Y-%m-%d_%H-%M).sql.dump&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==On the slave server==&lt;br /&gt;
;Import the databases&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -uroot -p &amp;lt; &amp;lt;dumpfile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;Restart the slave processes and check the slave status.&lt;br /&gt;
When needed update the slave log-file and position as in the masters &amp;lt;code&amp;gt;show slave status&amp;lt;/code&amp;gt;&lt;br /&gt;
 mysql&amp;gt; CHANGE MASTER TO MASTER_LOG_FILE=&#039;&amp;lt;filename&amp;gt;&#039;, MASTER_LOG_POS=&amp;lt;postition&amp;gt;; &lt;br /&gt;
Then:&lt;br /&gt;
 mysql&amp;gt; start slave;&lt;br /&gt;
 mysql&amp;gt; show slave status \G&lt;br /&gt;
&lt;br /&gt;
This should not show any errors&lt;br /&gt;
&lt;br /&gt;
=Populate and update timezone information=&lt;br /&gt;
Timezone information is required to use functions like CONVERT_TZ. The mysql.time_zone table need to be populated and maintained when the data changes.&lt;br /&gt;
&lt;br /&gt;
On a [[synology]] server following command takes care of this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/volume1/@appstore/MariaDB10/usr/local/mariadb10/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo |mysql -uroot -p mysql&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Help:Wiki&amp;diff=1731</id>
		<title>Help:Wiki</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Help:Wiki&amp;diff=1731"/>
		<updated>2026-09-25T14:53:10Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Upgrade */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Help]]&lt;br /&gt;
=Generic=&lt;br /&gt;
Wiki formatting options[https://www.mediawiki.org/wiki/Help:Formatting] or check Mediawiki advanced editing[https://www.mediawiki.org/wiki/Help:Advanced_editing] for more.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&amp;lt;syntaxhighlight lang=&#039;bash&#039;&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Block of code formatted for the specified [http://pygments.org/languages/ language]&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Do not apply wiki formatting on this block&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;;&amp;lt;/nowiki&amp;gt; Definition list term (&amp;lt;nowiki&amp;gt;&amp;lt;dt&amp;gt;&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
:&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Definition list definition or just indent(&amp;lt;nowiki&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
::&amp;lt;nowiki&amp;gt;::&amp;lt;/nowiki&amp;gt; Indent more&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Bullit list&lt;br /&gt;
* Bullit list &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; Numbered list&lt;br /&gt;
# Numbered list&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;[[category:name]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Add this page to category &#039;name&#039;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;[[wikipage|alt text]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Link to page on local wiki. When provided &#039;alt text&#039; is displayed instead of the page name. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;[[wikipage#Anchor|alt text]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Link to anchor on local wiki page. Headings, span and div&#039;s are automatic anchors.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&amp;lt;span id=Anchor1&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&amp;lt;div id=Anchor1&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;=Heading=&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Create anchor (works for each heading level)&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;[URL text]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Link to URL. When text is not provided the link&#039;s consecutive number is displayed.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;&#039;&#039;italics&#039;&#039;&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&#039;&#039;&#039;&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;bold&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;&#039;&#039;&#039;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;bold italics&#039;&#039;&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;&amp;lt;code&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;code&amp;gt;Fixed width text&amp;lt;/code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Tables[https://www.mediawiki.org/wiki/Help:Tables]=&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:60%&amp;quot;&lt;br /&gt;
| style=&amp;quot;padding: 10px;&amp;quot;| &amp;lt;big&amp;gt;&amp;lt;nowiki&amp;gt;{|&amp;lt;/nowiki&amp;gt;&amp;lt;/big&amp;gt;&lt;br /&gt;
| style=&amp;quot;padding: 5px;&amp;quot;| &amp;lt;!--T:9--&amp;gt; &#039;&#039;&#039;table start&#039;&#039;&#039;, &#039;&#039;required&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px;&amp;quot;| &amp;lt;big&amp;gt;&amp;lt;nowiki&amp;gt;|+&amp;lt;/nowiki&amp;gt;&amp;lt;/big&amp;gt;&lt;br /&gt;
| style=&amp;quot;padding: 5px;&amp;quot; | &amp;lt;!--T:10--&amp;gt; table &#039;&#039;&#039;caption&#039;&#039;&#039;, &#039;&#039;optional;&#039;&#039; only between &#039;&#039;&#039;table start&#039;&#039;&#039; and &#039;&#039;&#039;table row&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px;&amp;quot;| &amp;lt;big&amp;gt;&amp;lt;nowiki&amp;gt;|-&amp;lt;/nowiki&amp;gt;&amp;lt;/big&amp;gt;&lt;br /&gt;
| style=&amp;quot;padding: 5px;&amp;quot; | &amp;lt;!--T:11--&amp;gt; &#039;&#039;&#039;table row&#039;&#039;&#039;, &#039;&#039;optional on first row&#039;&#039;—wiki engine assumes the first row&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px;&amp;quot;| &amp;lt;big&amp;gt;&amp;lt;nowiki&amp;gt;!&amp;lt;/nowiki&amp;gt;&amp;lt;/big&amp;gt; &lt;br /&gt;
| style=&amp;quot;padding: 5px;&amp;quot; | &amp;lt;!--T:12--&amp;gt; &#039;&#039;&#039;table header&#039;&#039;&#039; cell, &#039;&#039;optional.&#039;&#039;&amp;lt;!--T:13--&amp;gt; Consecutive &#039;&#039;&#039;table header&#039;&#039;&#039; cells may be added on same line separated by double marks (&amp;lt;code&amp;gt;!!&amp;lt;/code&amp;gt;) or start on new lines, each with its own single mark (&amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;).&lt;br /&gt;
|- &lt;br /&gt;
| style=&amp;quot;padding: 10px;&amp;quot;| &amp;lt;big&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;/big&amp;gt;&lt;br /&gt;
| style=&amp;quot;padding: 5px;&amp;quot; | &amp;lt;!--T:14--&amp;gt; &#039;&#039;&#039;table data&#039;&#039;&#039; cell, &#039;&#039;optional&#039;&#039;.&amp;gt;&amp;lt;!--T:15--&amp;gt; Consecutive &#039;&#039;&#039;table data&#039;&#039;&#039; cells may be added on same line separated by double marks (&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;) or start on new lines, each with its own single mark (&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px;&amp;quot;| &amp;lt;big&amp;gt;&amp;lt;nowiki&amp;gt;|}&amp;lt;/nowiki&amp;gt;&amp;lt;/big&amp;gt;&lt;br /&gt;
| style=&amp;quot;padding: 5px;&amp;quot; | &amp;lt;!--T:379--&amp;gt; &#039;&#039;&#039;table end&#039;&#039;&#039;, &#039;&#039;required&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:60%&amp;quot;&amp;lt;/nowiki&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|+ Caption&amp;lt;/nowiki&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;! style=&amp;quot;width:30%&amp;quot;| Header&amp;lt;/nowiki&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;! style=&amp;quot;width:70%&amp;quot;| Header&amp;lt;/nowiki&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|-&amp;lt;/nowiki&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;| Content&amp;lt;/nowiki&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;| Content&amp;lt;/nowiki&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|}&amp;lt;/nowiki&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:60%&amp;quot;&lt;br /&gt;
|+ Caption&lt;br /&gt;
!Header&lt;br /&gt;
!Header&lt;br /&gt;
|- &lt;br /&gt;
| Content&lt;br /&gt;
| Content&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Formula&#039;s=&lt;br /&gt;
For formula rendering by the Math extension check these [https://meta.wikimedia.org/wiki/Help:Displaying_a_formula examples].&lt;br /&gt;
&lt;br /&gt;
Basic &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;math&amp;gt;formula&amp;lt;/math&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Embedded file (images)=&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[[file:RadioSpectrum.jpeg|400x1107px]]&amp;lt;/nowiki&amp;gt;. See the [https://www.mediawiki.org/wiki/Help:Images MediaWiki documentation].&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
After activating the [https://www.mediawiki.org/wiki/Extension:Cite Cite extentsion] in LocalSettings.php (wfLoadExtension( &#039;Cite&#039; );) you can put &amp;lt;nowiki&amp;gt;&amp;lt;ref&amp;gt;This is the reference&amp;lt;/ref&amp;gt;&amp;lt;/nowiki&amp;gt; in your text. At the end of the page you can put &amp;lt;nowiki&amp;gt;{{References}} or {{reflist}}&amp;lt;/nowiki&amp;gt; to have the references displayed.&lt;br /&gt;
&lt;br /&gt;
More on how to use references can be found with wikipedia [https://en.wikipedia.org/wiki/Help:Referencing_for_beginners][https://nl.wikipedia.org/wiki/Help:Referenties_en_voetnoten]&lt;br /&gt;
&lt;br /&gt;
=Add icons to the footer=&lt;br /&gt;
Add following to LocalSettings.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
$wgFooterIcons[&#039;poweredby&#039;][&#039;ipv6ready&#039;] = [&lt;br /&gt;
        &amp;quot;src&amp;quot; =&amp;gt; &amp;quot;https://ipv6-test.com/button-ipv6-small.png&amp;quot;,&lt;br /&gt;
        &amp;quot;url&amp;quot; =&amp;gt; &amp;quot;https://ipv6-test.com/validate.php?url=$wgServer&amp;quot;,&lt;br /&gt;
        &amp;quot;alt&amp;quot; =&amp;gt; &amp;quot;ipv6 ready&amp;quot;,&lt;br /&gt;
        &amp;quot;height&amp;quot; =&amp;gt; &amp;quot;31&amp;quot;,&lt;br /&gt;
        &amp;quot;width&amp;quot; =&amp;gt; &amp;quot;88&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
src can be a local file too. More information on the [https://www.mediawiki.org/wiki/Manual:$wgFooterIcons Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
=Sidebar editing=&lt;br /&gt;
;Edit the sidebar (not the Tools section there).&lt;br /&gt;
:Like editing a wikipage, goto //yourwikiurl/index.php?title=MediaWiki:Sidebar&lt;br /&gt;
:Syntax is a bit different, e.g. no &amp;lt;nowiki&amp;gt;[[]]&amp;lt;/nowiki&amp;gt; for links&lt;br /&gt;
:The preview has little to do with how the sidebar will look. You have to save to see the result&lt;br /&gt;
:More info on [https://www.mediawiki.org/wiki/Manual:Interface/Sidebar the MediaWiki manual]&lt;br /&gt;
&lt;br /&gt;
=Redirect=&lt;br /&gt;
Redirect pages verwijzen direct door naar een andere pagina. Zij bestaan uitsluitend uit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#REDIRECT &amp;lt;nowiki&amp;gt;[[pagina]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Delete page history=&lt;br /&gt;
20180817 BEWARE, yet untested &lt;br /&gt;
# Prodecure found here [http://www.hungryfools.com/2007/04/how-to-clean-up-change-history-of.html] that just invokes in the maintenance subdirectory &amp;lt;code&amp;gt;# php deleteOldRevisions.php --delete&amp;lt;/code&amp;gt;&lt;br /&gt;
# A more complex [http://www.bigsoft.co.uk/blog/2011/08/03/permanently-deleting-mediawiki-pages-and-revisions suggestion]&lt;br /&gt;
# [https://en.wikibooks.org/wiki/MediaWiki_Administrator%27s_Handbook/Page_Deletion#Restoring_some_or_all_deleted_revisions This page] advises to go to Special:Nuke, which does not exist on my wiki.&lt;br /&gt;
&lt;br /&gt;
=Installations and upgrades=&lt;br /&gt;
&lt;br /&gt;
==Upgrade==&lt;br /&gt;
* Make sure you have a backup of the current files and database.&lt;br /&gt;
* Download and extract mediawiki and your extenstions tar-files over the current.&lt;br /&gt;
* Check if LocalSettings.php, your ./images directory are not overwritten&lt;br /&gt;
* Make sure ./cache is empty&lt;br /&gt;
* Run &amp;lt;code&amp;gt;php ./maintenantce/updade.php&amp;lt;/code&amp;gt;&lt;br /&gt;
* Link your web-root to the new release&lt;br /&gt;
* Rename the old directory to xxx_old to make sure nothing is fetched from any cache (I have to do this despite removing browser history and nginx restarts)&lt;br /&gt;
&lt;br /&gt;
==CirrusSearch==&lt;br /&gt;
Search extension that supports more complex search phrases.&lt;br /&gt;
&lt;br /&gt;
For installation on mediawiki 1.35:&lt;br /&gt;
* Install java8 and [https://www.elastic.co/guide/en/elasticsearch/reference/6.8/getting-started-install.html#successfully-running-node elasticsearch 6.8.23]&lt;br /&gt;
** &amp;lt;code&amp;gt;apt-get install openjdk-8-jre-headless&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;echo &amp;quot;deb https://artifacts.elastic.co/packages/6.x/apt stable main&amp;quot; | sudo tee -a /etc/apt/sources.list.d/elastic-6.x.list&amp;lt;/code&amp;gt;&lt;br /&gt;
**&amp;lt;code&amp;gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install elasticsearch&amp;lt;/code&amp;gt;&lt;br /&gt;
* Install the Elastica and CirrusSearch (use the same version as your MediaWiki version) extensions [https://www.mediawiki.org/wiki/Extension:CirrusSearch]&lt;br /&gt;
* Follow instructions in ./extentions/CirrusSearch/README&lt;br /&gt;
** Add this to LocalSettings.php&lt;br /&gt;
 wfLoadExtension( &#039;Elastica&#039; );&lt;br /&gt;
 wfLoadExtension( &#039;CirrusSearch&#039; );&lt;br /&gt;
 $wgDisableSearchUpdate = true;&lt;br /&gt;
:*&amp;lt;code&amp;gt;php7.4 ./extensions/CirrusSearch/maintenance/UpdateSearchIndexConfig.php&amp;lt;/code&amp;gt;&lt;br /&gt;
:*Remove &amp;lt;code&amp;gt;$wgDisableSearchUpdate = true&amp;lt;/code&amp;gt; from LocalSettings.php&lt;br /&gt;
:*&amp;lt;code&amp;gt;php7.4 ./extensions/CirrusSearch/maintenance/ForceSearchIndex.php --skipLinks --indexOnSkip&amp;lt;/code&amp;gt;&lt;br /&gt;
:*&amp;lt;code&amp;gt;php7.4 ./extensions/CirrusSearch/maintenance/ForceSearchIndex.php --skipParse&amp;lt;/code&amp;gt;&lt;br /&gt;
:*Edit LocalSettings.php to have &amp;lt;code&amp;gt;$wgSearchType = &#039;CirrusSearch&#039;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check [[Special:Version]] to see if all is installed&lt;br /&gt;
&lt;br /&gt;
To verify CirrusSearch is used add &#039;&amp;amp;cirrusDumpQuery&#039; to a search URL. A json-string will be shown.&lt;br /&gt;
&lt;br /&gt;
See the [[elasticsearch]] page for more&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=PHP&amp;diff=1730</id>
		<title>PHP</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=PHP&amp;diff=1730"/>
		<updated>2026-09-25T13:59:47Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Upgrade */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:PHP]]&lt;br /&gt;
[[category:Webdesign]]&lt;br /&gt;
=Basics=&lt;br /&gt;
Script language for dynamic web-pages. The syntax and concepts used are similar to [[Perl]]&lt;br /&gt;
&lt;br /&gt;
;Limited number of loops&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt; &lt;br /&gt;
for ($i = 0; $i &amp;lt;= 6; $i++) {&lt;br /&gt;
  echo &amp;quot;Loop number: $i &amp;quot;;&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;escapeshellcmd(shellcommand)&lt;br /&gt;
:Return the shellcommand with everything that might confuse the shell escaped.&lt;br /&gt;
;exec(&amp;lt;cmd&amp;gt;,&amp;lt;outputarray&amp;gt;,&amp;lt;returnvar&amp;gt;)&lt;br /&gt;
:Executed &amp;lt;cmd&amp;gt; in the shell, append the command output to he array &amp;lt;outputarray&amp;gt; and set &amp;lt;returnvar&amp;gt; to the returnvalue of the command.&lt;br /&gt;
:Also the last line of the command output is returned&lt;br /&gt;
;shell_exec(&amp;lt;cmd&amp;gt;)&lt;br /&gt;
:Execute &amp;lt;cmd&amp;gt; (output from excapedshellcmd) in the shell, return the command output.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;date(&amp;quot;Y-m-d h:i:s&amp;quot;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Current timestamp (YYYY-mm-dd HH:MM:SS).&lt;br /&gt;
:Format &amp;quot;U&amp;quot; is [https://duckduckgo.com/?q=unixtime unixtime] (seconds since epoch)&lt;br /&gt;
;sprintf(&amp;quot;%7.2f&amp;quot;, $float )&lt;br /&gt;
:Format a number (7 digits, 2 decimals)&lt;br /&gt;
;number_format($number, 2, &#039;.&#039;, &#039;,&#039;)&lt;br /&gt;
:Format $number with 2 decimals, . as decimal separator and , as thousand separator.&lt;br /&gt;
&lt;br /&gt;
;strpos($string, $search,$start)&lt;br /&gt;
:Return position of $search exists in $string. When it is not in, return FALSE. Start searching at position $start (optional). Simple test on strpos - &amp;lt;code&amp;gt;if (strpos(x,y)) {}&amp;lt;/code&amp;gt; - does not differ between position 0 and FALSE. Test on position 2 or count from the end by setting $start to a negative value (possible since PHP7.1).&lt;br /&gt;
;str_replace($old, $new, $string)&lt;br /&gt;
:Return $string with $old replaced by $new&lt;br /&gt;
;trim($string, &#039;abc&#039;)&lt;br /&gt;
:Remove characters a, b and c from the start and the end of $string. If no characters are specified all whitespace will be removed.&lt;br /&gt;
&lt;br /&gt;
;round($float,&amp;lt;precision&amp;gt;)&lt;br /&gt;
:Round $float to &amp;lt;precision&amp;gt; decimals (0 is default)&lt;br /&gt;
&lt;br /&gt;
=Regular expressions=&lt;br /&gt;
PHP is Perl-like, patterns need delimiters (default is /&amp;lt;pattern&amp;gt;/ )&lt;br /&gt;
;preg_match($pattern, $string)&lt;br /&gt;
:Return 1 if $pattern exists in $string&lt;br /&gt;
;preg_split(&#039;/\s*\=+\s*/&#039;,$string &lt;br /&gt;
:Split $string into an array on a pattern (in this example on white-spaces and equality signs.&lt;br /&gt;
;preg_replace(&#039;/#.*$/&#039;,&#039;&#039;,$string);&lt;br /&gt;
:Replace matches with the pattern in $string (in this example to remove comments from a line)&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
Almost all you need to know about files. For writing open with &#039;w&#039; and fwrite($fh,$line)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
$fh = fopen($filename, &#039;r&#039;) or die(&#039;Unable to open &#039;.$file);&lt;br /&gt;
while(!feof($fh)) {&lt;br /&gt;
  $line =  fgets($fh);&lt;br /&gt;
}&lt;br /&gt;
fclose($fh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
$dir = &amp;quot;./&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// Open a directory, and read its contents&lt;br /&gt;
if (is_dir($dir)){&lt;br /&gt;
  if ($dh = opendir($dir)){&lt;br /&gt;
    while (($file = readdir($dh))){&lt;br /&gt;
      echo &amp;quot;filename:&amp;quot; . $file . &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    closedir($dh);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Functions=&lt;br /&gt;
&lt;br /&gt;
All variables are local to the function. You have to pass everything it needs, or declare variables as GLOBAL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
function func1($arg1, $arg2)&lt;br /&gt;
{&lt;br /&gt;
    GLOBAL $vardeclaredoutside&lt;br /&gt;
    &amp;lt;codeblock&amp;gt;&lt;br /&gt;
    return $value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only one value can be returned but you can return arrays.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
function func1()&lt;br /&gt;
{&lt;br /&gt;
    &amp;lt;codeblock&amp;gt;&lt;br /&gt;
    return array ($value1, $value2);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
list($val1,$val2) = func1();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Arrays=&lt;br /&gt;
&lt;br /&gt;
;arr = []&lt;br /&gt;
:(Create) empty array&lt;br /&gt;
&lt;br /&gt;
;arr1 = [val1, val2, val3]&lt;br /&gt;
;arr1 = array(val1, val2, val3)&lt;br /&gt;
:Create an indexed array. The keys are the range 0..arraylength.&lt;br /&gt;
&lt;br /&gt;
;array_push($arr1,val1,val2)&lt;br /&gt;
:Add elements val1 and val2 to the end of $arr1&lt;br /&gt;
&lt;br /&gt;
;$arr1 = array(key1=&amp;gt;val1, key2=&amp;gt;val2, key3=&amp;gt;val3)&lt;br /&gt;
;$arr2[key1] = val1&lt;br /&gt;
:Create an associative array (like a [[Perl#Hashes]] or a [[Python:DataTypes#Dictionary_or_dict|Python dictionay]])&lt;br /&gt;
&lt;br /&gt;
;count($arr1)&lt;br /&gt;
:Return the number of elements (length) of an array&lt;br /&gt;
&lt;br /&gt;
;end($arr1)&lt;br /&gt;
:Return the value of the last element in $arr1 and set the pointer to it.&lt;br /&gt;
&lt;br /&gt;
;join(&#039;,&#039;,$arr1)&lt;br /&gt;
:Join elements in arr1 with &#039;,&#039; as separator.&lt;br /&gt;
&lt;br /&gt;
;foreach($arr1 as $value) { codeblock }&lt;br /&gt;
:Loop over an indexed array&lt;br /&gt;
&lt;br /&gt;
;foreach($arr1 as $key =&amp;gt; $value) { codeblock }&lt;br /&gt;
:Loop over an associative array&lt;br /&gt;
&lt;br /&gt;
;unset($arr1[key])&lt;br /&gt;
:Remove the key element from $array. Numerical keys will not be reindexed.&lt;br /&gt;
&lt;br /&gt;
=Install=&lt;br /&gt;
On debian (and its derivates)&lt;br /&gt;
;apt-get install php-fpm php-mysql&lt;br /&gt;
:Install php7 and mysql support&lt;br /&gt;
:Fix php security by editing &amp;lt;code&amp;gt;/etc/php/7.0/fpm/php.ini&amp;lt;/code&amp;gt;&lt;br /&gt;
:Uncomment line with cgi.fix_pathinfo and set it to 0&lt;br /&gt;
&lt;br /&gt;
==php repository==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
apt -y install lsb-release apt-transport-https ca-certificates&lt;br /&gt;
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg&lt;br /&gt;
echo &amp;quot;deb https://packages.sury.org/php/ $(lsb_release -sc) main&amp;quot; | sudo tee /etc/apt/sources.list.d/php.list&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt -y install php7.4&lt;br /&gt;
php -v&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Upgrade==&lt;br /&gt;
Nice overview of how to upgrade can be found on [https://php.watch/articles/php-8-5-installation-upgrade-guide-debian-ubuntu php-watch]&lt;br /&gt;
&lt;br /&gt;
Installing multiple package can easily be done like &amp;lt;code&amp;gt;install php8.3-{fpm,curl,mbstring,mysql,xml}&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Unix_time&amp;diff=1729</id>
		<title>Unix time</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Unix_time&amp;diff=1729"/>
		<updated>2026-09-18T11:08:23Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category: Linux/Unix]]&lt;br /&gt;
The number of seconds since the [https://en.wikipedia.org/wiki/Unix_time Unix Epoch] (1-1-1970).&lt;br /&gt;
&lt;br /&gt;
The are online [https://www.epochconverter.com/ epoch converters]&lt;br /&gt;
&lt;br /&gt;
Originally unix time was stored as a 32-bits integer which limits the time to reaching 19 January 2038 03:14:07 UTC [https://en.wikipedia.org/wiki/Year_2038_problem]. Modern computers use a 64-bit field that expands the maximum time far beyond the expected lifetime of the universe.&lt;br /&gt;
&lt;br /&gt;
;date +%s&lt;br /&gt;
:Return the current unix time&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:20%&amp;quot;&lt;br /&gt;
|+ Good to know these seconds&lt;br /&gt;
! Timeframe&lt;br /&gt;
! Seconds&lt;br /&gt;
|-&lt;br /&gt;
| Hour&lt;br /&gt;
| 3600&lt;br /&gt;
|-&lt;br /&gt;
| Day &lt;br /&gt;
| 86400&lt;br /&gt;
|-&lt;br /&gt;
| Week&lt;br /&gt;
| 604800&lt;br /&gt;
|-&lt;br /&gt;
| Year&lt;br /&gt;
| 31536000&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Mail&amp;diff=1728</id>
		<title>Mail</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Mail&amp;diff=1728"/>
		<updated>2026-09-17T07:14:16Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Linux/Unix]]&lt;br /&gt;
[[Category:python]]&lt;br /&gt;
=Sending mail with sendmail=&lt;br /&gt;
;&amp;lt;code&amp;gt;sendmail -t &amp;lt; &amp;lt;messagefile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Send the email as in &amp;lt;messagefile&amp;gt;&lt;br /&gt;
:The email headers are in &amp;lt;messagefile&amp;gt;. That should look like:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
From: me@mydomain.tld&lt;br /&gt;
To: user@domain.tld&lt;br /&gt;
Subject: Subject of your mail&lt;br /&gt;
email text&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;mailx -s Subject -a &amp;lt;attachmentfile&amp;gt; email@domain.tld&amp;lt;/code&amp;gt;&lt;br /&gt;
:Send email with attachment after entering optional text and an EOT (CTRL-D). &lt;br /&gt;
&lt;br /&gt;
=Sending mail with python=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
def usage():&lt;br /&gt;
    print (&amp;quot;Usage: &amp;quot;+__file__)&lt;br /&gt;
    print(&amp;quot;Send email, include what you need in your program&amp;quot;)&lt;br /&gt;
    version = &#039;0.1, 19700101, Initial release&#039;&lt;br /&gt;
    print(&amp;quot;Version: &amp;quot;+version)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sendmail(mailto,mailfrom = &#039;NN&#039;,mailsubject = &#039;&#039;,mailtext = &#039;&#039;,attachments = &#039;&#039;):&lt;br /&gt;
    import smtplib&lt;br /&gt;
    from email import encoders&lt;br /&gt;
    from email.message import Message&lt;br /&gt;
    from email.mime.base import MIMEBase&lt;br /&gt;
    from email.mime.multipart import MIMEMultipart&lt;br /&gt;
    from email.mime.text import MIMEText&lt;br /&gt;
    from email.utils import formatdate&lt;br /&gt;
&lt;br /&gt;
    outer = MIMEMultipart()&lt;br /&gt;
    outer[&#039;Subject&#039;] = mailsubject&lt;br /&gt;
    outer[&#039;To&#039;] = &amp;quot;, &amp;quot;.join(mailto)&lt;br /&gt;
    outer[&#039;From&#039;] = mailfrom&lt;br /&gt;
    outer[&#039;Date&#039;] =  formatdate(localtime=True)&lt;br /&gt;
    msg = MIMEText(mailtext,&#039;plain&#039;)&lt;br /&gt;
    outer.attach(msg)&lt;br /&gt;
    if attachments != &#039;&#039;:&lt;br /&gt;
        for attachment in attachments:&lt;br /&gt;
            filename = attachment.split(&#039;/&#039;)[-1]&lt;br /&gt;
            ctype = &#039;application/octet-stream&#039;&lt;br /&gt;
            maintype, subtype = ctype.split(&#039;/&#039;, 1)&lt;br /&gt;
            fp = open(attachment, &#039;rb&#039;)&lt;br /&gt;
            msg = MIMEBase(maintype, subtype)&lt;br /&gt;
            msg.set_payload(fp.read())&lt;br /&gt;
            fp.close()&lt;br /&gt;
            # Encode the payload using Base64&lt;br /&gt;
            encoders.encode_base64(msg)&lt;br /&gt;
            # Set the filename parameter&lt;br /&gt;
            msg.add_header(&#039;Content-Disposition&#039;, &#039;attachment&#039;, filename=filename)&lt;br /&gt;
            outer.attach(msg)&lt;br /&gt;
    composed = outer.as_string()&lt;br /&gt;
    print(composed)&lt;br /&gt;
    s = smtplib.SMTP(&#039;localhost&#039;)&lt;br /&gt;
    print(&#039;Sending mail&#039;)&lt;br /&gt;
    s.sendmail(mailfrom, mailto , composed)&lt;br /&gt;
    s.quit()&lt;br /&gt;
    return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For Python 2 it was&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
#!/usr/bin/env python2&lt;br /&gt;
&lt;br /&gt;
def usage():&lt;br /&gt;
    print (&amp;quot;Usage: &amp;quot;+__file__)&lt;br /&gt;
    print(&amp;quot;Send email, include what you need in your program&amp;quot;)&lt;br /&gt;
    version = &#039;0.1, 19700101, Initial release&#039;&lt;br /&gt;
    print(&amp;quot;Version: &amp;quot;+version)&lt;br /&gt;
    sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
# USER CONFIGURABLE ITEMS&lt;br /&gt;
&lt;br /&gt;
maxmailsize = 10000000&lt;br /&gt;
&lt;br /&gt;
# END USER CONFIGURABLE ITEMS, DO NOT CHANGE ANYTHING BELOW THIS LINE&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    attachement1 = filepath&lt;br /&gt;
    attachement2 = filepath&lt;br /&gt;
&lt;br /&gt;
    mailto = [&#039;you@domain.tld&#039;]&lt;br /&gt;
    mailcc =  [&#039;someoneelse@anotherdomain.tld&#039;,&#039;andmore@domain.tld&#039;]&lt;br /&gt;
    mailbcc = [&#039;secret@domain.tld&#039;]     # Only include this in the final sendmail call, not in the headers.&lt;br /&gt;
    mailfrom = &#039;me@domain.tld&#039;          # Some systems do not like this, just remove it from the sendmail call&lt;br /&gt;
    mailsubject = &#039;What this is about&#039;&lt;br /&gt;
    mailtext = &amp;quot;Hi,\n\nI&#039;d like to send you an email.\n\nBest Regards\n\nMe.&amp;quot;&lt;br /&gt;
    sendmail(mailto, mailcc=mailcc, mailbcc=mailbcc, mailfrom=mailfrom, mailsubject=mailsubject, mailtext=mailtext, attachments=[attachment1,attachment2])&lt;br /&gt;
    return&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
def sendmail(mailto,mailcc = &#039;&#039;,mailbcc = &#039;&#039;,mailfrom = &#039;Sender&#039;,mailsubject = &#039;&#039;,mailtext = &#039;&#039;,attachments = &#039;&#039;):&lt;br /&gt;
    import smtplib&lt;br /&gt;
    from email import encoders&lt;br /&gt;
    from email.message import Message&lt;br /&gt;
    from email.mime.base import MIMEBase&lt;br /&gt;
    from email.mime.multipart import MIMEMultipart&lt;br /&gt;
    from email.mime.text import MIMEText&lt;br /&gt;
&lt;br /&gt;
    outer = MIMEMultipart()&lt;br /&gt;
    outer[&#039;Subject&#039;] = mailsubject&lt;br /&gt;
    outer[&#039;To&#039;] = &amp;quot;,&amp;quot;.join(mailto)&lt;br /&gt;
    outer[&#039;CC&#039;] = &amp;quot;,&amp;quot;.join(mailcc)&lt;br /&gt;
    outer[&#039;From&#039;] = mailfrom&lt;br /&gt;
    msg = MIMEText(mailtext,&#039;plain&#039;)&lt;br /&gt;
    outer.attach(msg)&lt;br /&gt;
    if attachments != &#039;&#039;:&lt;br /&gt;
        attachtotsize = 0&lt;br /&gt;
        for attachment in attachments:&lt;br /&gt;
            attachsize = os.stat(attachment).st_size&lt;br /&gt;
            if  attachtotsize + attachsize &amp;gt; maxmailsize:&lt;br /&gt;
                mailtext += attachment+&amp;quot; makes the message bigger than &amp;quot;+maxmailsize+&amp;quot;, it is not attached.\n&amp;quot;&lt;br /&gt;
            else:&lt;br /&gt;
                attachtotsize += attachsize&lt;br /&gt;
                filename = attachment.split(&#039;/&#039;)[-1]&lt;br /&gt;
                ctype = &#039;application/octet-stream&#039;&lt;br /&gt;
                maintype, subtype = ctype.split(&#039;/&#039;, 1)&lt;br /&gt;
                fp = open(attachment, &#039;rb&#039;)&lt;br /&gt;
                msg = MIMEBase(maintype, subtype)&lt;br /&gt;
                msg.set_payload(fp.read())&lt;br /&gt;
                fp.close()&lt;br /&gt;
                # Encode the payload using Base64&lt;br /&gt;
                encoders.encode_base64(msg)&lt;br /&gt;
                # Set the filename parameter&lt;br /&gt;
                msg.add_header(&#039;Content-Disposition&#039;, &#039;attachment&#039;, filename=filename)&lt;br /&gt;
                outer.attach(msg)&lt;br /&gt;
    composed = outer.as_string()&lt;br /&gt;
    s = smtplib.SMTP(&#039;localhost&#039;)&lt;br /&gt;
    s.sendmail(mailfrom, mailto+list(mailcc)+list(mailbcc) , composed)&lt;br /&gt;
    s.quit()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
main()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Reading mail with mailx=&lt;br /&gt;
The web knows more[https://www.computerhope.com/unix/umailx.htm].&lt;br /&gt;
;mailx&lt;br /&gt;
:Start mailx client and show 1 pages or messages. The Mailx prompt is a &#039;&amp;amp;&#039;&lt;br /&gt;
:The current message is marked with a&#039;&amp;gt;&#039; at the start of the line.&lt;br /&gt;
&lt;br /&gt;
;&amp;amp; quit&lt;br /&gt;
:Submit the changes you made and exit the client&lt;br /&gt;
&lt;br /&gt;
;&amp;amp; exit&lt;br /&gt;
:Exit the client without submitting the changes&lt;br /&gt;
&lt;br /&gt;
;&amp;amp; &amp;lt;RET&amp;gt;&lt;br /&gt;
:Read the current message&lt;br /&gt;
&lt;br /&gt;
;&amp;amp; d&lt;br /&gt;
:Delete the current message&lt;br /&gt;
;&amp;amp;d&amp;lt;id1&amp;gt; &amp;lt;id3&amp;gt;&lt;br /&gt;
:Delete the messages with id &amp;lt;id1&amp;gt; and &amp;lt;id2&amp;gt;&lt;br /&gt;
;&amp;amp;d&amp;lt;id1&amp;gt;-&amp;lt;id3&amp;gt;&lt;br /&gt;
:Delete the messages with id &amp;lt;id1&amp;gt; up to and including &amp;lt;id2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;amp; h&lt;br /&gt;
:Show a page of headers&lt;br /&gt;
;&amp;amp; z&lt;br /&gt;
:Show next page of headers&lt;br /&gt;
;&amp;amp; z$&lt;br /&gt;
:Show last page of headers&lt;br /&gt;
&lt;br /&gt;
;&amp;amp; +&lt;br /&gt;
:Go to next message&lt;br /&gt;
;&amp;amp; - &lt;br /&gt;
:Go to previous message&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=PHP&amp;diff=1727</id>
		<title>PHP</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=PHP&amp;diff=1727"/>
		<updated>2026-09-16T20:07:57Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:PHP]]&lt;br /&gt;
[[category:Webdesign]]&lt;br /&gt;
=Basics=&lt;br /&gt;
Script language for dynamic web-pages. The syntax and concepts used are similar to [[Perl]]&lt;br /&gt;
&lt;br /&gt;
;Limited number of loops&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt; &lt;br /&gt;
for ($i = 0; $i &amp;lt;= 6; $i++) {&lt;br /&gt;
  echo &amp;quot;Loop number: $i &amp;quot;;&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;escapeshellcmd(shellcommand)&lt;br /&gt;
:Return the shellcommand with everything that might confuse the shell escaped.&lt;br /&gt;
;exec(&amp;lt;cmd&amp;gt;,&amp;lt;outputarray&amp;gt;,&amp;lt;returnvar&amp;gt;)&lt;br /&gt;
:Executed &amp;lt;cmd&amp;gt; in the shell, append the command output to he array &amp;lt;outputarray&amp;gt; and set &amp;lt;returnvar&amp;gt; to the returnvalue of the command.&lt;br /&gt;
:Also the last line of the command output is returned&lt;br /&gt;
;shell_exec(&amp;lt;cmd&amp;gt;)&lt;br /&gt;
:Execute &amp;lt;cmd&amp;gt; (output from excapedshellcmd) in the shell, return the command output.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;date(&amp;quot;Y-m-d h:i:s&amp;quot;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Current timestamp (YYYY-mm-dd HH:MM:SS).&lt;br /&gt;
:Format &amp;quot;U&amp;quot; is [https://duckduckgo.com/?q=unixtime unixtime] (seconds since epoch)&lt;br /&gt;
;sprintf(&amp;quot;%7.2f&amp;quot;, $float )&lt;br /&gt;
:Format a number (7 digits, 2 decimals)&lt;br /&gt;
;number_format($number, 2, &#039;.&#039;, &#039;,&#039;)&lt;br /&gt;
:Format $number with 2 decimals, . as decimal separator and , as thousand separator.&lt;br /&gt;
&lt;br /&gt;
;strpos($string, $search,$start)&lt;br /&gt;
:Return position of $search exists in $string. When it is not in, return FALSE. Start searching at position $start (optional). Simple test on strpos - &amp;lt;code&amp;gt;if (strpos(x,y)) {}&amp;lt;/code&amp;gt; - does not differ between position 0 and FALSE. Test on position 2 or count from the end by setting $start to a negative value (possible since PHP7.1).&lt;br /&gt;
;str_replace($old, $new, $string)&lt;br /&gt;
:Return $string with $old replaced by $new&lt;br /&gt;
;trim($string, &#039;abc&#039;)&lt;br /&gt;
:Remove characters a, b and c from the start and the end of $string. If no characters are specified all whitespace will be removed.&lt;br /&gt;
&lt;br /&gt;
;round($float,&amp;lt;precision&amp;gt;)&lt;br /&gt;
:Round $float to &amp;lt;precision&amp;gt; decimals (0 is default)&lt;br /&gt;
&lt;br /&gt;
=Regular expressions=&lt;br /&gt;
PHP is Perl-like, patterns need delimiters (default is /&amp;lt;pattern&amp;gt;/ )&lt;br /&gt;
;preg_match($pattern, $string)&lt;br /&gt;
:Return 1 if $pattern exists in $string&lt;br /&gt;
;preg_split(&#039;/\s*\=+\s*/&#039;,$string &lt;br /&gt;
:Split $string into an array on a pattern (in this example on white-spaces and equality signs.&lt;br /&gt;
;preg_replace(&#039;/#.*$/&#039;,&#039;&#039;,$string);&lt;br /&gt;
:Replace matches with the pattern in $string (in this example to remove comments from a line)&lt;br /&gt;
&lt;br /&gt;
=Files=&lt;br /&gt;
Almost all you need to know about files. For writing open with &#039;w&#039; and fwrite($fh,$line)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
$fh = fopen($filename, &#039;r&#039;) or die(&#039;Unable to open &#039;.$file);&lt;br /&gt;
while(!feof($fh)) {&lt;br /&gt;
  $line =  fgets($fh);&lt;br /&gt;
}&lt;br /&gt;
fclose($fh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
$dir = &amp;quot;./&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// Open a directory, and read its contents&lt;br /&gt;
if (is_dir($dir)){&lt;br /&gt;
  if ($dh = opendir($dir)){&lt;br /&gt;
    while (($file = readdir($dh))){&lt;br /&gt;
      echo &amp;quot;filename:&amp;quot; . $file . &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    closedir($dh);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Functions=&lt;br /&gt;
&lt;br /&gt;
All variables are local to the function. You have to pass everything it needs, or declare variables as GLOBAL&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
function func1($arg1, $arg2)&lt;br /&gt;
{&lt;br /&gt;
    GLOBAL $vardeclaredoutside&lt;br /&gt;
    &amp;lt;codeblock&amp;gt;&lt;br /&gt;
    return $value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only one value can be returned but you can return arrays.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
function func1()&lt;br /&gt;
{&lt;br /&gt;
    &amp;lt;codeblock&amp;gt;&lt;br /&gt;
    return array ($value1, $value2);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
list($val1,$val2) = func1();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Arrays=&lt;br /&gt;
&lt;br /&gt;
;arr = []&lt;br /&gt;
:(Create) empty array&lt;br /&gt;
&lt;br /&gt;
;arr1 = [val1, val2, val3]&lt;br /&gt;
;arr1 = array(val1, val2, val3)&lt;br /&gt;
:Create an indexed array. The keys are the range 0..arraylength.&lt;br /&gt;
&lt;br /&gt;
;array_push($arr1,val1,val2)&lt;br /&gt;
:Add elements val1 and val2 to the end of $arr1&lt;br /&gt;
&lt;br /&gt;
;$arr1 = array(key1=&amp;gt;val1, key2=&amp;gt;val2, key3=&amp;gt;val3)&lt;br /&gt;
;$arr2[key1] = val1&lt;br /&gt;
:Create an associative array (like a [[Perl#Hashes]] or a [[Python:DataTypes#Dictionary_or_dict|Python dictionay]])&lt;br /&gt;
&lt;br /&gt;
;count($arr1)&lt;br /&gt;
:Return the number of elements (length) of an array&lt;br /&gt;
&lt;br /&gt;
;end($arr1)&lt;br /&gt;
:Return the value of the last element in $arr1 and set the pointer to it.&lt;br /&gt;
&lt;br /&gt;
;join(&#039;,&#039;,$arr1)&lt;br /&gt;
:Join elements in arr1 with &#039;,&#039; as separator.&lt;br /&gt;
&lt;br /&gt;
;foreach($arr1 as $value) { codeblock }&lt;br /&gt;
:Loop over an indexed array&lt;br /&gt;
&lt;br /&gt;
;foreach($arr1 as $key =&amp;gt; $value) { codeblock }&lt;br /&gt;
:Loop over an associative array&lt;br /&gt;
&lt;br /&gt;
;unset($arr1[key])&lt;br /&gt;
:Remove the key element from $array. Numerical keys will not be reindexed.&lt;br /&gt;
&lt;br /&gt;
=Install=&lt;br /&gt;
On debian (and its derivates)&lt;br /&gt;
;apt-get install php-fpm php-mysql&lt;br /&gt;
:Install php7 and mysql support&lt;br /&gt;
:Fix php security by editing &amp;lt;code&amp;gt;/etc/php/7.0/fpm/php.ini&amp;lt;/code&amp;gt;&lt;br /&gt;
:Uncomment line with cgi.fix_pathinfo and set it to 0&lt;br /&gt;
&lt;br /&gt;
==php repository==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
apt -y install lsb-release apt-transport-https ca-certificates&lt;br /&gt;
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg&lt;br /&gt;
echo &amp;quot;deb https://packages.sury.org/php/ $(lsb_release -sc) main&amp;quot; | sudo tee /etc/apt/sources.list.d/php.list&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt -y install php7.4&lt;br /&gt;
php -v&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Upgrade==&lt;br /&gt;
Nice overview of how to upgrade can be found on [https://php.watch/articles/php-8-5-installation-upgrade-guide-debian-ubuntu php-watch]&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Git&amp;diff=1726</id>
		<title>Git</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Git&amp;diff=1726"/>
		<updated>2026-09-01T06:58:02Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Workflow making changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Using Git=&lt;br /&gt;
&lt;br /&gt;
This [https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow Atlassian workflow] looks like a good way to work with git.&lt;br /&gt;
&lt;br /&gt;
Here is a basic overview of how you can work with git@bitbucket:&lt;br /&gt;
&lt;br /&gt;
Initialize git on your computer:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
git config --global user.name &amp;quot;&amp;lt;your name&amp;gt;&amp;quot;&lt;br /&gt;
git config --global user.email &amp;quot;&amp;lt;your emailaddress&amp;gt;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Add your public key in your profile - &#039;Personal Settings&#039; - &#039;SSH keys&#039;&lt;br /&gt;
&lt;br /&gt;
==Fresh project (nothing locally yet)==&lt;br /&gt;
* Create a &amp;quot;repository&amp;quot; (project) with a git hosting tool (like Bitbucket)&lt;br /&gt;
* &amp;lt;code&amp;gt;git clone &amp;lt;Look under the Clone Button&amp;lt;/code&amp;gt; Copy (or clone) the repository to your local machine &lt;br /&gt;
* &amp;lt;code&amp;gt;git remote set-url --push origin &amp;lt;Look under the Clone Button&amp;gt;&amp;lt;/code&amp;gt; Set the push URL &lt;br /&gt;
* &amp;lt;code&amp;gt;git add &amp;lt;filenname&amp;gt;&amp;lt;/code&amp;gt; Add a file to your local repository&lt;br /&gt;
* &amp;lt;code&amp;gt;git commit -m &#039;Reason for commit&#039;&amp;lt;/code&amp;gt;  ] &lt;br /&gt;
* &amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt; Send your changes to your master branch &lt;br /&gt;
&lt;br /&gt;
==For a project you have files for already==&lt;br /&gt;
&lt;br /&gt;
* Create a &amp;quot;repository&amp;quot; (project) with a git hosting tool (like Bitbucket)&lt;br /&gt;
* &amp;lt;code&amp;gt;git init&amp;lt;/code&amp;gt; (initialize the local repository)&lt;br /&gt;
* &amp;lt;code&amp;gt;git pull &amp;lt;Repository URL(for bitbucket look under the Clone Button)&amp;gt;&amp;lt;/code&amp;gt; master&lt;br /&gt;
* &amp;lt;code&amp;gt;git add .&amp;lt;/code&amp;gt; (Add all file to the local repository)&lt;br /&gt;
* &amp;lt;code&amp;gt;git commit -m &#039;Initial upload&#039;&amp;lt;/code&amp;gt;  &lt;br /&gt;
* &amp;lt;code&amp;gt;git remote add origin &amp;lt;Look under the Clone Button&amp;gt;&amp;lt;/code&amp;gt;  (Connect local to remote repository)&lt;br /&gt;
* &amp;lt;code&amp;gt;git push -u origin --all&amp;lt;/code&amp;gt; (push all committed file to remote.&lt;br /&gt;
&lt;br /&gt;
==Other things you can do==&lt;br /&gt;
* Create a &amp;quot;branch&amp;quot; (version), make a change, commit the change&lt;br /&gt;
* Open a &amp;quot;pull request&amp;quot; (propose changes to the master branch)&lt;br /&gt;
* &amp;quot;Merge&amp;quot; your branch to the master branch&lt;br /&gt;
&lt;br /&gt;
=Workflow making changes=&lt;br /&gt;
;git pull&lt;br /&gt;
:Update from remote&lt;br /&gt;
;git checkout -b &amp;lt;branchname&amp;gt;&lt;br /&gt;
:Create a new branch &lt;br /&gt;
;git status&lt;br /&gt;
:Check if something changed&lt;br /&gt;
;git add --all&lt;br /&gt;
:Add all changed files to the repository&lt;br /&gt;
;git restore &amp;lt;file&amp;gt;&lt;br /&gt;
:Restore a file to it&#039;s last committed stage&lt;br /&gt;
;git commit -m &amp;quot;Message&amp;quot;&lt;br /&gt;
:Commit your changes&lt;br /&gt;
;git push&lt;br /&gt;
:Upload your repository&lt;br /&gt;
When you are ready with your change&lt;br /&gt;
;git checkout master&lt;br /&gt;
:Go to the master branch&lt;br /&gt;
;git pull&lt;br /&gt;
:Update from remote, fix conflicts&lt;br /&gt;
;git merge &amp;lt;branchname&amp;gt;&lt;br /&gt;
:Update master with your changes, fix conflicts&lt;br /&gt;
;git push&lt;br /&gt;
:Update the remote repository&lt;br /&gt;
&lt;br /&gt;
=Other commands=&lt;br /&gt;
Check the [https://www.atlassian.com/git/tutorials/atlassian-git-cheatsheet cheatsheet] for more.&lt;br /&gt;
;&amp;lt;code&amp;gt;git branch -d &amp;lt;brachname&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Delete a branch locally only&lt;br /&gt;
;&amp;lt;code&amp;gt;git config --local -l&amp;lt;/code&amp;gt;&lt;br /&gt;
:List your configuration for this repository (in the current directory).&lt;br /&gt;
;&amp;lt;code&amp;gt;git remote -v&amp;lt;/code&amp;gt;&lt;br /&gt;
:Show &#039;remote&#039; configuration.&lt;br /&gt;
;&amp;lt;code&amp;gt;git status -v&amp;lt;/code&amp;gt;&lt;br /&gt;
:Show all difference between the current directory and the local repository.&lt;br /&gt;
;&amp;lt;code&amp;gt;git add/rm &amp;lt;path&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Add or remove files from the list of files to be committed (local files will be removed too).&lt;br /&gt;
;&amp;lt;code&amp;gt;git commit -m &#039;Reason for commit&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Commit changes (add/rm) to the local repository.&lt;br /&gt;
;&amp;lt;code&amp;gt;git commit -a&amp;lt;/code&amp;gt;&lt;br /&gt;
:Commit all local changes to the local repository.&lt;br /&gt;
;&amp;lt;code&amp;gt;git branch &amp;lt;branchname&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Create a new branche&lt;br /&gt;
;&amp;lt;code&amp;gt;git checkout &amp;lt;branchname&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Make &amp;lt;branchename&amp;gt;  current&lt;br /&gt;
;&amp;lt;code&amp;gt;git checkout -b &amp;lt;branchname&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Make &amp;lt;branchename&amp;gt; and make it current (combine above 2 commands)&lt;br /&gt;
;&amp;lt;code&amp;gt;git reset HEAD &amp;lt;path&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Reset commit status for &amp;lt;path&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;git fetch&amp;lt;/code&amp;gt;&lt;br /&gt;
:Fetch all changes made remote&lt;br /&gt;
;&amp;lt;code&amp;gt;git merge &amp;lt;branch&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Merge &amp;lt;branch&amp;gt; into the current branch&lt;br /&gt;
;&amp;lt;code&amp;gt;git branch --all&amp;lt;/code&amp;gt;&lt;br /&gt;
:Show all branches in this repository&lt;br /&gt;
;&amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt;&lt;br /&gt;
:Send the repository remote&lt;br /&gt;
;&amp;lt;code&amp;gt;git pull&amp;lt;/code&amp;gt;&lt;br /&gt;
:Fetch all changes made remote and merge to current branch&lt;br /&gt;
;&amp;lt;code&amp;gt;git log&amp;lt;/code&amp;gt;&lt;br /&gt;
:Show all commits&lt;br /&gt;
&lt;br /&gt;
=Conflict resolution=&lt;br /&gt;
Git merge tries to merge files from 2 branches when they differ. If that is not possible (e.g. as both files have changes in the same lines) the file will mark the conflicting parts.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD&lt;br /&gt;
 Lines in the current branch&lt;br /&gt;
 =======&lt;br /&gt;
 Lines in the merged branch&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;lt;name of the merged branch&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ======= is the center of the conflict. Check which lines you want to be in and remove everything else (including the conflict markerd).&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Pandas&amp;diff=1725</id>
		<title>Pandas</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Pandas&amp;diff=1725"/>
		<updated>2026-08-04T14:22:28Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Select data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
Check the [https://pandas.pydata.org/pandas-docs/stable/10min.html 10 minutes to Pandas] too or [https://pythonexamples.org/pandas-examples/ pythonexamples].&lt;br /&gt;
;import pandas as pd&lt;br /&gt;
:Import the library, we assume this was done on this page&lt;br /&gt;
&lt;br /&gt;
=DataFrame=&lt;br /&gt;
Object for tabular data (that is e.g. obtained by read_html).&lt;br /&gt;
&lt;br /&gt;
Each column is a [[Pandas#Series]]&lt;br /&gt;
&lt;br /&gt;
;df = &amp;lt;nowiki&amp;gt;pd.DataFrame([{col1: 1,col2: 2},{col1: 1,col2: 2}])&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Create a simple dataframe having a range index, 2 rows and 2 columns&lt;br /&gt;
;df = &amp;lt;nowiki&amp;gt;pd.DataFrame([{col1: 1,col2: 2},{col1: 1,col2: 2}],[row1,row2])&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Create a dataframe having a list index. The size of index must match the number of rows.&lt;br /&gt;
&lt;br /&gt;
Single columns can be addressed by there name like in &amp;lt;code&amp;gt;df.columnname.unique()&amp;lt;/code&amp;gt; to get unique values in a column.&lt;br /&gt;
&lt;br /&gt;
Single or multiple columns can be addressed as list like in &amp;lt;code&amp;gt;df.set_index([column1,column2])&amp;lt;/code&amp;gt; to set an index over 2 columns.&lt;br /&gt;
&lt;br /&gt;
;df.copy&lt;br /&gt;
:Make a copy of df ( = will point to the same dataframe, like with [[Python:DataTypes#Dictionary or dict|dictionaries]])&lt;br /&gt;
&lt;br /&gt;
;df.join(table2)&lt;br /&gt;
:Like SQL-join merge on index&lt;br /&gt;
;df.merge(table2,on=&amp;lt;column&amp;gt;)&lt;br /&gt;
:Like SQL-join on  &amp;lt;column&amp;gt; = df.index&lt;br /&gt;
;dfall.merge(table2, on = &amp;lt;column&amp;gt;, how=&#039;left&#039;, indicator=True)&lt;br /&gt;
:Return df joined with table2. Add column _merge with value &#039;left_only&#039; to records that only exist in df.&lt;br /&gt;
;df = dfall[dfall[&#039;_merge&#039;] == &#039;left_only&#039;]&lt;br /&gt;
:Return dataframe with all records not in table2&lt;br /&gt;
;df = pd.concat(dflist)&lt;br /&gt;
:Concatenate all dataframes in dflist&lt;br /&gt;
&lt;br /&gt;
==Information==&lt;br /&gt;
&lt;br /&gt;
;df.info()&lt;br /&gt;
:Information on dataframe (Index, size, datatypes per column)&lt;br /&gt;
;df.size&lt;br /&gt;
:Return the number of cells in a dataframe&lt;br /&gt;
;df.shape&lt;br /&gt;
:Return the number of rows and columns in a dataframe as [[Python:DataTypes#Tuple|tuple]].&lt;br /&gt;
;df.describe()&lt;br /&gt;
:Return various attributes for numeric columns in the dataframe. This may indicate if there are outlyers.&lt;br /&gt;
;df.head(x)&lt;br /&gt;
;df.tail(x)&lt;br /&gt;
:Return first/last x data rows of df (5 is the default value for x).&lt;br /&gt;
&lt;br /&gt;
;df.index&lt;br /&gt;
:Return the table index (class = pandas.core.indexes.base.Index)&lt;br /&gt;
&lt;br /&gt;
;df.columns&lt;br /&gt;
:Return the column headers (class = pandas.core.indexes.base.Index)&lt;br /&gt;
;df.dtypes&lt;br /&gt;
:Return the data-type of the columns&lt;br /&gt;
;df.columnname.dtype&lt;br /&gt;
:Return the data-type of column columnname&lt;br /&gt;
&lt;br /&gt;
==Modify== &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.rename(columns={oldname:newname}, inplace=True)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Redefine the column headers (modifies the dataframe itself, nothing is returned)&lt;br /&gt;
&lt;br /&gt;
;df.set_index([&#039;col1&#039;,&#039;col2&#039;])&lt;br /&gt;
:Return the dataframe with a new index composed of 2 columns&lt;br /&gt;
;df.reset_index()&lt;br /&gt;
:Return the dataframe with a default index (range)&lt;br /&gt;
;df.sort_index(ascending=False)&lt;br /&gt;
:Sort the dataframe on the index. &#039;True&#039; is the default if &#039;acsending&#039; is not supplied.&lt;br /&gt;
;df.index = df.index.map(str)&lt;br /&gt;
:For a data-type on the index&lt;br /&gt;
&lt;br /&gt;
;df.drop(index)&lt;br /&gt;
;df.drop([indexes])&lt;br /&gt;
;df.drop(range(0,3))&lt;br /&gt;
:Remove row(s) from a dataframe.&lt;br /&gt;
;df.drop(columns=[listofcolumnstodrop]&lt;br /&gt;
:Remove columns from a dataframe.&lt;br /&gt;
&lt;br /&gt;
;df.dropna(thresh=x)&lt;br /&gt;
:Return only rows that have at least x columns with a none-NA  value. If x &amp;lt; 2 the threshold can be dropped.&lt;br /&gt;
&lt;br /&gt;
;df.loc[&amp;lt;index&amp;gt;,[&#039;field1&#039;,&#039;field2&#039;]] = [value1,value2]&lt;br /&gt;
:Change values for index &amp;lt;index&amp;gt; in a dataframe&lt;br /&gt;
;df.fillna(&amp;lt;value&amp;gt;)&lt;br /&gt;
;df[[&amp;lt;column1&amp;gt;,&amp;lt;column2&amp;gt;]] = df[[&amp;lt;column1&amp;gt;,&amp;lt;column2&amp;gt;].fillna(&amp;lt;value&amp;gt;)&lt;br /&gt;
:Return dataframe with all NA-values (in the selected columns) replaced by &amp;lt;value&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;table.agg(newname=(&#039;columname&#039;, np.max))&lt;br /&gt;
:Add newname to df with the max of columnname. This named aggregations is only supported from version v0.25 &lt;br /&gt;
&lt;br /&gt;
;df.transform(&amp;lt;function&amp;gt;)&lt;br /&gt;
:Apply a function to an existing column or the entire dataframe.&lt;br /&gt;
&lt;br /&gt;
;df.assign(newcolumn = &amp;lt;expression&amp;gt;)&lt;br /&gt;
:Add column newcolumn to the dataframe&lt;br /&gt;
:Expression can be a function like &amp;quot;lambda d: d[&#039;column&#039;] * &amp;lt;something&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;df.apply(&amp;lt;function&amp;gt;)&lt;br /&gt;
:Apply a function to the dataframe. By default every element of the table.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.apply(lambda x: &amp;lt;function&amp;gt;(x) if x.name in [columnname] else x)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Apply a function to specified colums &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[columname] = df[columname].apply(lambda x: &amp;lt;function&amp;gt;(x))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Change a column in the dataframe by applying &amp;lt;function&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;df.replace(&amp;lt;pattern&amp;gt;,&amp;lt;newvalue&amp;gt;,regex=True)&lt;br /&gt;
:Replace &amp;lt;pattern&amp;gt; with &amp;lt;newvalue&amp;gt; in the entire dataframe&lt;br /&gt;
&lt;br /&gt;
;df[columna].mask(df[columna] == origvalue , newvalue, inplace=True)&lt;br /&gt;
:Change all cells in columa that have origvalue into newvalue (inplace, so in the dataframe itself).&lt;br /&gt;
&lt;br /&gt;
==Select data==&lt;br /&gt;
Use .loc, else colomn-names will be considered too (if I understand this[https://stackoverflow.com/questions/38886080/python-pandas-series-why-use-loc] correctly).&lt;br /&gt;
&lt;br /&gt;
;WARNING!!&lt;br /&gt;
:at least with .loc if only 1 item is found is it returned as string(/float?) else as dataframe/series.&lt;br /&gt;
&lt;br /&gt;
;df.[[iloc]][&amp;lt;slice&amp;gt;]&lt;br /&gt;
:Return the rows indicated by &amp;lt;slice&amp;gt; as pandas.Series &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.iloc[:,0:3]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[[col0,col1,col2]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Return 3 columns from the dataframe&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;columns&#039;)&lt;br /&gt;
:Return all columns which name matches &amp;lt;regexp&amp;gt;. (axis=1)&lt;br /&gt;
&lt;br /&gt;
;df.loc[&amp;lt;index&amp;gt;]&lt;br /&gt;
:Select the row(s) with index &amp;lt;index&amp;gt;&lt;br /&gt;
;df.loc[&amp;lt;indexname&amp;gt;].&amp;lt;columnname&amp;gt;&lt;br /&gt;
;df.loc[&amp;lt;indexname&amp;gt;].[&amp;lt;columnname&amp;gt;]&lt;br /&gt;
:Select only 1 column from a row as pandas series. You may convert that to a list or set immediately by using &amp;lt;code&amp;gt;list(df.loc[&amp;lt;indexname&amp;gt;].&amp;lt;columnname&amp;gt;)&amp;lt;/code&amp;gt;&lt;br /&gt;
;df.loc[0][0]&lt;br /&gt;
:Select a cell in a dataframe with no index or header&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[lambda d: d[column1] == &amp;lt;value&amp;gt; ]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[df[column1] == &amp;lt;value&amp;gt; ]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[df[column1].notnull()]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Select all rows where column1 equals &amp;lt;value&amp;gt; or do not have a null-value.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[(df[column1] == &amp;lt;value&amp;gt;) | (df[colomn1] == &amp;lt;value2&amp;gt;)]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Combine conditions with &#039;|&#039; (or) or &#039;&amp;amp;&#039; (and). Use () on each condition!!&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[datetime.today()-pd.Timedelta(days=7) : datetime.today()]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Select all rows where the (datetime)-index is between 7 days ago and today.&lt;br /&gt;
:NOTE!! The index must be sorted in ascending order[https://stackoverflow.com/q/67298584/2213323]. &lt;br /&gt;
;df.last(&#039;7D&#039;)&lt;br /&gt;
:Select the last 7 days in the dataframe. For this als the datetime index must be sorted in ascending order&lt;br /&gt;
&lt;br /&gt;
See also the [https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.contains.html#pandas.Series.str.contains pandas series pages]  &lt;br /&gt;
;df[df[&#039;fieldname&#039;].str.contains(&#039;regexp&#039;,regex=True)]&lt;br /&gt;
:Select all rows in df where fieldname contens matches regexp. The field must have a string datetype. If you are looking for a simple string you can leave out the regex=True part.&lt;br /&gt;
;df[df[&#039;fieldname&#039;].gt(value)]&lt;br /&gt;
:Select all rows in df where fieldname is bigger than value. The field must have a numeric datetype&lt;br /&gt;
&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;)&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;).&amp;lt;columnname&amp;gt;&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;).index&lt;br /&gt;
:Return all rows for which in index matches &amp;lt;regexp&amp;gt; or get only the column of the matched indexes. (axis=0 ) or the indexname(s).&lt;br /&gt;
:The .index returns the matching indexes as a [[Python:DataTypes#List|list]].&lt;br /&gt;
&lt;br /&gt;
;df.sort_values(&amp;lt;columnname&amp;gt;)&lt;br /&gt;
;df.sort_values([&amp;lt;column1&amp;gt;,&amp;lt;colunm2&amp;gt;],ascending=(True,False))&lt;br /&gt;
:Return the dataframe sorted on the values in the columns. The second form sorts on column1 first and then on column2, column1 ascending, column2 descending&lt;br /&gt;
;df.groupby([column1,column2])&lt;br /&gt;
:Return a DataFrameGroupBy object, this is not a dataframe&lt;br /&gt;
;df.collname.unique()&lt;br /&gt;
:Return a [[Numpy]] array with all distinct values in column &#039;collname&#039;&lt;br /&gt;
&lt;br /&gt;
;Get all rows from df1 that have an index that exists in df2&lt;br /&gt;
:df = df1[df1.index.isin(df2.index)]&lt;br /&gt;
;Negate like&lt;br /&gt;
:df = df1[~df1.index.isin(df2.index)]&lt;br /&gt;
&lt;br /&gt;
;Or get all intersectioned indices and select by loc&lt;br /&gt;
:df = df1.loc[df.index.intersection(df2.index)]&lt;br /&gt;
&lt;br /&gt;
;Better for readibility is to create the indexes first and than filter&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
commen_idx = df1.index.intersection(df2.index)&lt;br /&gt;
df1_only_idx = df1.index.difference(df2.index)&lt;br /&gt;
newdf = df1.loc(df1_only_idx)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Use data==&lt;br /&gt;
;Print 2 attributes for each row and check for no value&lt;br /&gt;
:pd.isna(value) works for Null, NaN (Nod a number) and NaT (not a time) too.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for index, row in df.iterrows():&lt;br /&gt;
    print(row[&#039;ColumnA&#039;],row[&#039;ColumnB&#039;])&lt;br /&gt;
    if ps.isna(row[&#039;ColumnA&#039;]):&lt;br /&gt;
        print(&#039;Found a NaN value&#039;) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
;In multi-column indexes the index is returned as a tuple&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;for (indexA, indexB), row in df.iterrows():&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Print all values for the first row&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for column, row in df.iteritems():&lt;br /&gt;
    print(column,row[0])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Loop over columns&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for column in df:&lt;br /&gt;
    print(f&amp;quot;Columnname {column}&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;df.iloc[0]&lt;br /&gt;
:return the values of the first row as pandas series. If there is only 1 column returns the value.&lt;br /&gt;
&lt;br /&gt;
;df.iloc[0][0]&lt;br /&gt;
:return the value of the first column in the first row. Columns can also be identified by name&lt;br /&gt;
&lt;br /&gt;
;df[&amp;lt;column&amp;gt;].quantile(q=0.1)&lt;br /&gt;
:Return the 10th percentile (10% of the values in &amp;lt;column&amp;gt; is lower than the 10th percentile)&lt;br /&gt;
&lt;br /&gt;
;df[&amp;lt;column].str.extract(r&amp;quot;A regex(p\w+)&amp;quot;)&lt;br /&gt;
:Return a series (column) of the values selected by [[Regular Expressions]] (p\w+)&lt;br /&gt;
;df[&amp;lt;columna&amp;gt;].map(str) + &#039;_&#039; + df[&amp;lt;columnb&amp;gt;].map(str)&lt;br /&gt;
:Return a series (column) with the columns concatenated. If not mapped to str an error will be thrown.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[&amp;lt;column&amp;gt;].map(str).apply(lambda x: x[-1])&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
:Return a series (column) with the last character of the &amp;lt;column&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Series=&lt;br /&gt;
Pandas Series [https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.html online documentation].&amp;lt;br&amp;gt;&lt;br /&gt;
A pandas series is a 1 dimensional array with named keys.&amp;lt;br&amp;gt;&lt;br /&gt;
Pandas Series have all kind of methods similar to [[Numpy]] like main, std, min, max,.... In fact Pandas is using numpy to do this.&lt;br /&gt;
;s = pd.Series([])&lt;br /&gt;
;s = pd.Series([valuelist],[indexlist])&lt;br /&gt;
:Initialize a series. If indexlist is omitted the keys are integers starting at 0.&lt;br /&gt;
;s[&amp;lt;key&amp;gt;] = &amp;lt;value&amp;gt;&lt;br /&gt;
:Assign &amp;lt;value&amp;gt; to the series element with key &amp;lt;key&amp;gt;&lt;br /&gt;
:The order in the series is the order in which they are created, NOT the numeric order.&lt;br /&gt;
:Elements can be addressed as &amp;lt;code&amp;gt;s[&amp;lt;key&amp;gt;]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;s.&amp;lt;key&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;s[&amp;lt;numkey&amp;gt;]&amp;lt;/code&amp;gt;. Where &amp;lt;numkey&amp;gt; is defined by the order the element was created. &lt;br /&gt;
:Once you have used named keys in a series you cannot create new elements with a numeric key.&lt;br /&gt;
;s.index&lt;br /&gt;
:All indexes in the series. Can be sliced to find a particular index.&lt;br /&gt;
;s.describe()&lt;br /&gt;
:Series statistics&lt;br /&gt;
&lt;br /&gt;
All in 1 example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
import pandas as pd&lt;br /&gt;
s = pd.Series([])&lt;br /&gt;
for i in range(50):&lt;br /&gt;
    s[i] = int(np.random.random() * 100)&lt;br /&gt;
&lt;br /&gt;
for i in s.index:&lt;br /&gt;
    print(i,s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funny, you can do &amp;lt;code&amp;gt;s[0]&amp;lt;/code&amp;gt; but not&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for i in s:&lt;br /&gt;
    print(s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To get all values from the series you do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for v in s:&lt;br /&gt;
    print(v)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To get the indexes too:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for i in s.index:&lt;br /&gt;
    print(i,s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TimeSeries==&lt;br /&gt;
Indexes that contains datetime values are automatically casted to a DatetimeIndex.&lt;br /&gt;
&lt;br /&gt;
;df.resample(&#039;5D&#039;).mean&lt;br /&gt;
:Return the dataframe with the average value of each 5 days.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.resample(&#039;1H&#039;).agg({&#039;ColumnA&#039;:&#039;first&#039;,&#039;ColumnB&#039;:&#039;max&#039;, &#039;ColumnC&#039;:&#039;min&#039;, &#039;ColumnD&#039;:&#039;last&#039; })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Resample with aggregation specified per column.&lt;br /&gt;
&lt;br /&gt;
;df.resample(&#039;5D&#039;,origin=&#039;end&#039;)&lt;br /&gt;
:Resample so the last timestamp is used, by default it starts with the first, the last set may be incomplete.&lt;br /&gt;
&lt;br /&gt;
==Datetime functions==&lt;br /&gt;
;df[datefield] = pd.to_datetime(df[datefield],format=&#039;%d-%m-%Y&#039;)&lt;br /&gt;
:Convert a string-column with a date into datetime. Format is the input format.&lt;br /&gt;
:WARNING: without format to_datetime tries to make up what the format is. This is pretty intelligent but can easily be wrong with day-numbers under 13&lt;br /&gt;
;df[datefield] = pd.to_datetime(df[datefield],unit=&#039;s&#039;)&lt;br /&gt;
:Convert a column with [[unix time]] into datetime.&lt;br /&gt;
;df[&amp;lt;timefield&amp;gt;] = testdf[&amp;lt;datetime-field&amp;gt;].dt.time&lt;br /&gt;
:Return a series (column) with the time-value of a datetime-column&lt;br /&gt;
&lt;br /&gt;
=Reading Data=&lt;br /&gt;
;read_html(url)&lt;br /&gt;
:Read html tables into a list of [[#DataFrame |dataframes]] (no header, no index)&lt;br /&gt;
Example code. The first line in the table is a header, the first column the index (e.g. dates), decimal specifies the decimal point character.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
tables = pd.read_html(url,header=0,index_col=0,decimal=&amp;lt;char&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;read_sql(query,cnx,index_columns=[col1,col2])&lt;br /&gt;
:Read data from the database opened on cnx (see [[Python:Databases]])&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
df = pd.read_sql(query,cnx,index_col=[&#039;Primarykey&#039;])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;read_csv(csvfile)&lt;br /&gt;
:Read data from a file with Character Separated Values&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_csv(csvfile, delimiter=&#039;,&#039;, usecols=[&amp;lt;columnA&amp;gt;, &amp;lt;columnB&amp;gt;], dtype = {&amp;lt;columnA&amp;gt;: str})&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Read columns &amp;lt;columnA&amp;gt; and &amp;lt;columnB&amp;gt; into a dataframe and force columnA to string type.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_csv(csvfile, index_col=False, header=None, names=[&#039;columnA&#039;, columnB&#039;], na_values = &#039;None&#039;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Read from a file with no indexcolumn nor a headerrow,  set the colomnnames and handle &#039;None&#039; and NA value.&lt;br /&gt;
&lt;br /&gt;
==Excel==&lt;br /&gt;
;read_excel(xlsfile, sheetname)&lt;br /&gt;
:Read data from the sheet with &#039;sheetname&#039; in a microsoft [[XLS|Excel file]] into a dataframe&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_excel(xlsfile,sheetname,converters={&#039;columna&#039;:str,&#039;columnb&#039;:str})&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Force columns to be read as string&lt;br /&gt;
;read_excel(xlsfile, sheet_name=None)&lt;br /&gt;
:Read all sheets into a dict {sheetname: df,...}. Sheets can be specified by number or name, if multiple, in a list. If only 1 sheet is specified a dataframe is returned, not a dict of dataframes.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
dfdict = pd.read_excel(filename, sheet_name=None)&lt;br /&gt;
for sheetname, df in dfdict.items():&lt;br /&gt;
   print(f&amp;quot;Working on sheet {sheetname}&amp;quot;)&lt;br /&gt;
   for index, row in df.iterrows():&lt;br /&gt;
      print(row)&lt;br /&gt;
   adict = df.to_dict(&#039;records&#039;)    # Creates a list of dicts [{columname: value,...},...]&lt;br /&gt;
   print(json.dumps(adict, indent=4))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Convert all sheets to CSV files&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import sys&lt;br /&gt;
import pandas as pd&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    for filename in sys.argv[1:]:&lt;br /&gt;
        try:&lt;br /&gt;
            dfdict = pd.read_excel(filename, sheet_name=None)&lt;br /&gt;
        except Exception as exception:&lt;br /&gt;
            print(f&amp;quot;{filename} cannot be read by pandas.read_excel as {exception}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            for sheetname, df in dfdict.items():&lt;br /&gt;
                print(f&amp;quot;Working on {filename}, {sheetname}&amp;quot;)&lt;br /&gt;
                if len(dfdict) == 1:&lt;br /&gt;
                    sheetname = &#039;&#039;&lt;br /&gt;
                else:&lt;br /&gt;
                    sheetname = f&amp;quot;_{sheetname}&amp;quot;&lt;br /&gt;
                lines = df.to_dict(&#039;records&#039;)&lt;br /&gt;
                header = lines[0].keys()&lt;br /&gt;
                outputfile = filename.replace(&#039;.xlsx&#039;, f&amp;quot;{sheetname}.csv&amp;quot;)&lt;br /&gt;
                fh = open(outputfile, &#039;w&#039;)&lt;br /&gt;
                fh.write(&#039;,&#039;.join(header) + &#039;\n&#039;)&lt;br /&gt;
                for line in lines:&lt;br /&gt;
                    fh.write(&#039;,&#039;.join(map(str,line.values())) + &#039;\n&#039;)&lt;br /&gt;
                fh.close()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
main()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Pandas&amp;diff=1724</id>
		<title>Pandas</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Pandas&amp;diff=1724"/>
		<updated>2026-08-04T07:01:57Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Use data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
Check the [https://pandas.pydata.org/pandas-docs/stable/10min.html 10 minutes to Pandas] too or [https://pythonexamples.org/pandas-examples/ pythonexamples].&lt;br /&gt;
;import pandas as pd&lt;br /&gt;
:Import the library, we assume this was done on this page&lt;br /&gt;
&lt;br /&gt;
=DataFrame=&lt;br /&gt;
Object for tabular data (that is e.g. obtained by read_html).&lt;br /&gt;
&lt;br /&gt;
Each column is a [[Pandas#Series]]&lt;br /&gt;
&lt;br /&gt;
;df = &amp;lt;nowiki&amp;gt;pd.DataFrame([{col1: 1,col2: 2},{col1: 1,col2: 2}])&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Create a simple dataframe having a range index, 2 rows and 2 columns&lt;br /&gt;
;df = &amp;lt;nowiki&amp;gt;pd.DataFrame([{col1: 1,col2: 2},{col1: 1,col2: 2}],[row1,row2])&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Create a dataframe having a list index. The size of index must match the number of rows.&lt;br /&gt;
&lt;br /&gt;
Single columns can be addressed by there name like in &amp;lt;code&amp;gt;df.columnname.unique()&amp;lt;/code&amp;gt; to get unique values in a column.&lt;br /&gt;
&lt;br /&gt;
Single or multiple columns can be addressed as list like in &amp;lt;code&amp;gt;df.set_index([column1,column2])&amp;lt;/code&amp;gt; to set an index over 2 columns.&lt;br /&gt;
&lt;br /&gt;
;df.copy&lt;br /&gt;
:Make a copy of df ( = will point to the same dataframe, like with [[Python:DataTypes#Dictionary or dict|dictionaries]])&lt;br /&gt;
&lt;br /&gt;
;df.join(table2)&lt;br /&gt;
:Like SQL-join merge on index&lt;br /&gt;
;df.merge(table2,on=&amp;lt;column&amp;gt;)&lt;br /&gt;
:Like SQL-join on  &amp;lt;column&amp;gt; = df.index&lt;br /&gt;
;dfall.merge(table2, on = &amp;lt;column&amp;gt;, how=&#039;left&#039;, indicator=True)&lt;br /&gt;
:Return df joined with table2. Add column _merge with value &#039;left_only&#039; to records that only exist in df.&lt;br /&gt;
;df = dfall[dfall[&#039;_merge&#039;] == &#039;left_only&#039;]&lt;br /&gt;
:Return dataframe with all records not in table2&lt;br /&gt;
;df = pd.concat(dflist)&lt;br /&gt;
:Concatenate all dataframes in dflist&lt;br /&gt;
&lt;br /&gt;
==Information==&lt;br /&gt;
&lt;br /&gt;
;df.info()&lt;br /&gt;
:Information on dataframe (Index, size, datatypes per column)&lt;br /&gt;
;df.size&lt;br /&gt;
:Return the number of cells in a dataframe&lt;br /&gt;
;df.shape&lt;br /&gt;
:Return the number of rows and columns in a dataframe as [[Python:DataTypes#Tuple|tuple]].&lt;br /&gt;
;df.describe()&lt;br /&gt;
:Return various attributes for numeric columns in the dataframe. This may indicate if there are outlyers.&lt;br /&gt;
;df.head(x)&lt;br /&gt;
;df.tail(x)&lt;br /&gt;
:Return first/last x data rows of df (5 is the default value for x).&lt;br /&gt;
&lt;br /&gt;
;df.index&lt;br /&gt;
:Return the table index (class = pandas.core.indexes.base.Index)&lt;br /&gt;
&lt;br /&gt;
;df.columns&lt;br /&gt;
:Return the column headers (class = pandas.core.indexes.base.Index)&lt;br /&gt;
;df.dtypes&lt;br /&gt;
:Return the data-type of the columns&lt;br /&gt;
;df.columnname.dtype&lt;br /&gt;
:Return the data-type of column columnname&lt;br /&gt;
&lt;br /&gt;
==Modify== &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.rename(columns={oldname:newname}, inplace=True)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Redefine the column headers (modifies the dataframe itself, nothing is returned)&lt;br /&gt;
&lt;br /&gt;
;df.set_index([&#039;col1&#039;,&#039;col2&#039;])&lt;br /&gt;
:Return the dataframe with a new index composed of 2 columns&lt;br /&gt;
;df.reset_index()&lt;br /&gt;
:Return the dataframe with a default index (range)&lt;br /&gt;
;df.sort_index(ascending=False)&lt;br /&gt;
:Sort the dataframe on the index. &#039;True&#039; is the default if &#039;acsending&#039; is not supplied.&lt;br /&gt;
;df.index = df.index.map(str)&lt;br /&gt;
:For a data-type on the index&lt;br /&gt;
&lt;br /&gt;
;df.drop(index)&lt;br /&gt;
;df.drop([indexes])&lt;br /&gt;
;df.drop(range(0,3))&lt;br /&gt;
:Remove row(s) from a dataframe.&lt;br /&gt;
;df.drop(columns=[listofcolumnstodrop]&lt;br /&gt;
:Remove columns from a dataframe.&lt;br /&gt;
&lt;br /&gt;
;df.dropna(thresh=x)&lt;br /&gt;
:Return only rows that have at least x columns with a none-NA  value. If x &amp;lt; 2 the threshold can be dropped.&lt;br /&gt;
&lt;br /&gt;
;df.loc[&amp;lt;index&amp;gt;,[&#039;field1&#039;,&#039;field2&#039;]] = [value1,value2]&lt;br /&gt;
:Change values for index &amp;lt;index&amp;gt; in a dataframe&lt;br /&gt;
;df.fillna(&amp;lt;value&amp;gt;)&lt;br /&gt;
;df[[&amp;lt;column1&amp;gt;,&amp;lt;column2&amp;gt;]] = df[[&amp;lt;column1&amp;gt;,&amp;lt;column2&amp;gt;].fillna(&amp;lt;value&amp;gt;)&lt;br /&gt;
:Return dataframe with all NA-values (in the selected columns) replaced by &amp;lt;value&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;table.agg(newname=(&#039;columname&#039;, np.max))&lt;br /&gt;
:Add newname to df with the max of columnname. This named aggregations is only supported from version v0.25 &lt;br /&gt;
&lt;br /&gt;
;df.transform(&amp;lt;function&amp;gt;)&lt;br /&gt;
:Apply a function to an existing column or the entire dataframe.&lt;br /&gt;
&lt;br /&gt;
;df.assign(newcolumn = &amp;lt;expression&amp;gt;)&lt;br /&gt;
:Add column newcolumn to the dataframe&lt;br /&gt;
:Expression can be a function like &amp;quot;lambda d: d[&#039;column&#039;] * &amp;lt;something&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;df.apply(&amp;lt;function&amp;gt;)&lt;br /&gt;
:Apply a function to the dataframe. By default every element of the table.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.apply(lambda x: &amp;lt;function&amp;gt;(x) if x.name in [columnname] else x)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Apply a function to specified colums &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[columname] = df[columname].apply(lambda x: &amp;lt;function&amp;gt;(x))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Change a column in the dataframe by applying &amp;lt;function&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;df.replace(&amp;lt;pattern&amp;gt;,&amp;lt;newvalue&amp;gt;,regex=True)&lt;br /&gt;
:Replace &amp;lt;pattern&amp;gt; with &amp;lt;newvalue&amp;gt; in the entire dataframe&lt;br /&gt;
&lt;br /&gt;
;df[columna].mask(df[columna] == origvalue , newvalue, inplace=True)&lt;br /&gt;
:Change all cells in columa that have origvalue into newvalue (inplace, so in the dataframe itself).&lt;br /&gt;
&lt;br /&gt;
==Select data==&lt;br /&gt;
Use .loc, else colomn-names will be considered too (if I understand this[https://stackoverflow.com/questions/38886080/python-pandas-series-why-use-loc] correctly).&lt;br /&gt;
&lt;br /&gt;
;WARNING!!&lt;br /&gt;
:at least with .loc if only 1 item is found is it returned as string(/float?) else as dataframe/series.&lt;br /&gt;
&lt;br /&gt;
;df.[[iloc]][&amp;lt;slice&amp;gt;]&lt;br /&gt;
:Return the rows indicated by &amp;lt;slice&amp;gt; as pandas.Series &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.iloc[:,0:3]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[[col0,col1,col2]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Return 3 columns from the dataframe&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;columns&#039;)&lt;br /&gt;
:Return all columns which name matches &amp;lt;regexp&amp;gt;. (axis=1)&lt;br /&gt;
&lt;br /&gt;
;df.loc[&amp;lt;index&amp;gt;]&lt;br /&gt;
:Select the row(s) with index &amp;lt;index&amp;gt;&lt;br /&gt;
;df.loc[&amp;lt;indexname&amp;gt;].&amp;lt;columnname&amp;gt;&lt;br /&gt;
;df.loc[&amp;lt;indexname&amp;gt;].[&amp;lt;columnname&amp;gt;]&lt;br /&gt;
:Select only 1 column from a row as pandas series. You may convert that to a list or set immediately by using &amp;lt;code&amp;gt;list(df.loc[&amp;lt;indexname&amp;gt;].&amp;lt;columnname&amp;gt;)&amp;lt;/code&amp;gt;&lt;br /&gt;
;df.loc[0][0]&lt;br /&gt;
:Select a cell in a dataframe with no index or header&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[lambda d: d[column1] == &amp;lt;value&amp;gt; ]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[df[column1] == &amp;lt;value&amp;gt; ]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[df[column1].notnull()]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Select all rows where column1 equals &amp;lt;value&amp;gt; or do not have a null-value.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[(df[column1] == &amp;lt;value&amp;gt;) | (df[colomn1] == &amp;lt;value2&amp;gt;)]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Combine conditions with &#039;|&#039; (or) or &#039;&amp;amp;&#039; (and). Use () on each condition!!&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[datetime.today()-pd.Timedelta(days=7) : datetime.today()]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Select all rows where the (datetime)-index is between 7 days ago and today.&lt;br /&gt;
:NOTE!! The index must be sorted in ascending order[https://stackoverflow.com/q/67298584/2213323]. &lt;br /&gt;
;df.last(&#039;7D&#039;)&lt;br /&gt;
:Select the last 7 days in the dataframe. For this als the datetime index must be sorted in ascending order&lt;br /&gt;
&lt;br /&gt;
See also the [https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.contains.html#pandas.Series.str.contains pandas series pages]  &lt;br /&gt;
;df[df[&#039;fieldname&#039;].str.contains(&#039;regexp&#039;,regex=True)]&lt;br /&gt;
:Select all rows in df where fieldname contens matches regexp. The field must have a string datetype. If you are looking for a simple string you can leave out the regex=True part.&lt;br /&gt;
;df[df[&#039;fieldname&#039;].gt(value)]&lt;br /&gt;
:Select all rows in df where fieldname is bigger than value. The field must have a numeric datetype&lt;br /&gt;
&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;)&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;).&amp;lt;columnname&amp;gt;&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;).index&lt;br /&gt;
:Return all rows for which in index matches &amp;lt;regexp&amp;gt; or get only the column of the matched indexes. (axis=0 ) or the indexname(s).&lt;br /&gt;
:The .index returns the matching indexes as a [[Python:DataTypes#List|list]].&lt;br /&gt;
&lt;br /&gt;
;df.sort_values(&amp;lt;columnname&amp;gt;)&lt;br /&gt;
;df.sort_values([&amp;lt;column1&amp;gt;,&amp;lt;colunm2&amp;gt;],ascending=(True,False))&lt;br /&gt;
:Return the dataframe sorted on the values in the columns. The second form sorts on column1 first and then on column2, column1 ascending, column2 descending&lt;br /&gt;
;df.groupby([column1,column2])&lt;br /&gt;
:Return a DataFrameGroupBy object, this is not a dataframe&lt;br /&gt;
;df.collname.unique()&lt;br /&gt;
:Return a [[Numpy]] array with all distinct values in column &#039;collname&#039;&lt;br /&gt;
&lt;br /&gt;
;Get all rows from df1 that have an index that exists in df2&lt;br /&gt;
 df = df1[df1.index.isin(df2.index)]&lt;br /&gt;
&lt;br /&gt;
;Or get all intersectioned indices and select by loc:&lt;br /&gt;
 df = df1.loc[df1.index &amp;amp; df2.index]&lt;br /&gt;
 df = df1.loc[np.intersect1d(df1.index, df2.index)]&lt;br /&gt;
 df = df1.loc[df1.index.intersection(df2.index)]&lt;br /&gt;
&lt;br /&gt;
==Use data==&lt;br /&gt;
;Print 2 attributes for each row and check for no value&lt;br /&gt;
:pd.isna(value) works for Null, NaN (Nod a number) and NaT (not a time) too.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for index, row in df.iterrows():&lt;br /&gt;
    print(row[&#039;ColumnA&#039;],row[&#039;ColumnB&#039;])&lt;br /&gt;
    if ps.isna(row[&#039;ColumnA&#039;]):&lt;br /&gt;
        print(&#039;Found a NaN value&#039;) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
;In multi-column indexes the index is returned as a tuple&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;for (indexA, indexB), row in df.iterrows():&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Print all values for the first row&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for column, row in df.iteritems():&lt;br /&gt;
    print(column,row[0])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Loop over columns&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for column in df:&lt;br /&gt;
    print(f&amp;quot;Columnname {column}&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;df.iloc[0]&lt;br /&gt;
:return the values of the first row as pandas series. If there is only 1 column returns the value.&lt;br /&gt;
&lt;br /&gt;
;df.iloc[0][0]&lt;br /&gt;
:return the value of the first column in the first row. Columns can also be identified by name&lt;br /&gt;
&lt;br /&gt;
;df[&amp;lt;column&amp;gt;].quantile(q=0.1)&lt;br /&gt;
:Return the 10th percentile (10% of the values in &amp;lt;column&amp;gt; is lower than the 10th percentile)&lt;br /&gt;
&lt;br /&gt;
;df[&amp;lt;column].str.extract(r&amp;quot;A regex(p\w+)&amp;quot;)&lt;br /&gt;
:Return a series (column) of the values selected by [[Regular Expressions]] (p\w+)&lt;br /&gt;
;df[&amp;lt;columna&amp;gt;].map(str) + &#039;_&#039; + df[&amp;lt;columnb&amp;gt;].map(str)&lt;br /&gt;
:Return a series (column) with the columns concatenated. If not mapped to str an error will be thrown.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[&amp;lt;column&amp;gt;].map(str).apply(lambda x: x[-1])&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
:Return a series (column) with the last character of the &amp;lt;column&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Series=&lt;br /&gt;
Pandas Series [https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.html online documentation].&amp;lt;br&amp;gt;&lt;br /&gt;
A pandas series is a 1 dimensional array with named keys.&amp;lt;br&amp;gt;&lt;br /&gt;
Pandas Series have all kind of methods similar to [[Numpy]] like main, std, min, max,.... In fact Pandas is using numpy to do this.&lt;br /&gt;
;s = pd.Series([])&lt;br /&gt;
;s = pd.Series([valuelist],[indexlist])&lt;br /&gt;
:Initialize a series. If indexlist is omitted the keys are integers starting at 0.&lt;br /&gt;
;s[&amp;lt;key&amp;gt;] = &amp;lt;value&amp;gt;&lt;br /&gt;
:Assign &amp;lt;value&amp;gt; to the series element with key &amp;lt;key&amp;gt;&lt;br /&gt;
:The order in the series is the order in which they are created, NOT the numeric order.&lt;br /&gt;
:Elements can be addressed as &amp;lt;code&amp;gt;s[&amp;lt;key&amp;gt;]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;s.&amp;lt;key&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;s[&amp;lt;numkey&amp;gt;]&amp;lt;/code&amp;gt;. Where &amp;lt;numkey&amp;gt; is defined by the order the element was created. &lt;br /&gt;
:Once you have used named keys in a series you cannot create new elements with a numeric key.&lt;br /&gt;
;s.index&lt;br /&gt;
:All indexes in the series. Can be sliced to find a particular index.&lt;br /&gt;
;s.describe()&lt;br /&gt;
:Series statistics&lt;br /&gt;
&lt;br /&gt;
All in 1 example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
import pandas as pd&lt;br /&gt;
s = pd.Series([])&lt;br /&gt;
for i in range(50):&lt;br /&gt;
    s[i] = int(np.random.random() * 100)&lt;br /&gt;
&lt;br /&gt;
for i in s.index:&lt;br /&gt;
    print(i,s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funny, you can do &amp;lt;code&amp;gt;s[0]&amp;lt;/code&amp;gt; but not&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for i in s:&lt;br /&gt;
    print(s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To get all values from the series you do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for v in s:&lt;br /&gt;
    print(v)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To get the indexes too:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for i in s.index:&lt;br /&gt;
    print(i,s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TimeSeries==&lt;br /&gt;
Indexes that contains datetime values are automatically casted to a DatetimeIndex.&lt;br /&gt;
&lt;br /&gt;
;df.resample(&#039;5D&#039;).mean&lt;br /&gt;
:Return the dataframe with the average value of each 5 days.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.resample(&#039;1H&#039;).agg({&#039;ColumnA&#039;:&#039;first&#039;,&#039;ColumnB&#039;:&#039;max&#039;, &#039;ColumnC&#039;:&#039;min&#039;, &#039;ColumnD&#039;:&#039;last&#039; })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Resample with aggregation specified per column.&lt;br /&gt;
&lt;br /&gt;
;df.resample(&#039;5D&#039;,origin=&#039;end&#039;)&lt;br /&gt;
:Resample so the last timestamp is used, by default it starts with the first, the last set may be incomplete.&lt;br /&gt;
&lt;br /&gt;
==Datetime functions==&lt;br /&gt;
;df[datefield] = pd.to_datetime(df[datefield],format=&#039;%d-%m-%Y&#039;)&lt;br /&gt;
:Convert a string-column with a date into datetime. Format is the input format.&lt;br /&gt;
:WARNING: without format to_datetime tries to make up what the format is. This is pretty intelligent but can easily be wrong with day-numbers under 13&lt;br /&gt;
;df[datefield] = pd.to_datetime(df[datefield],unit=&#039;s&#039;)&lt;br /&gt;
:Convert a column with [[unix time]] into datetime.&lt;br /&gt;
;df[&amp;lt;timefield&amp;gt;] = testdf[&amp;lt;datetime-field&amp;gt;].dt.time&lt;br /&gt;
:Return a series (column) with the time-value of a datetime-column&lt;br /&gt;
&lt;br /&gt;
=Reading Data=&lt;br /&gt;
;read_html(url)&lt;br /&gt;
:Read html tables into a list of [[#DataFrame |dataframes]] (no header, no index)&lt;br /&gt;
Example code. The first line in the table is a header, the first column the index (e.g. dates), decimal specifies the decimal point character.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
tables = pd.read_html(url,header=0,index_col=0,decimal=&amp;lt;char&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;read_sql(query,cnx,index_columns=[col1,col2])&lt;br /&gt;
:Read data from the database opened on cnx (see [[Python:Databases]])&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
df = pd.read_sql(query,cnx,index_col=[&#039;Primarykey&#039;])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;read_csv(csvfile)&lt;br /&gt;
:Read data from a file with Character Separated Values&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_csv(csvfile, delimiter=&#039;,&#039;, usecols=[&amp;lt;columnA&amp;gt;, &amp;lt;columnB&amp;gt;], dtype = {&amp;lt;columnA&amp;gt;: str})&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Read columns &amp;lt;columnA&amp;gt; and &amp;lt;columnB&amp;gt; into a dataframe and force columnA to string type.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_csv(csvfile, index_col=False, header=None, names=[&#039;columnA&#039;, columnB&#039;], na_values = &#039;None&#039;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Read from a file with no indexcolumn nor a headerrow,  set the colomnnames and handle &#039;None&#039; and NA value.&lt;br /&gt;
&lt;br /&gt;
==Excel==&lt;br /&gt;
;read_excel(xlsfile, sheetname)&lt;br /&gt;
:Read data from the sheet with &#039;sheetname&#039; in a microsoft [[XLS|Excel file]] into a dataframe&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_excel(xlsfile,sheetname,converters={&#039;columna&#039;:str,&#039;columnb&#039;:str})&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Force columns to be read as string&lt;br /&gt;
;read_excel(xlsfile, sheet_name=None)&lt;br /&gt;
:Read all sheets into a dict {sheetname: df,...}. Sheets can be specified by number or name, if multiple, in a list. If only 1 sheet is specified a dataframe is returned, not a dict of dataframes.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
dfdict = pd.read_excel(filename, sheet_name=None)&lt;br /&gt;
for sheetname, df in dfdict.items():&lt;br /&gt;
   print(f&amp;quot;Working on sheet {sheetname}&amp;quot;)&lt;br /&gt;
   for index, row in df.iterrows():&lt;br /&gt;
      print(row)&lt;br /&gt;
   adict = df.to_dict(&#039;records&#039;)    # Creates a list of dicts [{columname: value,...},...]&lt;br /&gt;
   print(json.dumps(adict, indent=4))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Convert all sheets to CSV files&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import sys&lt;br /&gt;
import pandas as pd&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    for filename in sys.argv[1:]:&lt;br /&gt;
        try:&lt;br /&gt;
            dfdict = pd.read_excel(filename, sheet_name=None)&lt;br /&gt;
        except Exception as exception:&lt;br /&gt;
            print(f&amp;quot;{filename} cannot be read by pandas.read_excel as {exception}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            for sheetname, df in dfdict.items():&lt;br /&gt;
                print(f&amp;quot;Working on {filename}, {sheetname}&amp;quot;)&lt;br /&gt;
                if len(dfdict) == 1:&lt;br /&gt;
                    sheetname = &#039;&#039;&lt;br /&gt;
                else:&lt;br /&gt;
                    sheetname = f&amp;quot;_{sheetname}&amp;quot;&lt;br /&gt;
                lines = df.to_dict(&#039;records&#039;)&lt;br /&gt;
                header = lines[0].keys()&lt;br /&gt;
                outputfile = filename.replace(&#039;.xlsx&#039;, f&amp;quot;{sheetname}.csv&amp;quot;)&lt;br /&gt;
                fh = open(outputfile, &#039;w&#039;)&lt;br /&gt;
                fh.write(&#039;,&#039;.join(header) + &#039;\n&#039;)&lt;br /&gt;
                for line in lines:&lt;br /&gt;
                    fh.write(&#039;,&#039;.join(map(str,line.values())) + &#039;\n&#039;)&lt;br /&gt;
                fh.close()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
main()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Python:Control_structures&amp;diff=1723</id>
		<title>Python:Control structures</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Python:Control_structures&amp;diff=1723"/>
		<updated>2026-07-29T09:55:03Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
&lt;br /&gt;
Most flow control is standard. Indentation defines the code block to execute. You must be strict, all indents must be the same in a block, a mix of spaces and tabs is not allowed (unless each line uses the same mix).&lt;br /&gt;
&lt;br /&gt;
You can define you own [[Python:Functions]] too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
if expression:&lt;br /&gt;
    block&lt;br /&gt;
elif expression:&lt;br /&gt;
    block&lt;br /&gt;
else:&lt;br /&gt;
    otherblock&lt;br /&gt;
&lt;br /&gt;
for var1 in itterable:  # keys if itterable is a dict&lt;br /&gt;
    block&lt;br /&gt;
    if somethinghappens:&lt;br /&gt;
        break&lt;br /&gt;
&lt;br /&gt;
while expression:&lt;br /&gt;
    block&lt;br /&gt;
    if somethinghappens:&lt;br /&gt;
        continue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt;&lt;br /&gt;
:Stop looping immediately. Jump to the next statement after the loop.&lt;br /&gt;
;&amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt;&lt;br /&gt;
:Stop the current iteration immediately and jump the the top of the loop, do the next iteration.&lt;br /&gt;
;&amp;lt;code&amp;gt;pass&amp;lt;/code&amp;gt;&lt;br /&gt;
:No operation, use e.g. to avoid negative tests&lt;br /&gt;
;&amp;lt;code&amp;gt;var1 = ( x if &amp;lt;condition1&amp;gt; elif &amp;lt;condition2&amp;gt; y else z )&amp;lt;/code&amp;gt;&lt;br /&gt;
:Different way to assign a value conditionally. () only needed if spread over more lines.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Exception handling==&lt;br /&gt;
&lt;br /&gt;
Exceptions are used a lot by python programmers. The mantra is: &amp;quot;Easier to ask for forgiveness than permission&amp;quot; aka EAFP; and it is said to be faster. &lt;br /&gt;
&lt;br /&gt;
To catch exceptions:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
try:&lt;br /&gt;
    blockthatmaythowexception&lt;br /&gt;
except &amp;lt;exception&amp;gt;:&lt;br /&gt;
    blockifexceptionisthrown&lt;br /&gt;
except &amp;lt;exception2&amp;gt; as ex:&lt;br /&gt;
    blockifexception2isthrown&lt;br /&gt;
else:&lt;br /&gt;
    blockif_NO_exceptionisthrown&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
NOTE: elif is not allowed here.&lt;br /&gt;
&lt;br /&gt;
Specifying a specific exception is optional but highly recommended. However, take care you don&#039;t forgive real faults.&lt;br /&gt;
&lt;br /&gt;
If more exceptions are defined with 1 try only 1 exception block will be executed,&lt;br /&gt;
&lt;br /&gt;
For reporting where the exception happened use [[#traceback]].&lt;br /&gt;
&lt;br /&gt;
;except &amp;lt;exception&amp;gt; as ex&lt;br /&gt;
:Puts the exception result in ex. ex.message has the reason for the exception.&lt;br /&gt;
&lt;br /&gt;
;type(ex)&lt;br /&gt;
:The exception class&lt;br /&gt;
&lt;br /&gt;
;except Exception&lt;br /&gt;
:Catches any exception&lt;br /&gt;
&lt;br /&gt;
;except NameError&lt;br /&gt;
:The variable does not exist&lt;br /&gt;
&lt;br /&gt;
;except KeyError&lt;br /&gt;
:The key does not exist in the dict&lt;br /&gt;
&lt;br /&gt;
;except IndexError&lt;br /&gt;
:The index does not exist in the list&lt;br /&gt;
&lt;br /&gt;
A full list of exception-classes can be found in the [https://docs.python.org/3/library/exceptions.html#exception-hierarchy python docs]&lt;br /&gt;
&lt;br /&gt;
;raise &amp;lt;Exception&amp;gt;(&amp;lt;text&amp;gt;)&lt;br /&gt;
:Raise an &amp;lt;Exception&amp;gt; exception, &amp;lt;Exception&amp;gt;-class must exist, &amp;lt;text&amp;gt; is up to you.&lt;br /&gt;
&lt;br /&gt;
===Traceback===&lt;br /&gt;
Show where things went wrong&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import traceback&lt;br /&gt;
tracetext = traceback.format_exc()   # Return info as string&lt;br /&gt;
traceback.print_exc()  # Print the info&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Warnings==&lt;br /&gt;
[https://docs.python.org/3/library/warnings.html Warnings] are a subcategory of Exceptions for problems that do not break the script. E.g. for deprecated modules, division by 0 etc.&lt;br /&gt;
&lt;br /&gt;
After importing the warnings package you can do things like &lt;br /&gt;
;warnings.simplefilter(action=&#039;ignore&#039;, category=UserWarning)&lt;br /&gt;
:Ignore warnings in a specific category.&lt;br /&gt;
;warnings.filterwarnings(&amp;quot;error&amp;quot;)&lt;br /&gt;
:Turn warnings into exceptions&lt;br /&gt;
;warnings.resetwarnings()&lt;br /&gt;
:Reset to the default handling of warnings&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import warnings&lt;br /&gt;
...&lt;br /&gt;
...&lt;br /&gt;
warnings.simplefilter(action=&#039;ignore&#039;, category=UserWarning)&lt;br /&gt;
&amp;lt;code that throws warning&amp;gt;&lt;br /&gt;
warnings.resetwarnings()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This way the warning settings are restored after the known one has been passed&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Iptables&amp;diff=1722</id>
		<title>Iptables</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Iptables&amp;diff=1722"/>
		<updated>2026-07-06T09:50:41Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:networking]]&lt;br /&gt;
[[category:Linux/Unix]]&lt;br /&gt;
[[nftables]] is a successor of iptables of firewall managment&lt;br /&gt;
&lt;br /&gt;
;iptables -F&lt;br /&gt;
:Flush all rules&lt;br /&gt;
;iptables -nvL&lt;br /&gt;
:Show all rules&lt;br /&gt;
&lt;br /&gt;
In Debian rules are in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/iptables/rules.v4&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/iptables/rules.v6&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pretty strict rules for an IPv4 webserver can be configured like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
cat /etc/iptables/rules.v4&lt;br /&gt;
*filter&lt;br /&gt;
:INPUT DROP -4 [0:0]&lt;br /&gt;
:FORWARD DROP -4 [0:0]&lt;br /&gt;
:OUTPUT ACCEPT -4 [0:0]&lt;br /&gt;
-A INPUT -4 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT&lt;br /&gt;
-A INPUT -4 -p icmp -j ACCEPT&lt;br /&gt;
-A INPUT -4 -i lo -j ACCEPT&lt;br /&gt;
-A INPUT -4 -p tcp -m conntrack --ctstate NEW -m tcp -s 192.168.2.0/24 --dport 22 -j ACCEPT&lt;br /&gt;
-A INPUT -4 -p tcp -m conntrack --ctstate NEW -m tcp --dport 80 -j ACCEPT&lt;br /&gt;
-A INPUT -4 -p tcp -m conntrack --ctstate NEW -m tcp --dport 443 -j ACCEPT&lt;br /&gt;
COMMIT&lt;br /&gt;
&lt;br /&gt;
cat /etc/iptables/rules.v6&lt;br /&gt;
*filter&lt;br /&gt;
:INPUT DROP -6 [0:0]&lt;br /&gt;
:FORWARD DROP -6 [0:0]&lt;br /&gt;
:OUTPUT DROP -6 [0:0]&lt;br /&gt;
-A INPUT -6 -i lo -j ACCEPT&lt;br /&gt;
-A OUTPUT -6 -o lo -j ACCEPT&lt;br /&gt;
COMMIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Activated by &amp;lt;code&amp;gt;iptables-restore &amp;lt; /etc/iptables/rules.v4&amp;lt;/code&amp;gt; this results in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
iptables -nvL&lt;br /&gt;
Chain INPUT (policy DROP 100 packets, 27924 bytes)&lt;br /&gt;
 pkts bytes target     prot opt in     out     source               destination         &lt;br /&gt;
19748 1436K ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED&lt;br /&gt;
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           &lt;br /&gt;
   25  1800 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           &lt;br /&gt;
   84  5040 ACCEPT     tcp  --  *      *       192.168.2.0/24       0.0.0.0/0            ctstate NEW tcp dpt:22&lt;br /&gt;
    2    92 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate NEW tcp dpt:80&lt;br /&gt;
    9   540 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate NEW tcp dpt:443&lt;br /&gt;
&lt;br /&gt;
Chain FORWARD (policy DROP 0 packets, 0 bytes)&lt;br /&gt;
 pkts bytes target     prot opt in     out     source               destination         &lt;br /&gt;
&lt;br /&gt;
Chain OUTPUT (policy ACCEPT 35665 packets, 49M bytes)&lt;br /&gt;
 pkts bytes target     prot opt in     out     source               destination        &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For IPv6 &lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
ip6tables-restore &amp;lt; /etc/iptables/rules.v6&lt;br /&gt;
&lt;br /&gt;
ip6tables -nvL&lt;br /&gt;
Chain INPUT (policy DROP 14 packets, 2902 bytes)&lt;br /&gt;
 pkts bytes target     prot opt in     out     source               destination         &lt;br /&gt;
   13  2476 ACCEPT     all      lo     *       ::/0                 ::/0                &lt;br /&gt;
&lt;br /&gt;
Chain FORWARD (policy DROP 0 packets, 0 bytes)&lt;br /&gt;
 pkts bytes target     prot opt in     out     source               destination         &lt;br /&gt;
&lt;br /&gt;
Chain OUTPUT (policy DROP 16 packets, 2134 bytes)&lt;br /&gt;
 pkts bytes target     prot opt in     out     source               destination         &lt;br /&gt;
   13  2476 ACCEPT     all      *      lo      ::/0                 ::/0                &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=ufw=&lt;br /&gt;
(Uncomplicated FireWall) is a frontend to iptables that creates a pretty complicated set of firewall rules.&lt;br /&gt;
&lt;br /&gt;
Configuration files are stored in /etc/ufw/&lt;br /&gt;
&lt;br /&gt;
By default the INPUT and FORWARD chain drop all, OUTPUT allow all.&lt;br /&gt;
&lt;br /&gt;
;ufw enable/disable&lt;br /&gt;
:Enable/Disable the firewall rules&lt;br /&gt;
&lt;br /&gt;
;ufw allow proto tcp from 192.168.1.0/24 to any port 22;&lt;br /&gt;
:ufw allow proto tcp from fd8e:xxx:xxx:xxx::/64 to any port 22&lt;br /&gt;
:Add firewall rule to allow port 22 (ssh) from a local subnet to the current set and to the ufw configuration files. Works for IPv6 addresses too&lt;br /&gt;
&lt;br /&gt;
;ufw delete allow proto tcp from 192.168.1.0/24 to any port 22&lt;br /&gt;
:Remove firewall rule to allow port 22 (ssh) from a local subnet from current set and from the ufw configuration files.&lt;br /&gt;
&lt;br /&gt;
;ufw delete &amp;lt;rulenumber&amp;gt;&lt;br /&gt;
:Delete the rule with number &amp;lt;rulenumber&amp;gt; (see below)&lt;br /&gt;
&lt;br /&gt;
;ufw status numbered&lt;br /&gt;
:Show rule summary with rule numbers&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=MariaDB/MySQL&amp;diff=1721</id>
		<title>MariaDB/MySQL</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=MariaDB/MySQL&amp;diff=1721"/>
		<updated>2026-06-09T19:50:47Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://mariadb.org/ MariaDB] is an open source fork of [http://www.mysql.com/ MySQL]. There are some differences but most are internal, for users the commands and [[SQL]] syntax is exactly the same.&lt;br /&gt;
&lt;br /&gt;
[https://www.phpmyadmin.net/ phpMyAdmin] is a web based GUI for the maintenance of MariaDB and MySQL servers.&lt;br /&gt;
&lt;br /&gt;
=Performance related queries=&lt;br /&gt;
;show status like &#039;Qcache_total_blocks&#039;&lt;br /&gt;
:Fragmentation of the query cache (lower is better)&lt;br /&gt;
;flush query cache&lt;br /&gt;
:Flush the query cache to fix the fragmentation (check if cache sizes need to be changed too)&lt;br /&gt;
&lt;br /&gt;
=User management=&lt;br /&gt;
User data is stored in table mysql.user&lt;br /&gt;
;alter user username@host identified by &#039;password&#039;&lt;br /&gt;
:Change a users password&lt;br /&gt;
;drop user username@host&lt;br /&gt;
:Delete a user&lt;br /&gt;
;grans all privileges on *.* to &#039;user&#039;@&#039;host&#039;;&lt;br /&gt;
:Grant all privileges to all database to a user&lt;br /&gt;
&lt;br /&gt;
=Login to password user without plain text password on commandline=&lt;br /&gt;
Put the password in a protected config file.&lt;br /&gt;
&lt;br /&gt;
 vi ~/.my.conf&lt;br /&gt;
 [client]&lt;br /&gt;
 password=&amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 chmod 600 ~/.my.cnf&lt;br /&gt;
&lt;br /&gt;
When you want to use a different filename start mysql-clinet like&lt;br /&gt;
 mysql --defaults-file=/home/francis/mysql-opts&lt;br /&gt;
&lt;br /&gt;
NOTE: commands can be stored in the history logging. Make sure the log-file (~/.mysql_history) has very restrictive permissions&lt;br /&gt;
&lt;br /&gt;
=Move users from one server to another=&lt;br /&gt;
&lt;br /&gt;
Starting on the source server execute this script&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
PASSWORD=$1&lt;br /&gt;
mysql -B -N -uroot -p${PASSWORD} -e &amp;quot;SELECT CONCAT(&#039;\&#039;&#039;, user,&#039;\&#039;@\&#039;&#039;, host, &#039;\&#039;&#039;) FROM user WHERE user IN (&#039;username1&#039;, &#039;username2&#039;, &#039;username3&#039;)&amp;quot; &amp;gt; users.txt&lt;br /&gt;
while read line&lt;br /&gt;
 do&lt;br /&gt;
  mysql -B -N -uroot -p${PASSWORD} -e &amp;quot;SHOW GRANTS FOR $line&amp;quot;&lt;br /&gt;
 done &amp;lt; users.txt &amp;gt; users.sql&lt;br /&gt;
sed -i &#039;s/$/;/&#039; users.sql&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move the file to the other server and there do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p &amp;lt; users.sql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Set up replication=&lt;br /&gt;
With replication all transactions on the master database server are immediately replicated to the slave database server. So you create a hot copy of the database that can be used in case of a failure of the master server or to offload the master server by executing retrieval queries on the slave.&lt;br /&gt;
&lt;br /&gt;
The slave server logs into the master and checks if the bin-log position differs, if so all transactions after the last binlog-position are redone on the slave.&lt;br /&gt;
&lt;br /&gt;
This procedure is for a large part based on a tutorial found on howtoforge.com [https://www.howtoforge.com/mysql_database_replication]&lt;br /&gt;
&lt;br /&gt;
For multi master replication to 1 slave check [https://mariadb.com/kb/en/multi-source-replication/ this].&lt;br /&gt;
&lt;br /&gt;
==On the master==&lt;br /&gt;
;Edit the my.cnf so it has below lines.&lt;br /&gt;
:The server must be accessible from the slave server and the server-id must be unique in you network&lt;br /&gt;
:The binlog-do-db specifies for which database the binlog is written, one line per database. If omitted for all databases binlog is written except those specified by binlog-ingnore-db.&lt;br /&gt;
 #skip-networking&lt;br /&gt;
 #bind-address            = 127.0.0.1&lt;br /&gt;
 log-bin = /var/log/mysql/mysql-bin.log&lt;br /&gt;
 #binlog-do-db=exampledb&lt;br /&gt;
 binlog-ignore-db       = mysql&lt;br /&gt;
 binlog-ignore-db       = information_schema&lt;br /&gt;
 binlog-ignore-db       = performance_schema&lt;br /&gt;
 binlog-ignore-db       = phpmyadmin&lt;br /&gt;
 server-id=1&lt;br /&gt;
&lt;br /&gt;
;Restart the database server&lt;br /&gt;
 /etc/init.d/mysql restart&lt;br /&gt;
&lt;br /&gt;
;Create a replication user&lt;br /&gt;
 mysql -uroot -p&lt;br /&gt;
 mysql&amp;gt; GRANT REPLICATION SLAVE ON *.* TO &#039;slave_user&#039;@&#039;%&#039; IDENTIFIED BY &#039;&amp;lt;some_password&amp;gt;&#039;;&lt;br /&gt;
 mysql&amp;gt; FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
;Make sure nothing is changes in the database during backup&lt;br /&gt;
 mysql&amp;gt; USE exampledb;&lt;br /&gt;
 mysql&amp;gt; FLUSH TABLES WITH READ LOCK;&lt;br /&gt;
Or, for all databases;&lt;br /&gt;
 mysql&amp;gt; FLUSH TABLES WITH READ LOCK;&lt;br /&gt;
 mysql&amp;gt; SET GLOBAL read_only = 1;&lt;br /&gt;
;Check status;&lt;br /&gt;
 mysql&amp;gt; SHOW MASTER STATUS;&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 | File          | Position | Binlog_do_db | Binlog_ignore_db |&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 | mysql-bin.006 | 183      |              |                  |&lt;br /&gt;
 +---------------+----------+--------------+------------------+&lt;br /&gt;
 1 row in set (0.00 sec)&lt;br /&gt;
&lt;br /&gt;
;Dump the database:&lt;br /&gt;
 mysqldump -u root -p&amp;lt;password&amp;gt; --opt exampledb &amp;gt; exampledb.sql&lt;br /&gt;
&lt;br /&gt;
;Unlock the tables&lt;br /&gt;
 mysql -u root -p&amp;lt;password&amp;gt;&lt;br /&gt;
 mysql&amp;gt; UNLOCK TABLES;&lt;br /&gt;
 mysql&amp;gt; quit;&lt;br /&gt;
Or, for all databases;&lt;br /&gt;
 mysql&amp;gt; SET GLOBAL read_only = 0;&lt;br /&gt;
 mysql&amp;gt; UNLOCK TABLES;&lt;br /&gt;
&lt;br /&gt;
==On the slave server==&lt;br /&gt;
&lt;br /&gt;
;Create the slave database&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
CREATE DATABASE exampledb;&lt;br /&gt;
quit;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Load the database dump created on the master&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt; exampledb &amp;lt; /path/to/exampledb.sql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Edit the my.cnf so it has these lines&lt;br /&gt;
:The server-id must be unique in you network&lt;br /&gt;
:The replicate-do-db specifies for which database the binlog on the master is read, one line per database. If omitted for all databases binlog is read.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
server-id=2&lt;br /&gt;
replicate-do-db=exampledb&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Restart the database server&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/init.d/mysql restart&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the following statement the values from SHOW MASTER STATUS above must be used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
STOP SLAVE;&lt;br /&gt;
CHANGE MASTER TO MASTER_HOST=&amp;lt;masterIP&amp;gt;, MASTER_USER=&#039;slave_user&#039;, MASTER_PASSWORD=&#039;&amp;lt;password&amp;gt;&#039;, MASTER_LOG_FILE=&#039;mysql-bin.006&#039;, MASTER_LOG_POS=183; &lt;br /&gt;
START SLAVE;&lt;br /&gt;
quit;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====In case of using GTID for replication====&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -u root -p&amp;lt;password&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=sql&amp;gt;&lt;br /&gt;
CHANGE MASTER TO master_host= &amp;lt;masterIP&amp;gt;&#039;, master_user=&#039;&amp;lt;slave_user&amp;gt;&#039;, MASTER_PASSWORD=&#039;&amp;lt;password&amp;gt;&#039;, master_use_gtid=current_pos;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SELECT @@GLOBAL.gtid_slave_pos;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Show current GTID position&lt;br /&gt;
;&amp;lt;code&amp;gt;SET GLOBAL gtid_slave_pos = &amp;quot;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Reset counter, slave databases must be in sync with the master.&lt;br /&gt;
&lt;br /&gt;
=Add a database to replication=&lt;br /&gt;
&lt;br /&gt;
Everything must be working fine and log positions up to date. On the slave Read_Master_Log_Pos is the same as the Exec_Master_Log_Pos and the Read_Master_Log_Pos is the same as the masters Position (in show master status).&lt;br /&gt;
&lt;br /&gt;
Then you can do:&lt;br /&gt;
* Slave: Add database to my.cnf (replicate-do-db=&amp;lt;dbname&amp;gt;)&lt;br /&gt;
* Slave: &amp;lt;code&amp;gt;stop slave;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Master: &amp;lt;code&amp;gt;flush tables with read lock;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Master: dump database&lt;br /&gt;
* Master: &amp;lt;code&amp;gt;unlock tables&amp;lt;/code&amp;gt;&lt;br /&gt;
* Slave: Load the database dump&lt;br /&gt;
* Slave: Restart the database server&lt;br /&gt;
Then check the slave status &amp;lt;code&amp;gt;show slave status \G&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Repair replication=&lt;br /&gt;
==On the slave server==&lt;br /&gt;
;Stop replication processes&lt;br /&gt;
 mysql -u root -p&lt;br /&gt;
 mysql&amp;gt; stop slave;&lt;br /&gt;
&lt;br /&gt;
==On the master server==&lt;br /&gt;
Dump the replicated databases including the replication data.&lt;br /&gt;
&amp;lt;code&amp;gt;mysqldump --databases &amp;lt;db1&amp;gt; &amp;lt;db2&amp;gt; --master-data=1 &amp;gt; ../mysql_dump_$(hostname)_$(date +%Y-%m-%d_%H-%M).sql.dump&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==On the slave server==&lt;br /&gt;
;Import the databases&lt;br /&gt;
&amp;lt;code&amp;gt;mysql -uroot -p &amp;lt; &amp;lt;dumpfile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;Restart the slave processes and check the slave status.&lt;br /&gt;
When needed update the slave log-file and position as in the masters &amp;lt;code&amp;gt;show slave status&amp;lt;/code&amp;gt;&lt;br /&gt;
 mysql&amp;gt; CHANGE MASTER TO MASTER_LOG_FILE=&#039;&amp;lt;filename&amp;gt;&#039;, MASTER_LOG_POS=&amp;lt;postition&amp;gt;; &lt;br /&gt;
Then:&lt;br /&gt;
 mysql&amp;gt; start slave;&lt;br /&gt;
 mysql&amp;gt; show slave status \G&lt;br /&gt;
&lt;br /&gt;
This should not show any errors&lt;br /&gt;
&lt;br /&gt;
=Populate and update timezone information=&lt;br /&gt;
Timezone information is required to use functions like CONVERT_TZ. The mysql.time_zone table need to be populated and maintained when the data changes.&lt;br /&gt;
&lt;br /&gt;
On a [[synology]] server following command takes care of this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/volume1/@appstore/MariaDB10/usr/local/mariadb10/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo |mysql -uroot -p mysql&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Webdesign&amp;diff=1720</id>
		<title>Webdesign</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Webdesign&amp;diff=1720"/>
		<updated>2026-06-07T08:53:54Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Certificate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Webdesign]]&lt;br /&gt;
=Speed=&lt;br /&gt;
;Tests&lt;br /&gt;
*[https://developers.google.com/speed/pagespeed/insights/ Google]&lt;br /&gt;
*[https://tools.pingdom.com/ Pingdom]&lt;br /&gt;
&lt;br /&gt;
;Enable [https://en.wikipedia.org/wiki/HTTP/2 http/2] on port 443 for better performance&lt;br /&gt;
:In your webserver condfig put &amp;lt;code&amp;gt;listen 443 http2 ssl;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=HTML=&lt;br /&gt;
Make up language for web pages.&lt;br /&gt;
Check [https://www.w3schools.com/ w3schools]&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;a href=&amp;quot;a url&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;go to a url&amp;lt;/a&amp;gt;&lt;br /&gt;
:Hyperlink to a url to be opened in a new tab. Display &amp;quot;go to a url&amp;quot; as hyperlink (underscored)&lt;br /&gt;
&lt;br /&gt;
=CSS=&lt;br /&gt;
Change presentation style for html elements.&lt;br /&gt;
Check [https://www.w3schools.com/ w3schools]&lt;br /&gt;
&lt;br /&gt;
;Use a lightyellow background, black characters and readable font:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=css&amp;gt;&lt;br /&gt;
body {&lt;br /&gt;
	color: #000000;&lt;br /&gt;
	background-color: #FFFFDD;&lt;br /&gt;
	font-family: arial, helvetica, sans-serif;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Colors=&lt;br /&gt;
Check [https://html-color.codes/ 🎨 HTML Color Codes]&lt;br /&gt;
&lt;br /&gt;
=Certificate=&lt;br /&gt;
Check [https://www.ssl.org/ ssl org]&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Webdesign&amp;diff=1719</id>
		<title>Webdesign</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Webdesign&amp;diff=1719"/>
		<updated>2026-06-07T08:49:20Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Webdesign]]&lt;br /&gt;
=Speed=&lt;br /&gt;
;Tests&lt;br /&gt;
*[https://developers.google.com/speed/pagespeed/insights/ Google]&lt;br /&gt;
*[https://tools.pingdom.com/ Pingdom]&lt;br /&gt;
&lt;br /&gt;
;Enable [https://en.wikipedia.org/wiki/HTTP/2 http/2] on port 443 for better performance&lt;br /&gt;
:In your webserver condfig put &amp;lt;code&amp;gt;listen 443 http2 ssl;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=HTML=&lt;br /&gt;
Make up language for web pages.&lt;br /&gt;
Check [https://www.w3schools.com/ w3schools]&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;a href=&amp;quot;a url&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;go to a url&amp;lt;/a&amp;gt;&lt;br /&gt;
:Hyperlink to a url to be opened in a new tab. Display &amp;quot;go to a url&amp;quot; as hyperlink (underscored)&lt;br /&gt;
&lt;br /&gt;
=CSS=&lt;br /&gt;
Change presentation style for html elements.&lt;br /&gt;
Check [https://www.w3schools.com/ w3schools]&lt;br /&gt;
&lt;br /&gt;
;Use a lightyellow background, black characters and readable font:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=css&amp;gt;&lt;br /&gt;
body {&lt;br /&gt;
	color: #000000;&lt;br /&gt;
	background-color: #FFFFDD;&lt;br /&gt;
	font-family: arial, helvetica, sans-serif;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Colors=&lt;br /&gt;
Check [https://html-color.codes/ 🎨 HTML Color Codes]&lt;br /&gt;
&lt;br /&gt;
=Certificate=&lt;br /&gt;
Check [https://crt.sh https://crt.sh/?q=domain.tld]&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=DNS&amp;diff=1718</id>
		<title>DNS</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=DNS&amp;diff=1718"/>
		<updated>2026-05-18T15:13:51Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Networking]]&lt;br /&gt;
[[Category:Linux/Unix]]&lt;br /&gt;
&lt;br /&gt;
Domain Name Service. Bind a name to IP-addresses.&lt;br /&gt;
&lt;br /&gt;
=Server side=&lt;br /&gt;
Zone transfer between master and slave server is on TCP port 53.&lt;br /&gt;
&lt;br /&gt;
Disable resolving IPv6 addresses by editing /etc/default/bind9 to have &amp;lt;code&amp;gt;OPTIONS=&amp;quot;-4 -u bind&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Client side=&lt;br /&gt;
Clients query the nameserver on UDP port 53.&lt;br /&gt;
&lt;br /&gt;
;host &amp;lt;hostname or IPaddress&amp;gt;&lt;br /&gt;
:Resolve hostname to IPadddres or IPaddress to hostname&lt;br /&gt;
;host &amp;lt;host or IP&amp;gt;  &amp;lt;nameserver&amp;gt;&lt;br /&gt;
:Resolve using the specified nameserver&lt;br /&gt;
&lt;br /&gt;
;dig &amp;lt;hostname&amp;gt;  @&amp;lt;nameserver&amp;gt;&lt;br /&gt;
:Resolve hostname with extra info from the optinoal &amp;lt;nameserver&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;/etc/resolv.conf&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
options timeout:1 attempts:1 rotate&lt;br /&gt;
nameserver &amp;lt;dns-server1 IP&amp;gt;&lt;br /&gt;
nameserver &amp;lt;dns-server2 IP&amp;gt;&lt;br /&gt;
options &amp;lt;interface&amp;gt;&lt;br /&gt;
search &amp;lt;default search domain&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;If the systemd-resolved is active&lt;br /&gt;
/etc/resolv.conf has  127.0.0.53 as nameserver&lt;br /&gt;
 &lt;br /&gt;
;resolvectl status&lt;br /&gt;
:Show which nameservers are used by the systemd-resolved&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=DNS&amp;diff=1717</id>
		<title>DNS</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=DNS&amp;diff=1717"/>
		<updated>2026-05-18T15:11:59Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Client side */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Domain Name Service. Bind a name to IP-addresses.&lt;br /&gt;
&lt;br /&gt;
=Server side=&lt;br /&gt;
Zone transfer between master and slave server is on TCP port 53.&lt;br /&gt;
&lt;br /&gt;
Disable resolving IPv6 addresses by editing /etc/default/bind9 to have &amp;lt;code&amp;gt;OPTIONS=&amp;quot;-4 -u bind&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Client side=&lt;br /&gt;
Clients query the nameserver on UDP port 53.&lt;br /&gt;
&lt;br /&gt;
;host &amp;lt;hostname or IPaddress&amp;gt;&lt;br /&gt;
:Resolve hostname to IPadddres or IPaddress to hostname&lt;br /&gt;
;host &amp;lt;host or IP&amp;gt;  &amp;lt;nameserver&amp;gt;&lt;br /&gt;
:Resolve using the specified nameserver&lt;br /&gt;
&lt;br /&gt;
;dig &amp;lt;hostname&amp;gt;  @&amp;lt;nameserver&amp;gt;&lt;br /&gt;
:Resolve hostname with extra info from the optinoal &amp;lt;nameserver&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;/etc/resolv.conf&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
options timeout:1 attempts:1 rotate&lt;br /&gt;
nameserver &amp;lt;dns-server1 IP&amp;gt;&lt;br /&gt;
nameserver &amp;lt;dns-server2 IP&amp;gt;&lt;br /&gt;
options &amp;lt;interface&amp;gt;&lt;br /&gt;
search &amp;lt;default search domain&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;If the systemd-resolved is active&lt;br /&gt;
/etc/resolv.conf has  127.0.0.53 as nameserver&lt;br /&gt;
 &lt;br /&gt;
;resolvectl status&lt;br /&gt;
:Show which nameservers are used by the systemd-resolved&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Python:DataTypes&amp;diff=1716</id>
		<title>Python:DataTypes</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Python:DataTypes&amp;diff=1716"/>
		<updated>2026-05-13T11:48:45Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* list */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
&lt;br /&gt;
=Object Classes=&lt;br /&gt;
Lots of things to tell about strings, they have there own [[Python:Strings]] page.&lt;br /&gt;
&lt;br /&gt;
For different number types we have [[Python:Numbers]].&lt;br /&gt;
&lt;br /&gt;
Also for numpy (module for scientific arithmetic) there is a special [[Numpy]] page.&lt;br /&gt;
&lt;br /&gt;
Objects are iterable if they can contain more than 1 ordered objects ([[Python:Strings|string]], list, tuple, dict).&lt;br /&gt;
&lt;br /&gt;
Objects are mutable if their content can be changed (list, set, dict)&lt;br /&gt;
&lt;br /&gt;
;isinstance(&amp;lt;obj&amp;gt;, &amp;lt;class&amp;gt;)&lt;br /&gt;
:Boolean (returns True or False) to check if &amp;lt;obj&amp;gt; is an instance of &amp;lt;class&amp;gt;. Classnames are str, int, dict, list, set, tuple, range, ...&lt;br /&gt;
&lt;br /&gt;
locals() and globals() are dictionaries holding the global and local variables so you can do:&lt;br /&gt;
;&amp;lt;code&amp;gt;if var in locals()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Check if a variable exists as local&lt;br /&gt;
;&amp;lt;code&amp;gt;if var in globals()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Check if a variable exists and is global.&lt;br /&gt;
;globals().update(adict) &lt;br /&gt;
:updates the globals with the dict. You can now address the keys as variable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;NOTE:&amp;lt;/strong&amp;gt; Variables are pointers to objects, not the object itself. dict2 = dict1 does not make a new dictionary. Both variables point to the same dictionary. To make a copy use dict2 = dict(dict1). Same for lists, sets and tuples. &lt;br /&gt;
&lt;br /&gt;
==list==&lt;br /&gt;
Class of iterable, mutable objects. Lists can be compared to arrays in other languages. Lists can contain a mixture of all kind of objects.&lt;br /&gt;
&lt;br /&gt;
;lst1 = []&lt;br /&gt;
:Initialize an empty list&lt;br /&gt;
&lt;br /&gt;
;lst1 = [0] * 10&lt;br /&gt;
:Create a list with 10 elements 0&lt;br /&gt;
&lt;br /&gt;
;lst1.append(2)&lt;br /&gt;
:Add the &#039;2&#039; object to the end of lst1&lt;br /&gt;
&lt;br /&gt;
;lst1.extend(list2)&lt;br /&gt;
;lst1 + lst2&lt;br /&gt;
:Add the elements of lst2 to the end of lst1&lt;br /&gt;
&lt;br /&gt;
;lst1.pop(n)&lt;br /&gt;
:Remove and return n&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; element from lst1. Last element if n is not specified.&lt;br /&gt;
;lst1.remove(x)&lt;br /&gt;
:Remove object x from the list.&lt;br /&gt;
&lt;br /&gt;
;lst1 = list(object)&lt;br /&gt;
:Convert object to a list (object is e.g. set, tuple or string)&lt;br /&gt;
&lt;br /&gt;
;count = lst1.count[x]&lt;br /&gt;
:Return the number of occurrences of x in lst1&lt;br /&gt;
&lt;br /&gt;
;lst1.index(x)&lt;br /&gt;
:Return the first position in lst1 where x is found&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;len(lst1) - 1 - lst1[::-1].index(x)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Return the last position in lst1 where x is found&lt;br /&gt;
;bisect(lst1, x)&lt;br /&gt;
:Return index of first value higher than x. bisect needs to be imported as &amp;lt;code&amp;gt;from bisect import bisect&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;lst1.sort()&lt;br /&gt;
:Sort lst1 and return &#039;None&#039; object&lt;br /&gt;
&lt;br /&gt;
;lst2 = sorted(iterable, key=int)&lt;br /&gt;
:Return the iterable object sorted as list.&lt;br /&gt;
:The optional key= part converts the elements to int before sorting. Other functions can be used too. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;srtlist = sorted(alist, key = lambda x: (x[4], x[0]))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Return alist sorted on the third and the first element of each list in alist (alist is a list of lists)&lt;br /&gt;
&lt;br /&gt;
[https://wiki.python.org/moin/HowTo/Sorting More on sorting].&lt;br /&gt;
&lt;br /&gt;
;random.shuffle(alist)&lt;br /&gt;
:Randomize the list element order. The list itself is changed, nothing is returned.&lt;br /&gt;
&lt;br /&gt;
;print (&#039;,&#039;.join(map(str, alist)))&lt;br /&gt;
:Concatenate the elements of alist to &amp;lt;element1&amp;gt;,&amp;lt;element2&amp;gt;,... and print&lt;br /&gt;
;print (&#039;\n&#039;.join(map(str, alist)))&lt;br /&gt;
:Print alist with each element on another line&lt;br /&gt;
;list(map(int, alist))&lt;br /&gt;
:Return a list with all elements in alist mapped to integer.&lt;br /&gt;
&lt;br /&gt;
;Put items matching a regular expression in newlist.&lt;br /&gt;
More on regular expressions in [[Python:Strings#Regular_Expressions_(regexp)]]&lt;br /&gt;
&lt;br /&gt;
NOTE: filter applies a function (regexp matching in this case) on the object (list1). The object is modified. A filter object is returned. A filter object is not a list. However, when you iterate over it, it does return the matching elements. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import re&lt;br /&gt;
filterobject = filter(re.compile(&amp;lt;regular expression&amp;gt;).search,list1)    # This returns a filter object you can iterate over but not slice like filterobject[0]&lt;br /&gt;
newlist = list(filter(re.compile(&amp;lt;regular expression&amp;gt;).search,list1)))  # This returns a real list&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Select from a list of lists.&lt;br /&gt;
&amp;lt;code&amp;gt;newist = [i for i in lists if &#039;SERACHSTRING&#039; in str(i)]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Check if some values are in a list (works for sets too)&lt;br /&gt;
&amp;lt;code&amp;gt;if [ i for i in alist if i in [value1,value2]]:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;sum(aListWithNumbers)&lt;br /&gt;
:Total of all values in the list&lt;br /&gt;
&lt;br /&gt;
==set==&lt;br /&gt;
Class of iterable, mutable objects. Objects added to sets are hashed. Therefor:&lt;br /&gt;
* Only immutable objects can be added to a set. So not dictionaries or lists&lt;br /&gt;
* Sets cannot hold duplicate objects (adding an object again does not change the set).&lt;br /&gt;
* Checking if a set holds an object is very fast.&lt;br /&gt;
&lt;br /&gt;
A set is iterable but has no order, therfor:&lt;br /&gt;
* You can loop over a set like &amp;lt;code&amp;gt;for a in set:&amp;lt;/code&amp;gt;&lt;br /&gt;
* You cannot take a [[Python:DataTypes#Slicing | slice]] from a set.&lt;br /&gt;
&lt;br /&gt;
;set1 = set()&lt;br /&gt;
:Initialize an empty set&lt;br /&gt;
&lt;br /&gt;
;set1 = set([&amp;lt;values&amp;gt;])&lt;br /&gt;
;set1 = {&amp;lt;val1&amp;gt;,&amp;lt;val2&amp;gt;}&lt;br /&gt;
:Initialize a set with objects. Note the list-format of &amp;lt;values&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
;set2 = set1.copy()&lt;br /&gt;
:Make a copy of set1. &amp;lt;code&amp;gt;set2 = set1&amp;lt;/code&amp;gt; will make set2 point to the same set, changing set1 will change set2 (as it is the same object).&lt;br /&gt;
;set1.add(2)&lt;br /&gt;
:Add the &#039;2&#039; object to set1. You can add only 1 object at a time.&lt;br /&gt;
&lt;br /&gt;
;set1.discard(2)&lt;br /&gt;
:Remove the &#039;2&#039; object from set1 (returns None object)&lt;br /&gt;
&lt;br /&gt;
;set1.update(itterable)&lt;br /&gt;
:Update the set with the elements in itterable (list, set,   )&lt;br /&gt;
;unionset = set1.union(set2)&lt;br /&gt;
:Combine the sets into a new set (e.g.to remove duplicates)&lt;br /&gt;
&lt;br /&gt;
;intersectset = set1.intersection(set2)&lt;br /&gt;
;intersectset = set1 &amp;amp; set2&lt;br /&gt;
:Put all elements that exist in both sets into a new set&lt;br /&gt;
&lt;br /&gt;
;diffset = set1 - set2&lt;br /&gt;
;diffset = set1.difference(set2)&lt;br /&gt;
:diffset will have all elements of set1 that are not in set2&lt;br /&gt;
&lt;br /&gt;
Augmented assignment (update the left hand object instead of creating a new one) are:&lt;br /&gt;
;set1 |= set2&lt;br /&gt;
:Update set1 with set2&lt;br /&gt;
;set1 -= set2&lt;br /&gt;
:Removed set2 from set1&lt;br /&gt;
;set1 &amp;amp;= set2&lt;br /&gt;
:set1 will have the elements that exist in both sets (intersection)&lt;br /&gt;
;set1 ^= set2&lt;br /&gt;
:set1 will have the elements that exist in only 1 of the sets&lt;br /&gt;
&lt;br /&gt;
==Tuple==&lt;br /&gt;
Class of iterable, immutable objects. It acts as an immutable [[#list|list]]. Multiple return values from functions are tuples and e.g. results from database queries are by default returned as tuple.&lt;br /&gt;
&lt;br /&gt;
;tpl1 = ()&lt;br /&gt;
:Initialize an empty tuple (pretty useless action)&lt;br /&gt;
&lt;br /&gt;
==Dictionary or dict==&lt;br /&gt;
Class of iterable, mutable objects. Dictionary&#039;s can be compared to perl hashes. Check the [[Python:JSON]] page too.&lt;br /&gt;
&lt;br /&gt;
;dict1 = {}&lt;br /&gt;
:Initialize an empty dictionary.&lt;br /&gt;
&lt;br /&gt;
;dict1 = { &amp;lt;nowiki&amp;gt;column1: value1, column2: value2&amp;lt;/nowiki&amp;gt; }&lt;br /&gt;
:Initialize dictionary with data &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The [[Python#collections|collections defaultdict]] module can be used for dictionairies with automatic key creation.&lt;br /&gt;
&lt;br /&gt;
;WARNING; In a [[Python:DataTypes#Dictionary_or_dict|dictionary]] created with defaultdict a key will be added when you try to read a non-existing lower key.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
from collections import defaultdict&lt;br /&gt;
adict = defaultdict(lambda: defaultdict())&lt;br /&gt;
print(adict[key1][key2])  # This will create adict[key1]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;adict = defaultdict(&amp;lt;type&amp;gt;)&lt;br /&gt;
:Create a dictionary key of the provided type automatically when it is used (see WARNINIG above). Use this to avoid checking if a key already exists before you populate it. If you do not provide &amp;lt;type&amp;gt; you can put in anything.&lt;br /&gt;
;bdict = dict(adict)&lt;br /&gt;
:bdict will be an ordinary dict.&lt;br /&gt;
&lt;br /&gt;
;adict = defaultdict(lambda&amp;lt;nowiki&amp;gt;: defaultdict(lambda: defaultdict()))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Use lambda function to handle multilevel dictionaries&lt;br /&gt;
:NOTE: For 2 levels, and 2nd level is a dictionary you can use &amp;lt;code&amp;gt;defaultdict(dict)&amp;lt;/code&amp;gt; too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;if key in dict:&lt;br /&gt;
:Test if key exists in dict. &amp;lt;code&amp;gt;if dict[key]:&amp;lt;/code&amp;gt; will throw a keyerror if it does not exist. &lt;br /&gt;
&lt;br /&gt;
;dict1.keys()&lt;br /&gt;
:Iterable  of keys in dict1&lt;br /&gt;
;dict1.values()&lt;br /&gt;
:Iterable of values &lt;br /&gt;
;dict1.items()&lt;br /&gt;
:iterable of all key-value pairs in dict1 as [[#Tuple|tuple]]s&lt;br /&gt;
&lt;br /&gt;
;sum(adict.values())&lt;br /&gt;
:Total of all values in a dict if all are numbers&lt;br /&gt;
&lt;br /&gt;
;dict2 = dict1.copy()&lt;br /&gt;
;dict2 = dict(dict1)&lt;br /&gt;
:Make a copy of dict1. dict2 = dict1 does not make a copy dict2 points to the same object as dict1&lt;br /&gt;
&lt;br /&gt;
;dict1.update(dict2)&lt;br /&gt;
:Add dict2 to dict1. Duplicate keys are overwritten in dict1.&lt;br /&gt;
:Overwriting happens in multilevel dictionary&#039;s too obviously, use something like this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for key in bdict:&lt;br /&gt;
    for key2 in bdict[key]:&lt;br /&gt;
        adict[key][key2] = bdict[key][key2]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;dict1.pop(key,None)&amp;lt;/code&amp;gt;&lt;br /&gt;
:Remove key from dict1, return dict1[key] if successful, None if key does not exist in dict1.&lt;br /&gt;
&lt;br /&gt;
Code example recursively search a key: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
def search_dict(data,skey=None):&lt;br /&gt;
    result = None&lt;br /&gt;
    if skey in data:&lt;br /&gt;
        result = data[skey]&lt;br /&gt;
    else:&lt;br /&gt;
        for key in data:&lt;br /&gt;
            if isinstance(data[key],dict):&lt;br /&gt;
                result = search_dict(data[key],skey)&lt;br /&gt;
    return result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a list of dict values where the key matches a string (List comprehension for dicts)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
[value for key, value in d.items() if &#039;searchstring&#039; in key]&lt;br /&gt;
[value for key, value in d.items() if re.search(pattern,key)]&lt;br /&gt;
[value for key, value in d.items() if key == &#039;keyname&#039;]&lt;br /&gt;
# List of keys that match&lt;br /&gt;
[key for key in d.keys() if key == &#039;keyname&#039;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This very non-intuitive syntax is the same as:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
list1 = list[]&lt;br /&gt;
for key,value in d.items():&lt;br /&gt;
    if &#039;searchstring&#039; in key():&lt;br /&gt;
        list1.append(value)&lt;br /&gt;
return list1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;sorted(dict1.items(), key=lambda x: x[1], reverse=False)&amp;lt;/code&amp;gt;&lt;br /&gt;
:Return a list of tuples (key,value) sorted on value&lt;br /&gt;
;&amp;lt;code&amp;gt;sorted(adict.keys(), key=adict.get)&amp;lt;/code&amp;gt;&lt;br /&gt;
:Return a list of keys sorted on values&lt;br /&gt;
&lt;br /&gt;
;intersectionkeys = dicta.keys() &amp;amp; dictb.keys()&lt;br /&gt;
;intersectionkeys = set(dicta.keys()) &amp;amp; set(dictb.keys())&lt;br /&gt;
:As dictionary keys are a set-like objects in python3 you can make intersctions like.&lt;br /&gt;
:Second format is for python2&lt;br /&gt;
&lt;br /&gt;
==None==&lt;br /&gt;
The &amp;lt;code&amp;gt;None&amp;lt;/code&amp;gt; object is returned e.g. if nothing is found in a re.search. The &amp;lt;code&amp;gt;None&amp;lt;/code&amp;gt; object is &#039;&#039;&#039;not&#039;&#039;&#039; an empty string&lt;br /&gt;
&lt;br /&gt;
==Range==&lt;br /&gt;
Constructor of immutable sequences of integers. Use with list, set, tuple to create the desired object, or for loops.&lt;br /&gt;
&lt;br /&gt;
;range(start,stop,step)&lt;br /&gt;
:Generic format. If you leave out step, step = 1. If only 1 parameter is provided, it is the stop number, start = 0, step = 1 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for i in range (2,5,1):&lt;br /&gt;
    print(i)&lt;br /&gt;
2&lt;br /&gt;
3&lt;br /&gt;
4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;alist = [*range(5)]&lt;br /&gt;
:Unpack the range immediately (that is what * does). alist = [0, 1, 2, 3, 4]&lt;br /&gt;
&lt;br /&gt;
Module [[Python#itertools|itertools]] can be used to loop integers to infinity&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import itertools&lt;br /&gt;
&lt;br /&gt;
for i in itertools.count(step=15):&lt;br /&gt;
    if breakcondition:&lt;br /&gt;
        break&lt;br /&gt;
   print(i)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==DateTime==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
from datetime import datetime&lt;br /&gt;
timestamp = datetime.now().strftime(&amp;quot;%y%m%d-%H%M%S&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Other formats:&lt;br /&gt;
:%s - Seconds since [https://www.epochconverter.com/ epoc] (January 1, 1970 00:00:00)&lt;br /&gt;
:%f - Nanoseconds or Milliseconds depends on what your system supports&lt;br /&gt;
All formats can be found at W3schools[https://www.w3schools.com/python/gloss_python_date_format_codes.asp]&lt;br /&gt;
;datetime.datetime(year, month, day, hour, minute, second).strftime(&#039;%s&#039;)&lt;br /&gt;
:Date to [https://www.epochconverter.com/ epoc]; hour, minute and second are optional.&lt;br /&gt;
&lt;br /&gt;
;Get an unique integer. Time is cheaper than datetime.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import time as t&lt;br /&gt;
# Use UTC-time 1 tick per second&lt;br /&gt;
nonce = int(t.mktime(t.gmtime()))&lt;br /&gt;
# This has greater precision (nanoseconds) but is in local time, not unique when the clock is set back.&lt;br /&gt;
nonce = int(t.time()*10000)&lt;br /&gt;
# I use datetime as that is loaded most time anyhow for other timestamps&lt;br /&gt;
from datetime import datetime&lt;br /&gt;
timestamp = datetime.utcnow().strftime(&amp;quot;%s%f&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Convert datetime strings to a datetime object. The format indicates where the elements can be found (as in unix date formats (&#039;%Y%m%d_%H%M&#039;))&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
from datetime import datetime&lt;br /&gt;
dt = datetime.strptime(&amp;lt;datetimestring&amp;gt;, &amp;lt;format&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
;For unixtime however you can not use strptime with %s&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
dt = datetime.fromtimestamp(&amp;lt;unixtime&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
;To convert to a date object&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
from datetime import datetime&lt;br /&gt;
dateobj = datetime.strptime(&amp;lt;datetimestring&amp;gt;, &amp;lt;format&amp;gt;).date()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;The parser is pretty smart, but it can be confused for day numbers under 13. It accepts e.g. &amp;lt;nowiki&amp;gt;1-jan-1991 12:30&amp;lt;/nowiki&amp;gt; and YYYYMMDD-HHMM format.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
from dateutil.parser import parse&lt;br /&gt;
datetimeobject = parse(datestring)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Calculations (7 days before now)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
from datetime import date&lt;br /&gt;
from datetime import timedelta&lt;br /&gt;
newdate = date.today() - timedelta(days=7)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
timddiff = datetimeobject - datetimeobject2&lt;br /&gt;
print(timediff.days)&lt;br /&gt;
print(timediff.seconds) # max 1 day&lt;br /&gt;
print(timediff.microseconds)  # max 1 second&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Slicing=&lt;br /&gt;
You can address all iterable datatypes partly or in a difference sequence.&lt;br /&gt;
&lt;br /&gt;
;object&amp;lt;nowiki&amp;gt;[b:e:s]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Generic format where b=Begin (counting starts at 0), e=End, s=Stepsize (negative stepsize starts counting at the end)&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
&#039;last element&#039;[-1]&lt;br /&gt;
&#039;All elements except the last&#039;[:-1]&lt;br /&gt;
&#039;All elements in reversed order&#039;[::-1]&lt;br /&gt;
&lt;br /&gt;
&#039;All elements from the second&#039;[1:]&lt;br /&gt;
&#039;Second until 5th element (element 1,2,3 and 4)&#039;[1:5]  &lt;br /&gt;
&#039;Elements in reversed order (element 5,4,3 and 2)&#039;[5:1:-1]&lt;br /&gt;
&#039;Element 1,3 and 5&#039;[1:6:2]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Nginx&amp;diff=1715</id>
		<title>Nginx</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Nginx&amp;diff=1715"/>
		<updated>2026-05-12T19:12:52Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Webdesign]]&lt;br /&gt;
[https://nginx.org/ Nginx] is a webserver working very well on small systems &lt;br /&gt;
&lt;br /&gt;
;nginx -t&lt;br /&gt;
:Test configuration&lt;br /&gt;
&lt;br /&gt;
;nginx -V&lt;br /&gt;
:Print version, compiler version and configured parameters&lt;br /&gt;
&lt;br /&gt;
=PHP support=&lt;br /&gt;
To enable php suppport in ./sites-available/xxx put this&lt;br /&gt;
  location ~ \.php$ {&lt;br /&gt;
        #NOTE: You should have &amp;quot;cgi.fix_pathinfo = 0;&amp;quot; in php.ini&lt;br /&gt;
        include snippets/fastcgi-php.conf;&lt;br /&gt;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;&lt;br /&gt;
        fastcgi_intercept_errors on;&lt;br /&gt;
        fastcgi_param HTTPS on;&lt;br /&gt;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;&lt;br /&gt;
        fastcgi_param SCRIPT_NAME     $fastcgi_script_name;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=Tips=&lt;br /&gt;
# Put al customizations in your site-definitions (in ./sites-available) or in .conf files in the ./conf.d subdir. This make it easier to migrate your configuration to another server.&lt;br /&gt;
&lt;br /&gt;
==Force clients to use https (HSTS)==&lt;br /&gt;
Add to ./conf.d/myconfig.conf&lt;br /&gt;
:&amp;lt;code&amp;gt;add_header Strict-Transport-Security &amp;quot;max-age=31536000; includeSubDomains&amp;quot; always;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe browser history for the HSTS websites if HSTS settings were disabled but the max-age has not passed yet for your browser (31536000 seconds is 1 year).&lt;br /&gt;
&lt;br /&gt;
==Other recommenations==&lt;br /&gt;
In the http section (./conf.d/myconfig.conf) put&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# For security hide the server version&lt;br /&gt;
server_tokens off;&lt;br /&gt;
ssl_protocols TLSv1.2 TLSv1.3; #  Dropping SSL, TLSv1 and TLSv1.1&lt;br /&gt;
&lt;br /&gt;
# For performance&lt;br /&gt;
client_body_timeout 12;&lt;br /&gt;
client_header_timeout 12;&lt;br /&gt;
keepalive_timeout 15;&lt;br /&gt;
send_timeout 10;&lt;br /&gt;
&lt;br /&gt;
client_body_buffer_size 10K;&lt;br /&gt;
client_header_buffer_size 1k;&lt;br /&gt;
client_max_body_size 8m;&lt;br /&gt;
large_client_header_buffers 4 4k;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Block unwanted agents==&lt;br /&gt;
To block specific user agents, like GPTbot that can be really aggressive.&lt;br /&gt;
&lt;br /&gt;
In the http section  (./conf.d/myconfig.conf) add&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
map $http_user_agent $blocked_user_agent {&lt;br /&gt;
 default 0;&lt;br /&gt;
 ~*meta-externalagent 1;&lt;br /&gt;
 ~*GPTBot 1;&lt;br /&gt;
 ~*Amazonbot 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then in each server that needs the blocking add&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
 if ($blocked_user_agent) {&lt;br /&gt;
  return 403;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Issues and fixes=&lt;br /&gt;
;could not build server_names_hash, you should increase server_names_hash_bucket_size&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; 32&lt;br /&gt;
:Due to many servernames in a server definition. In a .conf file in /etc/nginx/conf.d put a line like&lt;br /&gt;
:&amp;lt;code&amp;gt;server_names_hash_bucket_size  64;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Using listen &amp;lt;nowiki&amp;gt;[::]:80&amp;lt;/nowiki&amp;gt; ipv6only=on;&lt;br /&gt;
:The ipv6only parameter can be set only once. If you have several virtual host you should not use it.&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Python:Files&amp;diff=1714</id>
		<title>Python:Files</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Python:Files&amp;diff=1714"/>
		<updated>2026-05-03T10:16:12Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Filehandling and metadata */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
&lt;br /&gt;
=Basics=&lt;br /&gt;
;basename = path.split(&#039;/&#039;)[-1]&lt;br /&gt;
:Get the filename from a path&lt;br /&gt;
;dirname = re.sub(&#039;/[^/]+/$&#039;, &#039;/&#039;, path)&lt;br /&gt;
:Get the directory name from a path&lt;br /&gt;
;glob.glob(filespec)&lt;br /&gt;
:Return a [[Python:DataTypes#list|list]] of files matching &#039;filespec&#039;.&lt;br /&gt;
Code example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import glob&lt;br /&gt;
files = glob.glob(filespec)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;os.path.isfile(filename)&lt;br /&gt;
:Boolean for file existence &lt;br /&gt;
&lt;br /&gt;
;fh = open (filename,&amp;quot;r&amp;quot;)&lt;br /&gt;
:open filename for read and return the filehandle fh. Use w for write, a for append.&lt;br /&gt;
;fh.write(line)&lt;br /&gt;
:Write line to file opened on filehandle f1.&lt;br /&gt;
:NOTE: you have to make sure the line-end is in the line too.&lt;br /&gt;
;fh.close()&lt;br /&gt;
:Close the file for filehandle fh.&lt;br /&gt;
;sys.stdout.write(&amp;lt;string&amp;gt;)&lt;br /&gt;
:Write to standard output&lt;br /&gt;
&lt;br /&gt;
Code example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
if os.path.isfile(filename):&lt;br /&gt;
    f1 =  open (filename,&amp;quot;r&amp;quot;)&lt;br /&gt;
    for line in f1:&lt;br /&gt;
        &amp;lt;codeblock&amp;gt;&lt;br /&gt;
    f1.close()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Or &#039;Easier to Ask for Forgiveness than Permission&#039; (EAFP):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
try:&lt;br /&gt;
    fh = open (filename,&amp;quot;r&amp;quot;)&lt;br /&gt;
except:&lt;br /&gt;
    print(&#039;ERROR: {} cannot be opened&#039;.format(filename))&lt;br /&gt;
    logging.error(&#039;ERROR: {} cannot be opened&#039;.format(filename))&lt;br /&gt;
else:&lt;br /&gt;
    &amp;lt;other code&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;with open (filename,&amp;quot;r&amp;quot;) as file&lt;br /&gt;
:Open filename for read and close at the end of the loop&lt;br /&gt;
&lt;br /&gt;
Code example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
with open (filename,&amp;quot;r&amp;quot;) as file:&lt;br /&gt;
    for line in file:&lt;br /&gt;
        &amp;lt;codeblock&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Other ways of reading==&lt;br /&gt;
;f1.read(size)&lt;br /&gt;
:Return &#039;size&#039; bytes from the file as [[Python:Strings|string]]. If size is omitted or 0 the entire file is returned.&lt;br /&gt;
&lt;br /&gt;
;f1.readlines()&lt;br /&gt;
;list(f1)&lt;br /&gt;
:Return all lines from file as [[Python:DataTypes#list|list]].&lt;br /&gt;
&lt;br /&gt;
;fileinput.input()&lt;br /&gt;
:Read through all files specified on the commandline.&lt;br /&gt;
:If there are no files on the commandline read standard input&lt;br /&gt;
:You can pass other arguments too but you have to remove them from sys.argv before you start reading fileinput&lt;br /&gt;
;fileinput.filename()&lt;br /&gt;
:The name of the we are working on&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import fileinput&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
otherarg = sys.argv.pop()  # other argument is the last on the commandline&lt;br /&gt;
&lt;br /&gt;
for line in fileinput.input():&lt;br /&gt;
    &amp;lt;codeblock&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Filehandling and metadata=&lt;br /&gt;
;os.unlink(filename)&lt;br /&gt;
:Remove file or symbolic link&lt;br /&gt;
&lt;br /&gt;
;shutil.copy(source, destination)&lt;br /&gt;
:Copy file from source to destination, destination can be both a file or a directory&lt;br /&gt;
;shutil.copyfile(source, destination)&lt;br /&gt;
:Copy file from source to destination, both as full path&lt;br /&gt;
;shutil.move(source, destination)&lt;br /&gt;
:Move file from source to destination, destination can be both a file or a directory&lt;br /&gt;
&lt;br /&gt;
;statinfo = os.stat(filename)&lt;br /&gt;
:Get file metadata like:&lt;br /&gt;
:&amp;lt;code&amp;gt;posix.stat_result(st_mode=33204, st_ino=3069488, st_dev=21L, st_nlink=1, st_uid=999, st_gid=999, st_size=37078, st_atime=4939053720, st_mtime=3939053719, st_ctime=2939053719)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;statinfo.st_size&amp;lt;/code&amp;gt; has the filesize in bytes.&lt;br /&gt;
&lt;br /&gt;
;Walking a directory tree and fetching file information&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
def do_dir(directory):&lt;br /&gt;
    with os.scandir(directory) as it:&lt;br /&gt;
        for entry in it:&lt;br /&gt;
            if not entry.name.startswith(&#039;.&#039;):&lt;br /&gt;
                if entry.is_file():&lt;br /&gt;
                    filepath = entry.path&lt;br /&gt;
                    inode = entry.inode()&lt;br /&gt;
                    ctime = entry.stat().st_ctime # see statinfo for other data&lt;br /&gt;
                elif entry.is_dir():&lt;br /&gt;
                    do_dir(entry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Archives=&lt;br /&gt;
&lt;br /&gt;
==Read an archive==&lt;br /&gt;
Read a file in a tar archive into a list of lines regardless the compression used (not zip).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import tarfile&lt;br /&gt;
tar = tarfile.open(&amp;lt;tarfile&amp;gt;,&#039;r&#039;)&lt;br /&gt;
for member in tar.getmembers():&lt;br /&gt;
   print(member.name)&lt;br /&gt;
   filelist = tar.extractfile(member)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Copy files from 1 archive to another==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import tarfile&lt;br /&gt;
&lt;br /&gt;
filenames = {&amp;lt;(part of) filename to copy&amp;gt;, &amp;lt;(part of) filename to copy&amp;gt;}&lt;br /&gt;
oldtar = tarfile.open(&#039;tar1.tar&#039;,&amp;quot;r&amp;quot;)&lt;br /&gt;
newtar = tarfile.open(&#039;tar2.tar&#039;,&amp;quot;w&amp;quot;)&lt;br /&gt;
for member in oldtar.getmembers():&lt;br /&gt;
    done = 0&lt;br /&gt;
    for filename in filenames:&lt;br /&gt;
        if filename in member.name:&lt;br /&gt;
            try:&lt;br /&gt;
                newtar.addfile(member, oldtar.extractfile(member.name))&lt;br /&gt;
                done = 1&lt;br /&gt;
            except OSError as exception:&lt;br /&gt;
                print(f&amp;quot;{member.name} has error {exception}&amp;quot;)&lt;br /&gt;
                done = 2&lt;br /&gt;
&lt;br /&gt;
    if done == 1:&lt;br /&gt;
        print(f&amp;quot;{member.name} Added&amp;quot;)&lt;br /&gt;
    elif done == 0:&lt;br /&gt;
        print(f&amp;quot;{member.name} Skipped&amp;quot;)&lt;br /&gt;
newtar.close()&lt;br /&gt;
oldtar.close()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Zip files=&lt;br /&gt;
Check [https://pymotw.com/2/zipfile/ this page].&lt;br /&gt;
&lt;br /&gt;
==Read a zip-file==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import zipfile&lt;br /&gt;
&lt;br /&gt;
z = zipfile.ZipFile(zipile)&lt;br /&gt;
for file in z.namelist():&lt;br /&gt;
    print(file)&lt;br /&gt;
&lt;br /&gt;
data = z.read(&amp;lt;zipped-filename&amp;gt;)    &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Create a zip-file==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import zipfile,zlib&lt;br /&gt;
&lt;br /&gt;
zipname = filename+&#039;.zip&#039;&lt;br /&gt;
zfile = zipfile.ZipFile(zipname, mode=&#039;w&#039;)&lt;br /&gt;
if zfile:&lt;br /&gt;
    zfile.write(filename, compress_type=zipfile.ZIP_DEFLATED)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=[[XLS|Excel files]]=&lt;br /&gt;
==Reading==&lt;br /&gt;
Excel-files is basically a zip-file with some specific content and they can be handled like that. [[Pandas#Reading_Data]] has a build in ability to read excel into a dataframe. Whenever possible use that, else check [[XLS]].&lt;br /&gt;
&lt;br /&gt;
==Writing==&lt;br /&gt;
Below writes a list of lists to excel&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import xlsxwriter&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    workbook = xlsxwriter.Workbook(excelfilename, {&#039;nan_inf_to_errors&#039;: True})&lt;br /&gt;
&lt;br /&gt;
    header = [&#039;Column1&#039;, &#039;Column2&#039;]&lt;br /&gt;
&lt;br /&gt;
    writeworkbook(workbook, worksheetname, alist, header)&lt;br /&gt;
&lt;br /&gt;
    workbook.close()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def writeworkbook(workbook, worksheetname, outlist, header):&lt;br /&gt;
    worksheet = workbook.add_worksheet(worksheetname)&lt;br /&gt;
    columnwidths = {}&lt;br /&gt;
&lt;br /&gt;
    columnno = 0&lt;br /&gt;
    for column in header:&lt;br /&gt;
        columnwidths[columnno] = len(column)&lt;br /&gt;
        columnno += 1&lt;br /&gt;
&lt;br /&gt;
    for row in outlist:&lt;br /&gt;
        columnno = 0&lt;br /&gt;
        for column in row:&lt;br /&gt;
            try:&lt;br /&gt;
                columnwidths[columnno] = max(columnwidths[columnno], len(str(column)))&lt;br /&gt;
            except KeyError:&lt;br /&gt;
                # The rows may have variable length&lt;br /&gt;
                columnwidths[columnno] = len(str(column))&lt;br /&gt;
            columnno += 1&lt;br /&gt;
&lt;br /&gt;
    for columnno in columnwidths:&lt;br /&gt;
        worksheet.set_column(columnno, columnno, columnwidths[columnno] + columnwidths[columnno] * 0.1)&lt;br /&gt;
&lt;br /&gt;
    wsindex = 0&lt;br /&gt;
    worksheet.write_row(wsindex, 0, header)&lt;br /&gt;
    for row in outlist:&lt;br /&gt;
        columnno = 0&lt;br /&gt;
        for column in row:&lt;br /&gt;
            if type(column) in (list, tuple, dict):&lt;br /&gt;
                row[columnno] = str(column)&lt;br /&gt;
            columnno += 1&lt;br /&gt;
        wsindex += 1&lt;br /&gt;
        worksheet.write_row(wsindex, 0, row)&lt;br /&gt;
&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
main()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Read from standard input and keyboard=&lt;br /&gt;
&lt;br /&gt;
Read from standard input&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
for line in sys.stdin:&lt;br /&gt;
    &amp;lt;codeblock&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prompt and read from keyboard into a&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
a = input(&amp;quot;Prompt: &amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In python2&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
a = raw_input(&amp;quot;Prompt: &amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Read a csv=&lt;br /&gt;
This code read all files matching the specification and return the content as a list of dicts that have the fieldnames as keys. Fieldnames must be on the first line of the file an must be unique.&lt;br /&gt;
NOTE: This code cannot handle value&#039;s that contain the separator. The line will be split on all separator occurrences. Use [[Pandas]] or a specific csv-reader module if you need this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
def csv2dict(filespec, separator=&#039;,&#039;):&lt;br /&gt;
    &#039;&#039;&#039;Convert a csv-file to a list of dicts&#039;&#039;&#039;&lt;br /&gt;
    outfile = []&lt;br /&gt;
    filedir = glob.glob(filespec)&lt;br /&gt;
    for filename in filedir:&lt;br /&gt;
        try:&lt;br /&gt;
            fh = open(filename, &amp;quot;r&amp;quot;)&lt;br /&gt;
        except:&lt;br /&gt;
            print(&#039;{} cannot be opened&#039;.format(filename))&lt;br /&gt;
        else:&lt;br /&gt;
            filelist = [line.strip().split(separator) for line in fh]&lt;br /&gt;
            fh.close()&lt;br /&gt;
            header = filelist.pop(0)&lt;br /&gt;
            fieldnames = set(header)&lt;br /&gt;
            if len(header) != len(fieldnames):&lt;br /&gt;
                print(&#039;ERROR: Fieldnames in {} are not unique&#039;.format(filename))&lt;br /&gt;
            else:&lt;br /&gt;
                numfields = len(header)&lt;br /&gt;
                linecount = 0&lt;br /&gt;
                for line in filelist:&lt;br /&gt;
                    linecount += 1&lt;br /&gt;
                    linedict = {}&lt;br /&gt;
                    count = 0&lt;br /&gt;
                    for field in line:&lt;br /&gt;
                        linedict[header[count]] = field&lt;br /&gt;
                        count += 1&lt;br /&gt;
                        if count &amp;gt; numfields - 1:&lt;br /&gt;
                            break&lt;br /&gt;
                    if count != numfields:&lt;br /&gt;
                        print(&#039;ERROR: invalid number of fields in line &#039; + str(linecount))&lt;br /&gt;
                    outfile.append(linedict)  &lt;br /&gt;
    return (outfile)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Read xml=&lt;br /&gt;
Module and code examples [[Python:XML]]&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Python:Functions&amp;diff=1713</id>
		<title>Python:Functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Python:Functions&amp;diff=1713"/>
		<updated>2026-04-28T09:50:39Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Build in functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Python]]&lt;br /&gt;
&lt;br /&gt;
;sys._getframe(  ).f_code.co_name&lt;br /&gt;
:Return name of current function&lt;br /&gt;
&lt;br /&gt;
;eval(functionnameasstring)()&lt;br /&gt;
:Convert a function name as string to a function call&lt;br /&gt;
:WARNING: Make sure you have control over the string provided, you may call anything this way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Passing arguments=&lt;br /&gt;
&lt;br /&gt;
If an argument is a mutable object it is passed by reference. So when you modify the object in the function, the change there in the outside world too.&lt;br /&gt;
Immutable objects are passed by value. You cannot change the object, you have to return the new one.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;python&#039;&amp;gt;&lt;br /&gt;
def main():&lt;br /&gt;
    aInt = 1&lt;br /&gt;
    aList = [&#039;a&#039;]&lt;br /&gt;
    bInt = function(aInt, aList)&lt;br /&gt;
    print(aInt, bInt, aList)  # This will print:  &amp;quot;1 6 [&#039;a&#039;, &#039;something&#039;]&amp;quot;&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def function (a, b):&lt;br /&gt;
    # a is a new integer object&lt;br /&gt;
    # b is a reference to the aList object.&lt;br /&gt;
    a += 5&lt;br /&gt;
    b.append(&#039;something&#039;)&lt;br /&gt;
    return a&lt;br /&gt;
&lt;br /&gt;
main()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Arguments are positional but can be passed by keyword too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;python&#039;&amp;gt;&lt;br /&gt;
def main():&lt;br /&gt;
    outcome = function(par1,par2)&lt;br /&gt;
    function(par2 = &amp;lt;value&amp;gt;, par1 = &amp;lt;value&amp;gt;)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def function (inpar1, inpar2 = &amp;lt;defaultvalue&amp;gt;):&lt;br /&gt;
    codeblock&lt;br /&gt;
    return result&lt;br /&gt;
&lt;br /&gt;
main()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;def function (*args,**kwargs):&lt;br /&gt;
:Take any number of positional arguments and put them in the [[Python:DataTypes#Tuple|tuple]] args&lt;br /&gt;
:Take any number of keyword arguments and put them in the [[Python:DataTypes#Dictionary_or_dict|dict]] kwargs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;You can pass a function-name as parameter&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;python&#039;&amp;gt;&lt;br /&gt;
def main():&lt;br /&gt;
    outcome = function1(function2,inpar2 = &amp;lt;value&amp;gt;)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def function1 (functiontocall, inpar2 = &amp;lt;defaultvalue&amp;gt;):&lt;br /&gt;
    result = functiontocall(inpar2)&lt;br /&gt;
    return result&lt;br /&gt;
&lt;br /&gt;
def function2 (inpar):&lt;br /&gt;
    codeblock&lt;br /&gt;
    return result&lt;br /&gt;
&lt;br /&gt;
main()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Anonymous functions(lambda)=&lt;br /&gt;
lambda defines an anonymous function.&lt;br /&gt;
&lt;br /&gt;
Can be used in may places.&lt;br /&gt;
&lt;br /&gt;
Here the dictionary has lambda functions as value. adict[&#039;a&#039;](&amp;lt;value&amp;gt;) calls the function and returns True of False.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
adict = {&lt;br /&gt;
        &#039;a&#039;: lambda a: 0 &amp;lt; a &amp;lt; 10,&lt;br /&gt;
        &#039;b&#039;: lambda a: 11 &amp;lt; a &amp;lt; 20,&lt;br /&gt;
        &#039;c&#039;: lambda a: 21 &amp;lt; a &amp;lt; 30,&lt;br /&gt;
        &#039;d&#039;: lambda a: 31 &amp;lt; a &amp;lt; 40&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
adict[&#039;a&#039;](5)  # True&lt;br /&gt;
adict[&#039;a&#039;](15) # False&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Build in functions=&lt;br /&gt;
&lt;br /&gt;
List of all build in functions [https://docs.python.org/3/library/functions.html]&lt;br /&gt;
&lt;br /&gt;
;len(obj1)&lt;br /&gt;
:Return the number of elements in obj1 (string, list, tuple, set)&lt;br /&gt;
&lt;br /&gt;
;max(obj1)&lt;br /&gt;
:Return the largest item in obj1&lt;br /&gt;
&lt;br /&gt;
;min(obj1)&lt;br /&gt;
Return the smallest item in obj1&lt;br /&gt;
&lt;br /&gt;
;round(x,y)&lt;br /&gt;
:Round x to y decimals, y defaults to 0&lt;br /&gt;
;BEWARE; In python 3x rounding does not work &#039;As taught in school&#039;[https://stackoverflow.com/questions/10825926/python-3-x-rounding-behavior] but rounds half to even[https://en.wikipedia.org/wiki/Rounding#Round_half_to_even].&lt;br /&gt;
Use this to implement &#039;As taught in school&#039; by overwriting the round() function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
def round(valuein, digits=None):&lt;br /&gt;
    import decimal&lt;br /&gt;
    value = str(valuein)&lt;br /&gt;
    if digits is None:&lt;br /&gt;
        try:&lt;br /&gt;
            digits = len(value.split(&#039;.&#039;)[1])&lt;br /&gt;
        except IndexError:&lt;br /&gt;
            digits = 0&lt;br /&gt;
    formatstring = &#039;1.&#039; + &#039;1&#039; * digits&lt;br /&gt;
    try:&lt;br /&gt;
        result = decimal.Decimal(value).quantize(decimal.Decimal(formatstring), rounding=decimal.ROUND_HALF_UP)&lt;br /&gt;
    except decimal.InvalidOperation:&lt;br /&gt;
        result = valuein&lt;br /&gt;
    return result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;input([prompt])&lt;br /&gt;
:Read and return input from standard input. Display &#039;prompt&#039; first when provided.&lt;br /&gt;
&lt;br /&gt;
;int(string[,base=x)])&lt;br /&gt;
:Convert str to an integer. Base = 2 converts bit-string presentation (&#039;010101&#039;).&lt;br /&gt;
&lt;br /&gt;
;str(object)&lt;br /&gt;
;repr(object)&lt;br /&gt;
:Return a string representation of an object. str for the informal representation (just make it printable), repr for the formal representation (more formating??)&lt;br /&gt;
&lt;br /&gt;
=Boolean functions=&lt;br /&gt;
Functions that just return True or False&lt;br /&gt;
;isinsantce(var, type)&lt;br /&gt;
:If a variable has the wanted type (list,set,int,str,dict)&lt;br /&gt;
;isfile(filename)&lt;br /&gt;
:If a file exists&lt;br /&gt;
&lt;br /&gt;
;any(&amp;lt;object&amp;gt;)&lt;br /&gt;
:If any of the elements is True (any iterateble will do)&lt;br /&gt;
;any(x in alist for x in aset)&lt;br /&gt;
:If any of the elements of list are in set&lt;br /&gt;
;all(&amp;lt;object&amp;gt;)&lt;br /&gt;
:True if all elements of &amp;lt;object&amp;gt; are true (have a value)&lt;br /&gt;
&lt;br /&gt;
=Resursive functions=&lt;br /&gt;
In resursive functions you should update the objects to return, not create new ones. Use augmented assignment (+=).&lt;br /&gt;
&lt;br /&gt;
=Other often used functions=&lt;br /&gt;
;Sleep function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
time.sleep(&amp;lt;sec&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Html&amp;diff=1712</id>
		<title>Html</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Html&amp;diff=1712"/>
		<updated>2026-04-26T13:18:08Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Webdesign]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h1&amp;gt;Redirect&amp;lt;/h1&amp;gt;&lt;br /&gt;
;&amp;lt;meta http-equiv=&amp;quot;Refresh&amp;quot; content=&amp;quot;0; url=&#039;https://wiki.deridder.it&#039;&amp;quot; /&amp;gt;&lt;br /&gt;
:Immediate redirect to this wiki.&lt;br /&gt;
&amp;lt;h1&amp;gt;Forms&amp;lt;/h1&amp;gt;&lt;br /&gt;
;&amp;lt;form action=&amp;quot;&#039;.htmlspecialchars($_SERVER[&#039;REQUEST_URI&#039;]).&#039;&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;&lt;br /&gt;
:Start a form&lt;br /&gt;
:;action&lt;br /&gt;
::Page to load when submit is done. This loads the same page as making the request&lt;br /&gt;
:;method&lt;br /&gt;
::Submit method (GET or POST)&lt;br /&gt;
&amp;lt;h2&amp;gt;Input boxes&amp;lt;/h2&amp;gt;&lt;br /&gt;
;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;varname&amp;quot; value=&amp;quot;xxx&amp;quot; size=20 readonly disabled&amp;gt;&lt;br /&gt;
:An input box to use in forms&lt;br /&gt;
:;name&lt;br /&gt;
::Name of the key in $_POST returned&lt;br /&gt;
:;value&lt;br /&gt;
::Default value&lt;br /&gt;
:;readonly&lt;br /&gt;
::No input allowed&lt;br /&gt;
:;disabled&lt;br /&gt;
::Value will not be in $_POST&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Pandas&amp;diff=1711</id>
		<title>Pandas</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Pandas&amp;diff=1711"/>
		<updated>2026-03-24T15:44:18Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Use data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
Check the [https://pandas.pydata.org/pandas-docs/stable/10min.html 10 minutes to Pandas] too or [https://pythonexamples.org/pandas-examples/ pythonexamples].&lt;br /&gt;
;import pandas as pd&lt;br /&gt;
:Import the library, we assume this was done on this page&lt;br /&gt;
&lt;br /&gt;
=DataFrame=&lt;br /&gt;
Object for tabular data (that is e.g. obtained by read_html).&lt;br /&gt;
&lt;br /&gt;
Each column is a [[Pandas#Series]]&lt;br /&gt;
&lt;br /&gt;
;df = &amp;lt;nowiki&amp;gt;pd.DataFrame([{col1: 1,col2: 2},{col1: 1,col2: 2}])&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Create a simple dataframe having a range index, 2 rows and 2 columns&lt;br /&gt;
;df = &amp;lt;nowiki&amp;gt;pd.DataFrame([{col1: 1,col2: 2},{col1: 1,col2: 2}],[row1,row2])&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Create a dataframe having a list index. The size of index must match the number of rows.&lt;br /&gt;
&lt;br /&gt;
Single columns can be addressed by there name like in &amp;lt;code&amp;gt;df.columnname.unique()&amp;lt;/code&amp;gt; to get unique values in a column.&lt;br /&gt;
&lt;br /&gt;
Single or multiple columns can be addressed as list like in &amp;lt;code&amp;gt;df.set_index([column1,column2])&amp;lt;/code&amp;gt; to set an index over 2 columns.&lt;br /&gt;
&lt;br /&gt;
;df.copy&lt;br /&gt;
:Make a copy of df ( = will point to the same dataframe, like with [[Python:DataTypes#Dictionary or dict|dictionaries]])&lt;br /&gt;
&lt;br /&gt;
;df.join(table2)&lt;br /&gt;
:Like SQL-join merge on index&lt;br /&gt;
;df.merge(table2,on=&amp;lt;column&amp;gt;)&lt;br /&gt;
:Like SQL-join on  &amp;lt;column&amp;gt; = df.index&lt;br /&gt;
;dfall.merge(table2, on = &amp;lt;column&amp;gt;, how=&#039;left&#039;, indicator=True)&lt;br /&gt;
:Return df joined with table2. Add column _merge with value &#039;left_only&#039; to records that only exist in df.&lt;br /&gt;
;df = dfall[dfall[&#039;_merge&#039;] == &#039;left_only&#039;]&lt;br /&gt;
:Return dataframe with all records not in table2&lt;br /&gt;
;df = pd.concat(dflist)&lt;br /&gt;
:Concatenate all dataframes in dflist&lt;br /&gt;
&lt;br /&gt;
==Information==&lt;br /&gt;
&lt;br /&gt;
;df.info()&lt;br /&gt;
:Information on dataframe (Index, size, datatypes per column)&lt;br /&gt;
;df.size&lt;br /&gt;
:Return the number of cells in a dataframe&lt;br /&gt;
;df.shape&lt;br /&gt;
:Return the number of rows and columns in a dataframe as [[Python:DataTypes#Tuple|tuple]].&lt;br /&gt;
;df.describe()&lt;br /&gt;
:Return various attributes for numeric columns in the dataframe. This may indicate if there are outlyers.&lt;br /&gt;
;df.head(x)&lt;br /&gt;
;df.tail(x)&lt;br /&gt;
:Return first/last x data rows of df (5 is the default value for x).&lt;br /&gt;
&lt;br /&gt;
;df.index&lt;br /&gt;
:Return the table index (class = pandas.core.indexes.base.Index)&lt;br /&gt;
&lt;br /&gt;
;df.columns&lt;br /&gt;
:Return the column headers (class = pandas.core.indexes.base.Index)&lt;br /&gt;
;df.dtypes&lt;br /&gt;
:Return the data-type of the columns&lt;br /&gt;
;df.columnname.dtype&lt;br /&gt;
:Return the data-type of column columnname&lt;br /&gt;
&lt;br /&gt;
==Modify== &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.rename(columns={oldname:newname}, inplace=True)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Redefine the column headers (modifies the dataframe itself, nothing is returned)&lt;br /&gt;
&lt;br /&gt;
;df.set_index([&#039;col1&#039;,&#039;col2&#039;])&lt;br /&gt;
:Return the dataframe with a new index composed of 2 columns&lt;br /&gt;
;df.reset_index()&lt;br /&gt;
:Return the dataframe with a default index (range)&lt;br /&gt;
;df.sort_index(ascending=False)&lt;br /&gt;
:Sort the dataframe on the index. &#039;True&#039; is the default if &#039;acsending&#039; is not supplied.&lt;br /&gt;
;df.index = df.index.map(str)&lt;br /&gt;
:For a data-type on the index&lt;br /&gt;
&lt;br /&gt;
;df.drop(index)&lt;br /&gt;
;df.drop([indexes])&lt;br /&gt;
;df.drop(range(0,3))&lt;br /&gt;
:Remove row(s) from a dataframe.&lt;br /&gt;
;df.drop(columns=[listofcolumnstodrop]&lt;br /&gt;
:Remove columns from a dataframe.&lt;br /&gt;
&lt;br /&gt;
;df.dropna(thresh=x)&lt;br /&gt;
:Return only rows that have at least x columns with a none-NA  value. If x &amp;lt; 2 the threshold can be dropped.&lt;br /&gt;
&lt;br /&gt;
;df.loc[&amp;lt;index&amp;gt;,[&#039;field1&#039;,&#039;field2&#039;]] = [value1,value2]&lt;br /&gt;
:Change values for index &amp;lt;index&amp;gt; in a dataframe&lt;br /&gt;
;df.fillna(&amp;lt;value&amp;gt;)&lt;br /&gt;
;df[[&amp;lt;column1&amp;gt;,&amp;lt;column2&amp;gt;]] = df[[&amp;lt;column1&amp;gt;,&amp;lt;column2&amp;gt;].fillna(&amp;lt;value&amp;gt;)&lt;br /&gt;
:Return dataframe with all NA-values (in the selected columns) replaced by &amp;lt;value&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;table.agg(newname=(&#039;columname&#039;, np.max))&lt;br /&gt;
:Add newname to df with the max of columnname. This named aggregations is only supported from version v0.25 &lt;br /&gt;
&lt;br /&gt;
;df.transform(&amp;lt;function&amp;gt;)&lt;br /&gt;
:Apply a function to an existing column or the entire dataframe.&lt;br /&gt;
&lt;br /&gt;
;df.assign(newcolumn = &amp;lt;expression&amp;gt;)&lt;br /&gt;
:Add column newcolumn to the dataframe&lt;br /&gt;
:Expression can be a function like &amp;quot;lambda d: d[&#039;column&#039;] * &amp;lt;something&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;df.apply(&amp;lt;function&amp;gt;)&lt;br /&gt;
:Apply a function to the dataframe. By default every element of the table.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.apply(lambda x: &amp;lt;function&amp;gt;(x) if x.name in [columnname] else x)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Apply a function to specified colums &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[columname] = df[columname].apply(lambda x: &amp;lt;function&amp;gt;(x))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Change a column in the dataframe by applying &amp;lt;function&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;df.replace(&amp;lt;pattern&amp;gt;,&amp;lt;newvalue&amp;gt;,regex=True)&lt;br /&gt;
:Replace &amp;lt;pattern&amp;gt; with &amp;lt;newvalue&amp;gt; in the entire dataframe&lt;br /&gt;
&lt;br /&gt;
;df[columna].mask(df[columna] == origvalue , newvalue, inplace=True)&lt;br /&gt;
:Change all cells in columa that have origvalue into newvalue (inplace, so in the dataframe itself).&lt;br /&gt;
&lt;br /&gt;
==Select data==&lt;br /&gt;
Use .loc, else colomn-names will be considered too (if I understand this[https://stackoverflow.com/questions/38886080/python-pandas-series-why-use-loc] correctly).&lt;br /&gt;
&lt;br /&gt;
;WARNING!!&lt;br /&gt;
:at least with .loc if only 1 item is found is it returned as string(/float?) else as dataframe/series.&lt;br /&gt;
&lt;br /&gt;
;df.[[iloc]][&amp;lt;slice&amp;gt;]&lt;br /&gt;
:Return the rows indicated by &amp;lt;slice&amp;gt; as pandas.Series &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.iloc[:,0:3]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[[col0,col1,col2]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Return 3 columns from the dataframe&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;columns&#039;)&lt;br /&gt;
:Return all columns which name matches &amp;lt;regexp&amp;gt;. (axis=1)&lt;br /&gt;
&lt;br /&gt;
;df.loc[&amp;lt;index&amp;gt;]&lt;br /&gt;
:Select the row(s) with index &amp;lt;index&amp;gt;&lt;br /&gt;
;df.loc[&amp;lt;indexname&amp;gt;].&amp;lt;columnname&amp;gt;&lt;br /&gt;
;df.loc[&amp;lt;indexname&amp;gt;].[&amp;lt;columnname&amp;gt;]&lt;br /&gt;
:Select only 1 column from a row as pandas series. You may convert that to a list or set immediately by using &amp;lt;code&amp;gt;list(df.loc[&amp;lt;indexname&amp;gt;].&amp;lt;columnname&amp;gt;)&amp;lt;/code&amp;gt;&lt;br /&gt;
;df.loc[0][0]&lt;br /&gt;
:Select a cell in a dataframe with no index or header&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[lambda d: d[column1] == &amp;lt;value&amp;gt; ]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[df[column1] == &amp;lt;value&amp;gt; ]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[df[column1].notnull()]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Select all rows where column1 equals &amp;lt;value&amp;gt; or do not have a null-value.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[(df[column1] == &amp;lt;value&amp;gt;) | (df[colomn1] == &amp;lt;value2&amp;gt;)]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Combine conditions with &#039;|&#039; (or) or &#039;&amp;amp;&#039; (and). Use () on each condition!!&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.loc[datetime.today()-pd.Timedelta(days=7) : datetime.today()]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Select all rows where the (datetime)-index is between 7 days ago and today.&lt;br /&gt;
:NOTE!! The index must be sorted in ascending order[https://stackoverflow.com/q/67298584/2213323]. &lt;br /&gt;
;df.last(&#039;7D&#039;)&lt;br /&gt;
:Select the last 7 days in the dataframe. For this als the datetime index must be sorted in ascending order&lt;br /&gt;
&lt;br /&gt;
See also the [https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.contains.html#pandas.Series.str.contains pandas series pages]  &lt;br /&gt;
;df[df[&#039;fieldname&#039;].str.contains(&#039;regexp&#039;,regex=True)]&lt;br /&gt;
:Select all rows in df where fieldname contens matches regexp. The field must have a string datetype. If you are looking for a simple string you can leave out the regex=True part.&lt;br /&gt;
;df[df[&#039;fieldname&#039;].gt(value)]&lt;br /&gt;
:Select all rows in df where fieldname is bigger than value. The field must have a numeric datetype&lt;br /&gt;
&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;)&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;).&amp;lt;columnname&amp;gt;&lt;br /&gt;
;df.filter(regex=&amp;lt;regex&amp;gt;,axis=&#039;index&#039;).index&lt;br /&gt;
:Return all rows for which in index matches &amp;lt;regexp&amp;gt; or get only the column of the matched indexes. (axis=0 ) or the indexname(s).&lt;br /&gt;
:The .index returns the matching indexes as a [[Python:DataTypes#List|list]].&lt;br /&gt;
&lt;br /&gt;
;df.sort_values(&amp;lt;columnname&amp;gt;)&lt;br /&gt;
;df.sort_values([&amp;lt;column1&amp;gt;,&amp;lt;colunm2&amp;gt;],ascending=(True,False))&lt;br /&gt;
:Return the dataframe sorted on the values in the columns. The second form sorts on column1 first and then on column2, column1 ascending, column2 descending&lt;br /&gt;
;df.groupby([column1,column2])&lt;br /&gt;
:Return a DataFrameGroupBy object, this is not a dataframe&lt;br /&gt;
;df.collname.unique()&lt;br /&gt;
:Return a [[Numpy]] array with all distinct values in column &#039;collname&#039;&lt;br /&gt;
&lt;br /&gt;
;Get all rows from df1 that have an index that exists in df2&lt;br /&gt;
 df = df1[df1.index.isin(df2.index)]&lt;br /&gt;
&lt;br /&gt;
;Or get all intersectioned indices and select by loc:&lt;br /&gt;
 df = df1.loc[df1.index &amp;amp; df2.index]&lt;br /&gt;
 df = df1.loc[np.intersect1d(df1.index, df2.index)]&lt;br /&gt;
 df = df1.loc[df1.index.intersection(df2.index)]&lt;br /&gt;
&lt;br /&gt;
==Use data==&lt;br /&gt;
;Print 2 attributes for each row and check for no value&lt;br /&gt;
:pd.isna(value) works for Null, NaN (Nod a number) and NaT (not a time) too.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for index, row in df.iterrows():&lt;br /&gt;
    print(row[&#039;ColumnA&#039;],row[&#039;ColumnB&#039;])&lt;br /&gt;
    if ps.isna(row[&#039;ColumnA&#039;]):&lt;br /&gt;
        print(&#039;Found a NaN value&#039;) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
;Print all values for the first row&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for column, row in df.iteritems():&lt;br /&gt;
    print(column,row[0])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Loop over columns&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for column in df:&lt;br /&gt;
    print(f&amp;quot;Columnname {column}&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;df.iloc[0]&lt;br /&gt;
:return the values of the first row as pandas series. If there is only 1 column returns the value.&lt;br /&gt;
&lt;br /&gt;
;df.iloc[0][0]&lt;br /&gt;
:return the value of the first column in the first row. Columns can also be identified by name&lt;br /&gt;
&lt;br /&gt;
;df[&amp;lt;column&amp;gt;].quantile(q=0.1)&lt;br /&gt;
:Return the 10th percentile (10% of the values in &amp;lt;column&amp;gt; is lower than the 10th percentile)&lt;br /&gt;
&lt;br /&gt;
;df[&amp;lt;column].str.extract(r&amp;quot;A regex(p\w+)&amp;quot;)&lt;br /&gt;
:Return a series (column) of the values selected by [[Regular Expressions]] (p\w+)&lt;br /&gt;
;df[&amp;lt;columna&amp;gt;].map(str) + &#039;_&#039; + df[&amp;lt;columnb&amp;gt;].map(str)&lt;br /&gt;
:Return a series (column) with the columns concatenated. If not mapped to str an error will be thrown.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df[&amp;lt;column&amp;gt;].map(str).apply(lambda x: x[-1])&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
:Return a series (column) with the last character of the &amp;lt;column&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Series=&lt;br /&gt;
Pandas Series [https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.html online documentation].&amp;lt;br&amp;gt;&lt;br /&gt;
A pandas series is a 1 dimensional array with named keys.&amp;lt;br&amp;gt;&lt;br /&gt;
Pandas Series have all kind of methods similar to [[Numpy]] like main, std, min, max,.... In fact Pandas is using numpy to do this.&lt;br /&gt;
;s = pd.Series([])&lt;br /&gt;
;s = pd.Series([valuelist],[indexlist])&lt;br /&gt;
:Initialize a series. If indexlist is omitted the keys are integers starting at 0.&lt;br /&gt;
;s[&amp;lt;key&amp;gt;] = &amp;lt;value&amp;gt;&lt;br /&gt;
:Assign &amp;lt;value&amp;gt; to the series element with key &amp;lt;key&amp;gt;&lt;br /&gt;
:The order in the series is the order in which they are created, NOT the numeric order.&lt;br /&gt;
:Elements can be addressed as &amp;lt;code&amp;gt;s[&amp;lt;key&amp;gt;]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;s.&amp;lt;key&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;s[&amp;lt;numkey&amp;gt;]&amp;lt;/code&amp;gt;. Where &amp;lt;numkey&amp;gt; is defined by the order the element was created. &lt;br /&gt;
:Once you have used named keys in a series you cannot create new elements with a numeric key.&lt;br /&gt;
;s.index&lt;br /&gt;
:All indexes in the series. Can be sliced to find a particular index.&lt;br /&gt;
;s.describe()&lt;br /&gt;
:Series statistics&lt;br /&gt;
&lt;br /&gt;
All in 1 example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
import pandas as pd&lt;br /&gt;
s = pd.Series([])&lt;br /&gt;
for i in range(50):&lt;br /&gt;
    s[i] = int(np.random.random() * 100)&lt;br /&gt;
&lt;br /&gt;
for i in s.index:&lt;br /&gt;
    print(i,s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funny, you can do &amp;lt;code&amp;gt;s[0]&amp;lt;/code&amp;gt; but not&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for i in s:&lt;br /&gt;
    print(s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To get all values from the series you do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for v in s:&lt;br /&gt;
    print(v)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To get the indexes too:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for i in s.index:&lt;br /&gt;
    print(i,s[i])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TimeSeries==&lt;br /&gt;
Indexes that contains datetime values are automatically casted to a DatetimeIndex.&lt;br /&gt;
&lt;br /&gt;
;df.resample(&#039;5D&#039;).mean&lt;br /&gt;
:Return the dataframe with the average value of each 5 days.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;df.resample(&#039;1H&#039;).agg({&#039;ColumnA&#039;:&#039;first&#039;,&#039;ColumnB&#039;:&#039;max&#039;, &#039;ColumnC&#039;:&#039;min&#039;, &#039;ColumnD&#039;:&#039;last&#039; })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Resample with aggregation specified per column.&lt;br /&gt;
&lt;br /&gt;
;df.resample(&#039;5D&#039;,origin=&#039;end&#039;)&lt;br /&gt;
:Resample so the last timestamp is used, by default it starts with the first, the last set may be incomplete.&lt;br /&gt;
&lt;br /&gt;
==Datetime functions==&lt;br /&gt;
;df[datefield] = pd.to_datetime(df[datefield],format=&#039;%d-%m-%Y&#039;)&lt;br /&gt;
:Convert a string-column with a date into datetime. Format is the input format.&lt;br /&gt;
:WARNING: without format to_datetime tries to make up what the format is. This is pretty intelligent but can easily be wrong with day-numbers under 13&lt;br /&gt;
;df[datefield] = pd.to_datetime(df[datefield],unit=&#039;s&#039;)&lt;br /&gt;
:Convert a column with [[unix time]] into datetime.&lt;br /&gt;
;df[&amp;lt;timefield&amp;gt;] = testdf[&amp;lt;datetime-field&amp;gt;].dt.time&lt;br /&gt;
:Return a series (column) with the time-value of a datetime-column&lt;br /&gt;
&lt;br /&gt;
=Reading Data=&lt;br /&gt;
;read_html(url)&lt;br /&gt;
:Read html tables into a list of [[#DataFrame |dataframes]] (no header, no index)&lt;br /&gt;
Example code. The first line in the table is a header, the first column the index (e.g. dates), decimal specifies the decimal point character.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
tables = pd.read_html(url,header=0,index_col=0,decimal=&amp;lt;char&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;read_sql(query,cnx,index_columns=[col1,col2])&lt;br /&gt;
:Read data from the database opened on cnx (see [[Python:Databases]])&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
df = pd.read_sql(query,cnx,index_col=[&#039;Primarykey&#039;])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;read_csv(csvfile)&lt;br /&gt;
:Read data from a file with Character Separated Values&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_csv(csvfile, delimiter=&#039;,&#039;, usecols=[&amp;lt;columnA&amp;gt;, &amp;lt;columnB&amp;gt;], dtype = {&amp;lt;columnA&amp;gt;: str})&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Read columns &amp;lt;columnA&amp;gt; and &amp;lt;columnB&amp;gt; into a dataframe and force columnA to string type.&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_csv(csvfile, index_col=False, header=None, names=[&#039;columnA&#039;, columnB&#039;], na_values = &#039;None&#039;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Read from a file with no indexcolumn nor a headerrow,  set the colomnnames and handle &#039;None&#039; and NA value.&lt;br /&gt;
&lt;br /&gt;
==Excel==&lt;br /&gt;
;read_excel(xlsfile, sheetname)&lt;br /&gt;
:Read data from the sheet with &#039;sheetname&#039; in a microsoft [[XLS|Excel file]] into a dataframe&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;read_excel(xlsfile,sheetname,converters={&#039;columna&#039;:str,&#039;columnb&#039;:str})&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Force columns to be read as string&lt;br /&gt;
;read_excel(xlsfile, sheet_name=None)&lt;br /&gt;
:Read all sheets into a dict {sheetname: df,...}. Sheets can be specified by number or name, if multiple, in a list. If only 1 sheet is specified a dataframe is returned, not a dict of dataframes.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
dfdict = pd.read_excel(filename, sheet_name=None)&lt;br /&gt;
for sheetname, df in dfdict.items():&lt;br /&gt;
   print(f&amp;quot;Working on sheet {sheetname}&amp;quot;)&lt;br /&gt;
   for index, row in df.iterrows():&lt;br /&gt;
      print(row)&lt;br /&gt;
   adict = df.to_dict(&#039;records&#039;)    # Creates a list of dicts [{columname: value,...},...]&lt;br /&gt;
   print(json.dumps(adict, indent=4))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Convert all sheets to CSV files&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import sys&lt;br /&gt;
import pandas as pd&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    for filename in sys.argv[1:]:&lt;br /&gt;
        try:&lt;br /&gt;
            dfdict = pd.read_excel(filename, sheet_name=None)&lt;br /&gt;
        except Exception as exception:&lt;br /&gt;
            print(f&amp;quot;{filename} cannot be read by pandas.read_excel as {exception}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            for sheetname, df in dfdict.items():&lt;br /&gt;
                print(f&amp;quot;Working on {filename}, {sheetname}&amp;quot;)&lt;br /&gt;
                if len(dfdict) == 1:&lt;br /&gt;
                    sheetname = &#039;&#039;&lt;br /&gt;
                else:&lt;br /&gt;
                    sheetname = f&amp;quot;_{sheetname}&amp;quot;&lt;br /&gt;
                lines = df.to_dict(&#039;records&#039;)&lt;br /&gt;
                header = lines[0].keys()&lt;br /&gt;
                outputfile = filename.replace(&#039;.xlsx&#039;, f&amp;quot;{sheetname}.csv&amp;quot;)&lt;br /&gt;
                fh = open(outputfile, &#039;w&#039;)&lt;br /&gt;
                fh.write(&#039;,&#039;.join(header) + &#039;\n&#039;)&lt;br /&gt;
                for line in lines:&lt;br /&gt;
                    fh.write(&#039;,&#039;.join(map(str,line.values())) + &#039;\n&#039;)&lt;br /&gt;
                fh.close()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
main()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Disks_and_filesystems&amp;diff=1710</id>
		<title>Disks and filesystems</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Disks_and_filesystems&amp;diff=1710"/>
		<updated>2026-03-10T10:23:35Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Linux/Unix]]&lt;br /&gt;
&lt;br /&gt;
;badblocks -v- s /dev/sdb &amp;gt;badblocks.log&lt;br /&gt;
:Check a device for bad blocks&lt;br /&gt;
&lt;br /&gt;
;fdisk /dev/sdb   # Deprecated&lt;br /&gt;
;gdisk /dev/sdb&lt;br /&gt;
:Manage disk (GPT) partitions&lt;br /&gt;
&lt;br /&gt;
;df -h&lt;br /&gt;
:Show filesystem block usage in human friendly format&lt;br /&gt;
&lt;br /&gt;
;df -i&lt;br /&gt;
:Show filesystem inode usage&lt;br /&gt;
&lt;br /&gt;
;df -P&lt;br /&gt;
:Report file-system information in parseble format. &lt;br /&gt;
&lt;br /&gt;
;du -shx *&lt;br /&gt;
:Report disk usage for all files and directories in the current directory. Do not count files on other filesystems (-x) and do not follow symbolic links (default)&lt;br /&gt;
&lt;br /&gt;
;ls -i &amp;lt;file&amp;gt;&lt;br /&gt;
:Show inode of &amp;lt;file&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;stat &amp;lt;file&amp;gt;&lt;br /&gt;
:Show about all there is to know about &amp;lt;file&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;getfacl &amp;lt;file&amp;gt;&lt;br /&gt;
:Show the Access Control List (ACL) information for a file or directory&lt;br /&gt;
&lt;br /&gt;
;setfacl -m &amp;lt;nowiki&amp;gt;u:&amp;lt;username&amp;gt;:&amp;lt;perm&amp;gt; &amp;lt;file&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Add &amp;lt;perm&amp;gt; for &amp;lt;username&amp;gt; to &amp;lt;file&amp;gt;&lt;br /&gt;
;setfacl -d -m &amp;lt;nowiki&amp;gt;u:&amp;lt;username&amp;gt;:&amp;lt;perm&amp;gt; &amp;lt;dir&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:-d makes that all files in &amp;lt;dir&amp;gt; will get the &amp;lt;username&amp;gt;:&amp;lt;perm&amp;gt; added to the ACL&lt;br /&gt;
&lt;br /&gt;
;mount -t &amp;lt;fstype&amp;gt; -o &amp;lt;options&amp;gt; &amp;lt;devicefile&amp;gt; &amp;lt;mountpoint&amp;gt; &lt;br /&gt;
:Mount a filesystem (fstype and options can be omitted often)&lt;br /&gt;
&lt;br /&gt;
;mount -a&lt;br /&gt;
:Mount all filesystems in [[#fstab|/etc/fstab]] with the &amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt; option.&lt;br /&gt;
;mount -o loop /path/to/my-iso-image.iso /mnt/iso&lt;br /&gt;
:Mount an .iso file &lt;br /&gt;
&lt;br /&gt;
==fstab==&lt;br /&gt;
Configuration file to store mounts. Example for NFS mounts:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;&amp;lt;host&amp;gt;:&amp;lt;path&amp;gt; 			&amp;lt;mountpoint&amp;gt; 	  nfs	  defaults	  0       0&amp;lt;/code&amp;gt;&lt;br /&gt;
:Enable mount by; &amp;lt;code&amp;gt;mount &amp;lt;mountpoint&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mount the &amp;lt;path&amp;gt; exported by &amp;lt;host&amp;gt; on directory &amp;lt;mountpoint&amp;gt; using the NFS protocol with default setting (see below), do not automatically backup when dump is executed and do not fsck when mounted at boot time.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;&amp;lt;host&amp;gt;:&amp;lt;path&amp;gt; 			&amp;lt;mountpoint&amp;gt; 	  nfs	  defaults,noauto	  0       0&amp;lt;/code&amp;gt;&lt;br /&gt;
:Same as above but do not mount at boot-time&lt;br /&gt;
&lt;br /&gt;
Defaults (specified by defaults) are for ext3 filesystems: rw,suid,dev,exec,auto,nouser,async (read/write, set userID, dev?, allow execution of executables, mount during boot and when &amp;lt;code&amp;gt;mount -a&amp;lt;/code&amp;gt; is done,  only root can mount this, do not wait for the host to have written to storage)&lt;br /&gt;
&lt;br /&gt;
See the [https://en.wikipedia.org/wiki/Fstab fstab wikipedia page] for more.&lt;br /&gt;
&lt;br /&gt;
==Performance==&lt;br /&gt;
The graphical utility &#039;&#039;&#039;Disks&#039;&#039;&#039; has a benchmark option.&lt;br /&gt;
&lt;br /&gt;
;dd if=/dev/zero of=./test.tmp bs=1G count=1 oflag=dsync;rm -f ./test.tmp&lt;br /&gt;
:Check plain write speed&lt;br /&gt;
;dd if=/dev/zero of=./test.tmp bs=512 count=1000 oflag=dsync;rm -f ./test.tmp&lt;br /&gt;
:Latency test&lt;br /&gt;
&lt;br /&gt;
On an empty disk you can do:&lt;br /&gt;
;dd if=/dev/zero of=/dev/sdb bs=8k count=10k&lt;br /&gt;
:Test disk write speed if no filesystem exists&lt;br /&gt;
&lt;br /&gt;
==Misc==&lt;br /&gt;
;/dev/null&lt;br /&gt;
:The unix black hole. Write always succeeds with no effect at all.&lt;br /&gt;
&lt;br /&gt;
;/dev/zero&lt;br /&gt;
:Provides an unlimited amount of null characters (ASCII 0). Can be used for cleaning disks or benchmarking (see #Performance)&lt;br /&gt;
:Writing to /dev/zero is the same as writing to /dev/null&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Archiving&amp;diff=1709</id>
		<title>Archiving</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Archiving&amp;diff=1709"/>
		<updated>2026-02-26T13:31:30Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating archives and compress files.&lt;br /&gt;
&lt;br /&gt;
==zip==&lt;br /&gt;
Available on most operating systems&lt;br /&gt;
;zip archive.zip file&lt;br /&gt;
:Create or update archive.zip, put file in there. If file is already existing in the archive it is replaced.&lt;br /&gt;
;zip -r archive.zip path&lt;br /&gt;
:Create or update archive.zip, put path and all below in there. Files existing in the archive are replaced.&lt;br /&gt;
&lt;br /&gt;
;unzip archive.zip file&lt;br /&gt;
:Extract file from archive.zip and put it in the current directory &lt;br /&gt;
&lt;br /&gt;
;unzip archive.zip path &lt;br /&gt;
:Extract path from archive.zip and put it in the current directory. Use quotes if path has wildcards.&lt;br /&gt;
&lt;br /&gt;
;unzip -l archive.zip&lt;br /&gt;
:List all files in the archive.&lt;br /&gt;
&lt;br /&gt;
;unzip -l archive.zip path&lt;br /&gt;
:List path if it is in the archive.&lt;br /&gt;
&lt;br /&gt;
==tar==&lt;br /&gt;
Available on Unix-like operating systems&lt;br /&gt;
;tar cvf archive.tar path&lt;br /&gt;
:Create archive.tar and put all file under path in it. Be verbose, list what is done (-v)&lt;br /&gt;
&lt;br /&gt;
;tar xvf archive.tar path&lt;br /&gt;
:Extract path from archive.tar, put it in the current directory. Be verbose, list what is done (-v)&lt;br /&gt;
&lt;br /&gt;
;tar tf archive.tar path&lt;br /&gt;
:List what is in archive.tar.&lt;br /&gt;
&lt;br /&gt;
;tar cvzf archive.tgz path&lt;br /&gt;
:Create gzipped archive.tgz and put all file under path in it. Be verbose, list what is done (-v).&lt;br /&gt;
:Similar for x and t, the z makes tar work on gzipped archives;&lt;br /&gt;
&lt;br /&gt;
;tar uvf archive.tar  --no-recursion --files-from -&lt;br /&gt;
:Read filenames from standard input e.g. as found by [[find]] and update the archive.&lt;br /&gt;
&lt;br /&gt;
==gzip==&lt;br /&gt;
;gzip &amp;lt;filename&amp;gt;&lt;br /&gt;
:Compress file to &amp;lt;filename&amp;gt;.gz&lt;br /&gt;
&lt;br /&gt;
;gzip -c &amp;lt;filename&amp;gt;&lt;br /&gt;
:Compress file to standard output. Can be used for log-rotation when the inode of the file should not change as the application keeps it open. &lt;br /&gt;
:&amp;lt;code&amp;gt;gzip -c &amp;lt;filename&amp;gt; &amp;gt; &amp;lt;filename&amp;gt;.gz; cp /dev/null &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==7zip==&lt;br /&gt;
Available on most operating systems. Provides very good compression&lt;br /&gt;
;7za a &amp;lt;archivename&amp;gt;.7z &amp;lt;files&amp;gt;&lt;br /&gt;
:Add files to archive, create it when needed.&lt;br /&gt;
;7za l &amp;lt;archivename&amp;gt;.7z&lt;br /&gt;
:List an archive.&lt;br /&gt;
;7za e &amp;lt;archivename&amp;gt;.7z &amp;lt;files&amp;gt;&lt;br /&gt;
:Extract &amp;lt;files&amp;gt; from archive without path, all if &amp;lt;files&amp;gt; is omitted.&lt;br /&gt;
;7za x &amp;lt;archivename&amp;gt;.7z&lt;br /&gt;
:Extract &amp;lt;files&amp;gt; from archive with full path, all if &amp;lt;files&amp;gt; is omitted.&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Hoofd_en_Hart&amp;diff=1708</id>
		<title>Hoofd en Hart</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Hoofd_en_Hart&amp;diff=1708"/>
		<updated>2026-02-13T20:40:37Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: Created page with &amp;quot;Het hoofd bestuurt, het hart regeert.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Het hoofd bestuurt, het hart regeert.&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Chat_with_large_language_models&amp;diff=1707</id>
		<title>Chat with large language models</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Chat_with_large_language_models&amp;diff=1707"/>
		<updated>2026-01-31T16:21:00Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Get better prompts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since 2024 we have Large Language Models (LLM) that are sophisticated enough to have a somewhat reasonable chat with.&lt;br /&gt;
&lt;br /&gt;
Some examples:&lt;br /&gt;
* ChatGPT [https://chatgpt.com] by OpenAI, the first public LLM chatbot&lt;br /&gt;
* Copilot [https://copilot.microsoft.com/] by Microsoft, based on the OpenAI models&lt;br /&gt;
* le Chat [https://https://mistral.ai/products/le-chat] by Mistral, the European alternative (in 2025 not as smart as the othters)&lt;br /&gt;
* Gemeni [https://gemini.google.com/] by Google&lt;br /&gt;
* Claude [https://claude.ai/] by Anthropic, should be best for coding &lt;br /&gt;
&lt;br /&gt;
An LLM is a implementation of [[Artificial Intelligence]] (AI).&lt;br /&gt;
&lt;br /&gt;
An LLM is trained with a vast amount of text. The model tries to find the most plausible word to present to you given the conversation you are having. Just that, find the next word to say, and at some point decide there is nothing to say until the user says something.&lt;br /&gt;
&lt;br /&gt;
An LLM only knows the things it is trained with and; IT HAS NO CLUE OF WHAT IT MEANS. In below text it may look like chatbots have some intelligence, THEY DON&#039;T. They are just very good at searching the most commonly given answer to your question and formulate that in correct &amp;lt;your language&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
e.g.:&lt;br /&gt;
:For chatbots that can generate pictures; Ask it to draw an analogue clock that points to 18:15. It will show you a clock pointing 10:10 (or 13:50) as the vast majority of clock pictures on the web show that time. It may get better over time but in 2025 Copilot offered to make 4 clock that show the time between 18:05 and 18:20 with 5 minutes intervals. It returned 4 clocks showing 10:10.&lt;br /&gt;
:You cannot ask a chatbot to count the number of characters in a random word. You may be lucky the word, and the number of characters for it, were in the training data but in general it will return the number that is most times found for counting a word&#039;s characters on the web.&lt;br /&gt;
&lt;br /&gt;
=Get better prompts=&lt;br /&gt;
Prompts (what you say to the chatbot) should be as specific possible to get the most accurate answer.&lt;br /&gt;
You can ask to improve your prompt like (in dutch):&lt;br /&gt;
 Je bent een expert op het gebied van &amp;lt;chatbot&amp;gt;. Jij helpt mij met het herschrijven van prompts om &amp;lt;chatbot&amp;gt; de meest complete antwoorden voor mij te genereren. Alleen als ik een prompt begin met &#039;XX:&#039; dan wil ik dat jij de prompt zo herschrijft dat je voldoet aan onderstaande regels:&lt;br /&gt;
 a) De nieuwe prompt benoemt een expertrol voor &amp;lt;chatbot&amp;gt;&lt;br /&gt;
 b) De nieuwe prompt geeft de vraagstelling gedetailleerd weer&lt;br /&gt;
 c) De nieuwe prompt bevat een gedetailleerde opdracht&lt;br /&gt;
 d) De nieuwe prompt geeft voldoende context&lt;br /&gt;
 e) De nieuwe prompt is geoptimaliseerd en volledig duidelijk voor &amp;lt;chatbot&amp;gt;&lt;br /&gt;
 Geef alleen aan of je het hebt begrepen&lt;br /&gt;
&lt;br /&gt;
This prompt will only tell you that is understood you. Next prompts in this chat you start with: &amp;quot;COPILOT-Prompt&amp;quot; will return an optimized prompt.&lt;br /&gt;
&lt;br /&gt;
In CoPilot and chatGPT you can add this prompt improver to you personal setting (without the last command). The chatbot will have this instruction in all future chats.&lt;br /&gt;
&lt;br /&gt;
=Hallucinating=&lt;br /&gt;
Chatbots can get lost in the possible answers and start talking rubbish, that is called hallucinating.&lt;br /&gt;
&lt;br /&gt;
All words in the chat are taken into account when formulating answers. That enables the bot to have a (potential) useful conversation with you, however when you change subject it may get confused.&lt;br /&gt;
&lt;br /&gt;
Limit a chat to 1 subject, start a new one when you want to discuss a different subject.&lt;br /&gt;
&lt;br /&gt;
=Bot instructions=&lt;br /&gt;
You can tell the bot to be more or less strict in the answers it returns&lt;br /&gt;
;Temperature&lt;br /&gt;
:Check and add&lt;br /&gt;
;forbidden_words_list&lt;br /&gt;
:Check and add&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Ntp&amp;diff=1706</id>
		<title>Ntp</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Ntp&amp;diff=1706"/>
		<updated>2026-01-23T15:14:20Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* systemd-timesyncd */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:networking]]&lt;br /&gt;
Network Time Protocol, synchronize local clock to remote.&lt;br /&gt;
&lt;br /&gt;
To use ntpq the [[iptables|firewall]] should be open for traffic to the localhost.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
iptables -A INPUT -i lo -j ACCEPT&lt;br /&gt;
iptables -A OUTPUT -o lo -j ACCEPT&lt;br /&gt;
ip6tables -A INPUT -i lo -j ACCEPT&lt;br /&gt;
ip6tables -A OUTPUT -o lo -j ACCEPT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When using an NTP-server pool like [https://pool.ntp.org pool.ntp.org] ( 0.&amp;lt;country&amp;gt;.pool.ntp.org etc.) make sure you refresh the peers every now and than. Only when ntp is started the hosts are selected, when they leave the pool ntp will not automatically select another.&lt;br /&gt;
&lt;br /&gt;
;Very secure setinngs in ntp.conf&lt;br /&gt;
 restrict -4 default kod nomodify notrap nopeer noquery&lt;br /&gt;
 restrict -6 default kod nomodify notrap nopeer noquery&lt;br /&gt;
&lt;br /&gt;
;ntpq&lt;br /&gt;
:CLI interface to query the ntp status. &lt;br /&gt;
:;peer &lt;br /&gt;
::Show peers&lt;br /&gt;
:;ass &lt;br /&gt;
::Show associations (details of peers) &lt;br /&gt;
:;pstat &amp;lt;assid&amp;gt;&lt;br /&gt;
::Show status of a association&lt;br /&gt;
&lt;br /&gt;
;ntpdate -q &amp;lt;server&amp;gt;&lt;br /&gt;
:Get date from &amp;lt;server&amp;gt; without doing any update&lt;br /&gt;
&lt;br /&gt;
=systemd-timesyncd=&lt;br /&gt;
systemd-timesyncd is a lightweight client-only ntp implementation.&lt;br /&gt;
&lt;br /&gt;
By default configuration from DHCP is used. Additional configuration can be added to /etc/systemd/timesyncd.conf&lt;br /&gt;
 NTP=&amp;lt;space separated list of NTP-servers&amp;gt;&lt;br /&gt;
 FallbackNTP=&amp;lt;space separated list of NTP-servers&amp;gt;&lt;br /&gt;
Only 1 server is used, the server lists are polled one by one until one responds.&lt;br /&gt;
&lt;br /&gt;
;timedatectl show&lt;br /&gt;
:Show status of the synchronization &lt;br /&gt;
;timedatectl show-timesync&lt;br /&gt;
:Detailed status of the synchronization&lt;br /&gt;
;timedatectl timesync-status&lt;br /&gt;
:More detailed status of the synchronization&lt;br /&gt;
;systemctl status systemd-timesyncd&lt;br /&gt;
:The status of the daemon&lt;br /&gt;
;systemctl restart systemd-timesyncd&lt;br /&gt;
:Restart the daemon on configuration changes, reload is not supported.&lt;br /&gt;
&lt;br /&gt;
If you want to use ntp instead of timesyncd e.g. because you want to run a ntp server use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt; &lt;br /&gt;
systemctl disable systemd-timesyncd.service&lt;br /&gt;
apt install ntp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The NTP deamon will automatically start with default settings. Adjust things (like the servers) to your likings&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Ntp&amp;diff=1705</id>
		<title>Ntp</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Ntp&amp;diff=1705"/>
		<updated>2026-01-23T14:38:59Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* systemd-timesyncd */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:networking]]&lt;br /&gt;
Network Time Protocol, synchronize local clock to remote.&lt;br /&gt;
&lt;br /&gt;
To use ntpq the [[iptables|firewall]] should be open for traffic to the localhost.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
iptables -A INPUT -i lo -j ACCEPT&lt;br /&gt;
iptables -A OUTPUT -o lo -j ACCEPT&lt;br /&gt;
ip6tables -A INPUT -i lo -j ACCEPT&lt;br /&gt;
ip6tables -A OUTPUT -o lo -j ACCEPT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When using an NTP-server pool like [https://pool.ntp.org pool.ntp.org] ( 0.&amp;lt;country&amp;gt;.pool.ntp.org etc.) make sure you refresh the peers every now and than. Only when ntp is started the hosts are selected, when they leave the pool ntp will not automatically select another.&lt;br /&gt;
&lt;br /&gt;
;Very secure setinngs in ntp.conf&lt;br /&gt;
 restrict -4 default kod nomodify notrap nopeer noquery&lt;br /&gt;
 restrict -6 default kod nomodify notrap nopeer noquery&lt;br /&gt;
&lt;br /&gt;
;ntpq&lt;br /&gt;
:CLI interface to query the ntp status. &lt;br /&gt;
:;peer &lt;br /&gt;
::Show peers&lt;br /&gt;
:;ass &lt;br /&gt;
::Show associations (details of peers) &lt;br /&gt;
:;pstat &amp;lt;assid&amp;gt;&lt;br /&gt;
::Show status of a association&lt;br /&gt;
&lt;br /&gt;
;ntpdate -q &amp;lt;server&amp;gt;&lt;br /&gt;
:Get date from &amp;lt;server&amp;gt; without doing any update&lt;br /&gt;
&lt;br /&gt;
=systemd-timesyncd=&lt;br /&gt;
systemd-timesyncd is a lightweight client-only ntp implementation.&lt;br /&gt;
&lt;br /&gt;
By default configuration from DHCP is used. Additional configuration can be added to /etc/systemd/timesyncd.conf&lt;br /&gt;
 NTP=&amp;lt;space separated list of NTP-servers&amp;gt;&lt;br /&gt;
 FallbackNTP=&amp;lt;space separated list of NTP-servers&amp;gt;&lt;br /&gt;
Only 1 server is used, the server lists are polled one by one until one responds.&lt;br /&gt;
&lt;br /&gt;
;timedatectl timesync-status&lt;br /&gt;
:Detailed status of systemd-timesyncd&lt;br /&gt;
;systemctl status systemd-timesyncd&lt;br /&gt;
:The status of the daemon&lt;br /&gt;
;systemctl restart systemd-timesyncd&lt;br /&gt;
:Restart the daemon on configuration changes, reload is not supported.&lt;br /&gt;
&lt;br /&gt;
If you want to use ntp instead of timesyncd e.g. because you want to run a ntp server use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt; &lt;br /&gt;
systemctl disable systemd-timesyncd.service&lt;br /&gt;
apt install ntp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The NTP deamon will automatically start with default settings. Adjust things (like the servers) to your likings&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Nftables&amp;diff=1704</id>
		<title>Nftables</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Nftables&amp;diff=1704"/>
		<updated>2026-01-18T20:24:40Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Commands */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:networking]]&lt;br /&gt;
[[category:Linux/Unix]]&lt;br /&gt;
nftables is the successor of [[iptables]] for managing firewall rules.&lt;br /&gt;
&lt;br /&gt;
At first glance [https://wiki.debian.org/nftables] it looks a bit like a [[iptables#ufw|ufw]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:35%&amp;quot;&lt;br /&gt;
|+ Address families&lt;br /&gt;
! Family&lt;br /&gt;
! Remark&lt;br /&gt;
|-&lt;br /&gt;
| ip&lt;br /&gt;
| IPv4 This is the default if no family is specified&lt;br /&gt;
|-&lt;br /&gt;
| ip6&lt;br /&gt;
| IPv6&lt;br /&gt;
|-&lt;br /&gt;
| inet&lt;br /&gt;
| IPv4 + IPv6&lt;br /&gt;
|-&lt;br /&gt;
| arp&lt;br /&gt;
| arp&lt;br /&gt;
|-&lt;br /&gt;
| bridge&lt;br /&gt;
| bridge&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Install and activate=&lt;br /&gt;
Debian comes with nftables installed since Buster.&lt;br /&gt;
;apt install nftables&lt;br /&gt;
:Install if needed&lt;br /&gt;
;systemctl enable nftables.service&lt;br /&gt;
:Create the service&lt;br /&gt;
;systemctl start nftables&lt;br /&gt;
;service nftables start&lt;br /&gt;
:Start the service&lt;br /&gt;
;systemctl status nftables&lt;br /&gt;
;service nftables status&lt;br /&gt;
:Show status&lt;br /&gt;
&lt;br /&gt;
=Confiuration=&lt;br /&gt;
The configuration is in /etc/nftables.conf&lt;br /&gt;
&lt;br /&gt;
=Commands=&lt;br /&gt;
;nft list ruleset&lt;br /&gt;
:Show the current ruleset in the format you can load with nft -f (see below)&lt;br /&gt;
;nft list table &amp;lt;family&amp;gt; filter&lt;br /&gt;
:Show the current filters for &amp;lt;family&amp;gt;.&lt;br /&gt;
;nft -f &amp;lt;filename&amp;gt;&lt;br /&gt;
:Load rules from &amp;lt;filename&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Dhcp&amp;diff=1703</id>
		<title>Dhcp</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Dhcp&amp;diff=1703"/>
		<updated>2026-01-17T17:28:43Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* KEA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:networking]]&lt;br /&gt;
[[Category:Linux/Unix]]&lt;br /&gt;
Dynamic Host Configuration Protocol&lt;br /&gt;
&lt;br /&gt;
Provide IP addresses for your network from a central server.&lt;br /&gt;
==IPv6==&lt;br /&gt;
&lt;br /&gt;
[[IPv6]] addresses can be advertised by the radvd (often on your ISP&#039;s router). These are based on the MAC address of the client or pseudo randomly generated. For more control over the addresses you can run a dhcp server. When the [https://www.isc.org/dhcp/ ISC dhcp server] is used you need separate instances for the IPv4 and the IPv6 server.&lt;br /&gt;
&lt;br /&gt;
=KEA=&lt;br /&gt;
KEA[https://kb.isc.org/docs/aa-01615] is the successor of the isc-dhcp-server. The [[IPv4]] part works fine. [[IPv6]] appears to be a lot more difficult (like it was for isc-dhcp-server)&lt;br /&gt;
;apt install kea&lt;br /&gt;
:Install all packages for the KEA-server&lt;br /&gt;
&lt;br /&gt;
=isc-dhcp-server=&lt;br /&gt;
Sample configuration file (/etc/dhcp/dhcpd6.conf).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
log-facility local7;&lt;br /&gt;
default-lease-time 86400;&lt;br /&gt;
max-lease-time 604800;&lt;br /&gt;
&lt;br /&gt;
subnet6 your:site:ipv6:prefix::/64 {&lt;br /&gt;
#  range6 your:ipv6:prefix:address:1::f000 your:ipv6:prefix:address:1::ffff;&lt;br /&gt;
&lt;br /&gt;
  option dhcp6.domain-search &amp;quot;local.domain.tld&amp;quot;;&lt;br /&gt;
  option dhcp6.name-servers &amp;lt;name-server-address&amp;gt;;&lt;br /&gt;
  option ntp-servers ntp.domain.tld;&lt;br /&gt;
&lt;br /&gt;
  host host1name {&lt;br /&gt;
   host-identifier option dhcp6.client-id 00:a4:00:01:45:26:4d:8e:98:8e:76:d1:09:32;&lt;br /&gt;
   fixed-address6 &amp;lt;full ipv6-address&amp;gt;;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hosts for fixed addresses are found by their DUID. Only way I know to find it on the server is from the logfile (/var/log/syslog). On the client it is in var/lib/dhcpcd/duid&lt;br /&gt;
 &lt;br /&gt;
The firewall on the client needs to be open on the Link Local address (in the FE80::/10) range on port 546&lt;br /&gt;
&lt;br /&gt;
==IPv4==&lt;br /&gt;
Sample configuration file (/etc/dhcp/dhcpd.conf).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
ddns-update-style none;&lt;br /&gt;
&lt;br /&gt;
# option definitions common to all supported networks.&lt;br /&gt;
option domain-name &amp;quot;domain.tld&amp;quot;;&lt;br /&gt;
option domain-name-servers 192.168.1.2, 208.67.222.222;&lt;br /&gt;
option routers 192.168.1.254;&lt;br /&gt;
option broadcast-address 192.168.1.255;&lt;br /&gt;
option ntp-servers 192.168.1.4;&lt;br /&gt;
&lt;br /&gt;
# 1 day (fine for home networks, e.g. hotspots should have far shorter lease times) &lt;br /&gt;
default-lease-time 86400;&lt;br /&gt;
# 1 week&lt;br /&gt;
max-lease-time 604800;&lt;br /&gt;
&lt;br /&gt;
authoritative;&lt;br /&gt;
&lt;br /&gt;
log-facility local7;&lt;br /&gt;
&lt;br /&gt;
# Known hosts get fixed IP address defined in DNS-server&lt;br /&gt;
group {&lt;br /&gt;
 deny unknown-clients;&lt;br /&gt;
 # One week, these are sort of fixed addresses.&lt;br /&gt;
 default-lease-time 604800;&lt;br /&gt;
&lt;br /&gt;
 host host1name {&lt;br /&gt;
  hardware ethernet ff:ff:ff:ff:ff:ff;&lt;br /&gt;
  fixed-address host1name.domain.tld;&lt;br /&gt;
 }&lt;br /&gt;
 host host2name {&lt;br /&gt;
  hardware ethernet ff:ff:ff:ff:ff:ff;&lt;br /&gt;
  fixed-address host2name.domain.tld;&lt;br /&gt;
 }&lt;br /&gt;
}&lt;br /&gt;
# All other get an address from the range&lt;br /&gt;
subnet 192.168.1.0 netmask 255.255.255.0 {&lt;br /&gt;
 range 192.168.1.100 192.168.1.199;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The leases are kept track of in /var/lib/dhcp/dhcpd.leases&lt;br /&gt;
An ordinary entry looks like:&lt;br /&gt;
tstp and cltt are for the failover protocol, most other entries are self-explaining I think.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
lease 192.168.1.133 {&lt;br /&gt;
  starts 6 2021/03/18 11:22:00;&lt;br /&gt;
  ends 0 2021/03/19 11:22:00;&lt;br /&gt;
  tstp 0 2021/03/19 11:22:00;&lt;br /&gt;
  cltt 6 2021/03/19 11:22:00;&lt;br /&gt;
  binding state active;&lt;br /&gt;
  next binding state free;&lt;br /&gt;
  rewind binding state free;&lt;br /&gt;
  hardware ethernet ff:ff:ff:ff:ff:ff;&lt;br /&gt;
  client-hostname &amp;quot;host3name&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=DHCP clients=&lt;br /&gt;
;dhcpcd -k &amp;lt;interface&amp;gt;&lt;br /&gt;
:Release lease&lt;br /&gt;
;dhcpcd -n &amp;lt;interface&amp;gt;&lt;br /&gt;
:Renew lease&lt;br /&gt;
&lt;br /&gt;
=Traffic check=&lt;br /&gt;
;tcpdump -i eth0 port 547&lt;br /&gt;
:Check on server side&lt;br /&gt;
;tcpdump -i eth0 port 546&lt;br /&gt;
:Check on client side&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Perl&amp;diff=1702</id>
		<title>Perl</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Perl&amp;diff=1702"/>
		<updated>2026-01-15T13:18:23Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Programming]]&lt;br /&gt;
=Warnings=&lt;br /&gt;
===Put a ; at the end of each line===&lt;br /&gt;
This is still what I forget most.&lt;br /&gt;
&lt;br /&gt;
===autovivification===&lt;br /&gt;
:If testing for existence of a hash key beware that all intermediate keys will be created by the test. In below example &amp;lt;code&amp;gt;$hash1($key1}&amp;lt;/code&amp;gt; will be created if it does not exist yet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=Perl&amp;gt;&lt;br /&gt;
if (exists $hash1{$key1}{$key2) {&lt;br /&gt;
    ...&lt;br /&gt;
} else {&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=Things that do work=&lt;br /&gt;
&lt;br /&gt;
Searching and matching is explained in [[Regular Expressions]].&lt;br /&gt;
&lt;br /&gt;
;perl -e &#039;&amp;lt;commands&amp;gt;&#039;&lt;br /&gt;
:Execute &amp;lt;commnands&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Print out the contents of $variable in a structured format:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=Perl&amp;gt;&lt;br /&gt;
use Data::Dumper;&lt;br /&gt;
print Dumper($variable);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
if-then-else:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=Perl&amp;gt;&lt;br /&gt;
if &amp;lt; expr &amp;gt; {&lt;br /&gt;
 &amp;lt;codeblock&amp;gt;&lt;br /&gt;
} elsif &amp;lt; expr ) {&lt;br /&gt;
 &amp;lt;codeblock&amp;gt;&lt;br /&gt;
} else {&lt;br /&gt;
 &amp;lt;codeblock&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;$var += &amp;lt;value&amp;gt;&lt;br /&gt;
:Add &amp;lt;value&amp;gt; to $var (works for -, *, / too)&lt;br /&gt;
&lt;br /&gt;
;$string .= $addstring&lt;br /&gt;
:Concatenate $string and $addstring&lt;br /&gt;
&lt;br /&gt;
;$string =~ s/&amp;lt;regexp&amp;gt;/&amp;lt;newvalue&amp;gt;/[g]&lt;br /&gt;
:Substitute &amp;lt;regexp&amp;gt; with &amp;lt;newvalue&amp;gt; in $string. The g modifier makes the all occurrences of &amp;lt;regexp&amp;gt; are substituted.&lt;br /&gt;
&lt;br /&gt;
;$newstring = substr($string,start,length)&lt;br /&gt;
:Return substring of $string&lt;br /&gt;
&lt;br /&gt;
;sprintf(format,$string)&lt;br /&gt;
:Return formatted string. format is e.g. &amp;quot;%.3f&amp;quot;. Check [[Python:Strings#Advanced]] for all formats.&lt;br /&gt;
&lt;br /&gt;
;$exitcode = system(&amp;quot;a command&amp;quot;)&lt;br /&gt;
:Executed the command in a subprocess and return the exitcode&lt;br /&gt;
&lt;br /&gt;
;$output = `a command`&lt;br /&gt;
:Execute the command and return all command output&lt;br /&gt;
&lt;br /&gt;
;sleep(x)&lt;br /&gt;
:Sleep for x seconds&lt;br /&gt;
&lt;br /&gt;
;$|++&lt;br /&gt;
:Set standard output to unbuffered, every is put on screen immediately. &lt;br /&gt;
&lt;br /&gt;
;$username = getpwuid($&amp;lt;)&lt;br /&gt;
:Get the username of the one executing the script. $&amp;lt; is the uid of the current user.&lt;br /&gt;
&lt;br /&gt;
==Hashes==&lt;br /&gt;
;%newhash = (%oldhas1,%oldhash3)&lt;br /&gt;
;$newhashref = {$oldhasref1,$oldhashref3}&lt;br /&gt;
:Merge 2 hashes, works if all keys are unique&lt;br /&gt;
&lt;br /&gt;
==Arrays==&lt;br /&gt;
;arr1 = split(&amp;lt;sep&amp;gt;,$string)&lt;br /&gt;
:Split a string in to an array on &amp;lt;sep&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;a = arr1[0]&lt;br /&gt;
:First element in arr1&lt;br /&gt;
&lt;br /&gt;
;a = arr1[-1]&lt;br /&gt;
:Last element in arr1&lt;br /&gt;
&lt;br /&gt;
;if ( grep(/^&amp;lt;value&amp;gt;$/,@arr1) )&lt;br /&gt;
:Check if &amp;lt;value&amp;gt; exist in arr1 (Note the ^ and $  for an exact match&lt;br /&gt;
&lt;br /&gt;
==Files==&lt;br /&gt;
;open (FH, &amp;quot;&amp;lt; filename&amp;quot;) || die(&amp;quot;Open failed for filename&amp;quot;)&lt;br /&gt;
:Open filename for reading on filehandle FH. Exit the program when the open failed&lt;br /&gt;
&lt;br /&gt;
;@array = &amp;lt;FH&amp;gt;&lt;br /&gt;
:Read the file opened on FH into @array (1 element per line&lt;br /&gt;
&lt;br /&gt;
;while ( line = (&amp;lt;FH&amp;gt;) )&lt;br /&gt;
:Read the file opened on FH line by line&lt;br /&gt;
&lt;br /&gt;
==Flow control==&lt;br /&gt;
The usual works (if-then-else, for , foreach)&lt;br /&gt;
&lt;br /&gt;
;||die(&amp;quot;message&amp;quot;)&lt;br /&gt;
:|| causes the statement only to be executed if the previous failed. Stop the program and write messaged to standard error.&lt;br /&gt;
&lt;br /&gt;
;|| do {codeblock};&lt;br /&gt;
:Like die but not exiting the program, use to do additional actions on the failure of the previous command&lt;br /&gt;
&lt;br /&gt;
==Compare==&lt;br /&gt;
;==, !=, &amp;gt;=, &amp;gt;, &amp;lt;, etc&lt;br /&gt;
:Compare numeric data&lt;br /&gt;
;eq, ne, ge, gt, lt, etc&lt;br /&gt;
:Compare strings&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Python:Databases&amp;diff=1701</id>
		<title>Python:Databases</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Python:Databases&amp;diff=1701"/>
		<updated>2026-01-14T13:58:14Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* mariadb */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
= MySQL Connector =&lt;br /&gt;
&lt;br /&gt;
See below for an example script&lt;br /&gt;
&lt;br /&gt;
;import mysql.connector&lt;br /&gt;
:Load module for mysql &lt;br /&gt;
&lt;br /&gt;
;cnx = mysql.connector.connect(**cnxconfig)&lt;br /&gt;
:Open MySQL database as defined in the cnxconfig dictionary. See example below. The ** passes the dictionary unpacked to a function.&lt;br /&gt;
&lt;br /&gt;
;import cx_Oracle&lt;br /&gt;
:Load module for oracle &lt;br /&gt;
&lt;br /&gt;
;cnx = cx_Oracle.connect(user=dbuser, password=dbpasswd, dsn=dbtns_alias)&lt;br /&gt;
:Open Oracle database.&lt;br /&gt;
&lt;br /&gt;
;cnx.commit()&lt;br /&gt;
:Commit all open transactions to the database&lt;br /&gt;
 &lt;br /&gt;
;cursor = cnx.cursor()&lt;br /&gt;
:Create a cursor that returns rows as [[Python:DataTypes#Tuple | tuple]]&lt;br /&gt;
&lt;br /&gt;
;cursor = cnx.cursor(dictionary=True)&lt;br /&gt;
:Create a cursor that returns rows as [[Python:DataTypes#Dictionary_or_dict | dictionary]] { column1: value1, column2: value2 }&lt;br /&gt;
&lt;br /&gt;
;cursor = cnx.cursor(buffered=True)&lt;br /&gt;
:Create a cursor that retrieves the complete result at once so you can check rowcount immediately. Beware of overloading your memory if you expect large results. &lt;br /&gt;
&lt;br /&gt;
;cursor.execute(query)&lt;br /&gt;
:Execute &#039;query&#039;. Traverse the cursor to fetch the data. The cursor returns a tuple for each row by default.&amp;lt;br&amp;gt;&lt;br /&gt;
:;cursor.rowcount&lt;br /&gt;
::The number of rows fetched (SELECT) or affected (INSERT,UPDATE) by this query.&lt;br /&gt;
:;cursor.column_names&lt;br /&gt;
::The columnnames &lt;br /&gt;
&lt;br /&gt;
;cursor.fetchone()&lt;br /&gt;
:Return the next row from the cursor result.&lt;br /&gt;
&lt;br /&gt;
;cursor.fetchmany(size=2)&lt;br /&gt;
:Return the first two rows of the result in a list.&lt;br /&gt;
&lt;br /&gt;
;cursor.fetchall()&lt;br /&gt;
:Return all (remaining) rows of the result in a list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for row in cursor:&lt;br /&gt;
 print(row)&lt;br /&gt;
 for column in row:&lt;br /&gt;
 	print(column)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;cursor.close()&lt;br /&gt;
:Close the cursor&lt;br /&gt;
;cnx.close()&lt;br /&gt;
:Close the database connection&lt;br /&gt;
&lt;br /&gt;
Code example showing all:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import mysql.connector &lt;br /&gt;
&lt;br /&gt;
cnxconfig = {&lt;br /&gt;
    &#039;host&#039;: &#039;hostname&#039;,&lt;br /&gt;
    &#039;port&#039;: 3306,&lt;br /&gt;
    &#039;user&#039;: &#039;username&#039;,&lt;br /&gt;
    &#039;password&#039;: &#039;&#039;,&lt;br /&gt;
    &#039;database&#039;: &#039;DBname&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#cnx = mysql.connector.connect(host=&#039;hostname&#039;, port=3306, user=&#039;username&#039;, database=&#039;DBname&#039;)&lt;br /&gt;
cnx = mysql.connector.connect(**cnxconfig)&lt;br /&gt;
&lt;br /&gt;
if cnx:&lt;br /&gt;
	print(&amp;quot;Connection, continue&amp;quot;)&lt;br /&gt;
else:&lt;br /&gt;
	print(&amp;quot;No connection, exit&amp;quot;)&lt;br /&gt;
	exit()&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;Tuple cursor&amp;quot;)	&lt;br /&gt;
cursor = cnx.cursor()&lt;br /&gt;
&lt;br /&gt;
query = (&amp;quot;SELECT * FROM table&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
cursor.execute(query)&lt;br /&gt;
for columname in cursor.column_names:&lt;br /&gt;
 print(columname)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
 print(row)&lt;br /&gt;
 for column in row:&lt;br /&gt;
 	print(column)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;Dictionary cursor&amp;quot;)&lt;br /&gt;
cursor = cnx.cursor(dictionary=True)&lt;br /&gt;
cursor.execute(query)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
	for columname in row.keys():&lt;br /&gt;
		print(&amp;quot;{0:25s}: {1:}&amp;quot;.format(columname, row[columname])) &lt;br /&gt;
&lt;br /&gt;
cursor.close()&lt;br /&gt;
cnx.close()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=mariadb=&lt;br /&gt;
The mariadb module[https://mariadb.com/docs/connectors/mariadb-connector-python][https://mariadb-corporation.github.io/mariadb-connector-python/] works almost the same as the mysql.connecctor above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import mariadb&lt;br /&gt;
&lt;br /&gt;
# Connection parameters&lt;br /&gt;
config = {&lt;br /&gt;
    &#039;host&#039;: &#039;xxx&#039;,&lt;br /&gt;
    &#039;port&#039;: 3306,&lt;br /&gt;
    &#039;user&#039;: &#039;user&#039;,&lt;br /&gt;
    &#039;password&#039;: &#039;password&#039;,&lt;br /&gt;
    &#039;database&#039;: &#039;db&#039; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Connect to MariaDB&lt;br /&gt;
conn = mariadb.connect(**config)&lt;br /&gt;
cursor = conn.cursor()&lt;br /&gt;
cursor.execute(&amp;lt;query&amp;gt;)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
    print(row)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rows are tuples with a counter (id) as first element. &amp;lt;code&amp;gt;&#039;dictionary&#039;: True&amp;lt;/code&amp;gt; in the connection config should return dictionaries&lt;br /&gt;
;cursor.description&lt;br /&gt;
:Spec of the tuples in cursor&lt;br /&gt;
;cursor.metadata[&#039;field&#039;]&lt;br /&gt;
:The fields in the cursor&lt;br /&gt;
&lt;br /&gt;
= ODBC connections =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import pyodbc&lt;br /&gt;
&lt;br /&gt;
dsn = &#039;DSN=&amp;lt;name of ODBC-DNS&amp;gt;&#039;&lt;br /&gt;
&lt;br /&gt;
cnx = pyodbc.connect(dsn,autocommit=True)&lt;br /&gt;
cursor = cnx.cursor()&lt;br /&gt;
&lt;br /&gt;
query = &#039;show databases&#039;&lt;br /&gt;
&lt;br /&gt;
result = cursor.execute(query)&lt;br /&gt;
columnnames = [e[0] for e in cursor.description]&lt;br /&gt;
for row in result:&lt;br /&gt;
    field1 = row[0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Works with [[Pandas#Reading Data|pandas.read_sql]] too.&lt;br /&gt;
&lt;br /&gt;
= MySqlAlchemy =&lt;br /&gt;
&lt;br /&gt;
For more information check the sqlalchemy.org basic usage page[https://docs.sqlalchemy.org/en/11/core/connections.html#basic-usage].&lt;br /&gt;
&lt;br /&gt;
Very basic example for mysql with the pymysql module&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import pymysql&lt;br /&gt;
import sqlalchemy&lt;br /&gt;
&lt;br /&gt;
dbconnect = &#039;mysql+pymysql://user:password@databaseserver/databasename&#039;&lt;br /&gt;
&lt;br /&gt;
engine = sqlalchemy.create_engine(dbconnect)&lt;br /&gt;
&lt;br /&gt;
query = &#039;select something from table&#039;&lt;br /&gt;
result = engine.execute(query)&lt;br /&gt;
for row in result:&lt;br /&gt;
    field1 = row[0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Python:Databases&amp;diff=1700</id>
		<title>Python:Databases</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Python:Databases&amp;diff=1700"/>
		<updated>2026-01-14T13:55:45Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* mariadb */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
= MySQL Connector =&lt;br /&gt;
&lt;br /&gt;
See below for an example script&lt;br /&gt;
&lt;br /&gt;
;import mysql.connector&lt;br /&gt;
:Load module for mysql &lt;br /&gt;
&lt;br /&gt;
;cnx = mysql.connector.connect(**cnxconfig)&lt;br /&gt;
:Open MySQL database as defined in the cnxconfig dictionary. See example below. The ** passes the dictionary unpacked to a function.&lt;br /&gt;
&lt;br /&gt;
;import cx_Oracle&lt;br /&gt;
:Load module for oracle &lt;br /&gt;
&lt;br /&gt;
;cnx = cx_Oracle.connect(user=dbuser, password=dbpasswd, dsn=dbtns_alias)&lt;br /&gt;
:Open Oracle database.&lt;br /&gt;
&lt;br /&gt;
;cnx.commit()&lt;br /&gt;
:Commit all open transactions to the database&lt;br /&gt;
 &lt;br /&gt;
;cursor = cnx.cursor()&lt;br /&gt;
:Create a cursor that returns rows as [[Python:DataTypes#Tuple | tuple]]&lt;br /&gt;
&lt;br /&gt;
;cursor = cnx.cursor(dictionary=True)&lt;br /&gt;
:Create a cursor that returns rows as [[Python:DataTypes#Dictionary_or_dict | dictionary]] { column1: value1, column2: value2 }&lt;br /&gt;
&lt;br /&gt;
;cursor = cnx.cursor(buffered=True)&lt;br /&gt;
:Create a cursor that retrieves the complete result at once so you can check rowcount immediately. Beware of overloading your memory if you expect large results. &lt;br /&gt;
&lt;br /&gt;
;cursor.execute(query)&lt;br /&gt;
:Execute &#039;query&#039;. Traverse the cursor to fetch the data. The cursor returns a tuple for each row by default.&amp;lt;br&amp;gt;&lt;br /&gt;
:;cursor.rowcount&lt;br /&gt;
::The number of rows fetched (SELECT) or affected (INSERT,UPDATE) by this query.&lt;br /&gt;
:;cursor.column_names&lt;br /&gt;
::The columnnames &lt;br /&gt;
&lt;br /&gt;
;cursor.fetchone()&lt;br /&gt;
:Return the next row from the cursor result.&lt;br /&gt;
&lt;br /&gt;
;cursor.fetchmany(size=2)&lt;br /&gt;
:Return the first two rows of the result in a list.&lt;br /&gt;
&lt;br /&gt;
;cursor.fetchall()&lt;br /&gt;
:Return all (remaining) rows of the result in a list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for row in cursor:&lt;br /&gt;
 print(row)&lt;br /&gt;
 for column in row:&lt;br /&gt;
 	print(column)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;cursor.close()&lt;br /&gt;
:Close the cursor&lt;br /&gt;
;cnx.close()&lt;br /&gt;
:Close the database connection&lt;br /&gt;
&lt;br /&gt;
Code example showing all:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import mysql.connector &lt;br /&gt;
&lt;br /&gt;
cnxconfig = {&lt;br /&gt;
    &#039;host&#039;: &#039;hostname&#039;,&lt;br /&gt;
    &#039;port&#039;: 3306,&lt;br /&gt;
    &#039;user&#039;: &#039;username&#039;,&lt;br /&gt;
    &#039;password&#039;: &#039;&#039;,&lt;br /&gt;
    &#039;database&#039;: &#039;DBname&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#cnx = mysql.connector.connect(host=&#039;hostname&#039;, port=3306, user=&#039;username&#039;, database=&#039;DBname&#039;)&lt;br /&gt;
cnx = mysql.connector.connect(**cnxconfig)&lt;br /&gt;
&lt;br /&gt;
if cnx:&lt;br /&gt;
	print(&amp;quot;Connection, continue&amp;quot;)&lt;br /&gt;
else:&lt;br /&gt;
	print(&amp;quot;No connection, exit&amp;quot;)&lt;br /&gt;
	exit()&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;Tuple cursor&amp;quot;)	&lt;br /&gt;
cursor = cnx.cursor()&lt;br /&gt;
&lt;br /&gt;
query = (&amp;quot;SELECT * FROM table&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
cursor.execute(query)&lt;br /&gt;
for columname in cursor.column_names:&lt;br /&gt;
 print(columname)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
 print(row)&lt;br /&gt;
 for column in row:&lt;br /&gt;
 	print(column)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;Dictionary cursor&amp;quot;)&lt;br /&gt;
cursor = cnx.cursor(dictionary=True)&lt;br /&gt;
cursor.execute(query)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
	for columname in row.keys():&lt;br /&gt;
		print(&amp;quot;{0:25s}: {1:}&amp;quot;.format(columname, row[columname])) &lt;br /&gt;
&lt;br /&gt;
cursor.close()&lt;br /&gt;
cnx.close()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=mariadb=&lt;br /&gt;
The mariadb module[https://mariadb.com/docs/connectors/mariadb-connector-python] works almost the same as the mysql.connecctor above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import mariadb&lt;br /&gt;
&lt;br /&gt;
# Connection parameters&lt;br /&gt;
config = {&lt;br /&gt;
    &#039;host&#039;: &#039;xxx&#039;,&lt;br /&gt;
    &#039;port&#039;: 3306,&lt;br /&gt;
    &#039;user&#039;: &#039;user&#039;,&lt;br /&gt;
    &#039;password&#039;: &#039;password&#039;,&lt;br /&gt;
    &#039;database&#039;: &#039;db&#039; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Connect to MariaDB&lt;br /&gt;
conn = mariadb.connect(**config)&lt;br /&gt;
cursor = conn.cursor()&lt;br /&gt;
cursor.execute(&amp;lt;query&amp;gt;)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
    print(row)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rows are tuples with a counter (id) as first element. &amp;lt;code&amp;gt;&#039;dictionary&#039;: True&amp;lt;/code&amp;gt; in the connection config should return dictionaries&lt;br /&gt;
;cursor.description&lt;br /&gt;
:Spec of the tuples in cursor&lt;br /&gt;
;cursor.metadata[&#039;field&#039;]&lt;br /&gt;
:The fields in the cursor&lt;br /&gt;
&lt;br /&gt;
= ODBC connections =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import pyodbc&lt;br /&gt;
&lt;br /&gt;
dsn = &#039;DSN=&amp;lt;name of ODBC-DNS&amp;gt;&#039;&lt;br /&gt;
&lt;br /&gt;
cnx = pyodbc.connect(dsn,autocommit=True)&lt;br /&gt;
cursor = cnx.cursor()&lt;br /&gt;
&lt;br /&gt;
query = &#039;show databases&#039;&lt;br /&gt;
&lt;br /&gt;
result = cursor.execute(query)&lt;br /&gt;
columnnames = [e[0] for e in cursor.description]&lt;br /&gt;
for row in result:&lt;br /&gt;
    field1 = row[0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Works with [[Pandas#Reading Data|pandas.read_sql]] too.&lt;br /&gt;
&lt;br /&gt;
= MySqlAlchemy =&lt;br /&gt;
&lt;br /&gt;
For more information check the sqlalchemy.org basic usage page[https://docs.sqlalchemy.org/en/11/core/connections.html#basic-usage].&lt;br /&gt;
&lt;br /&gt;
Very basic example for mysql with the pymysql module&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import pymysql&lt;br /&gt;
import sqlalchemy&lt;br /&gt;
&lt;br /&gt;
dbconnect = &#039;mysql+pymysql://user:password@databaseserver/databasename&#039;&lt;br /&gt;
&lt;br /&gt;
engine = sqlalchemy.create_engine(dbconnect)&lt;br /&gt;
&lt;br /&gt;
query = &#039;select something from table&#039;&lt;br /&gt;
result = engine.execute(query)&lt;br /&gt;
for row in result:&lt;br /&gt;
    field1 = row[0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Python:Databases&amp;diff=1699</id>
		<title>Python:Databases</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Python:Databases&amp;diff=1699"/>
		<updated>2026-01-14T13:53:32Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Python]]&lt;br /&gt;
= MySQL Connector =&lt;br /&gt;
&lt;br /&gt;
See below for an example script&lt;br /&gt;
&lt;br /&gt;
;import mysql.connector&lt;br /&gt;
:Load module for mysql &lt;br /&gt;
&lt;br /&gt;
;cnx = mysql.connector.connect(**cnxconfig)&lt;br /&gt;
:Open MySQL database as defined in the cnxconfig dictionary. See example below. The ** passes the dictionary unpacked to a function.&lt;br /&gt;
&lt;br /&gt;
;import cx_Oracle&lt;br /&gt;
:Load module for oracle &lt;br /&gt;
&lt;br /&gt;
;cnx = cx_Oracle.connect(user=dbuser, password=dbpasswd, dsn=dbtns_alias)&lt;br /&gt;
:Open Oracle database.&lt;br /&gt;
&lt;br /&gt;
;cnx.commit()&lt;br /&gt;
:Commit all open transactions to the database&lt;br /&gt;
 &lt;br /&gt;
;cursor = cnx.cursor()&lt;br /&gt;
:Create a cursor that returns rows as [[Python:DataTypes#Tuple | tuple]]&lt;br /&gt;
&lt;br /&gt;
;cursor = cnx.cursor(dictionary=True)&lt;br /&gt;
:Create a cursor that returns rows as [[Python:DataTypes#Dictionary_or_dict | dictionary]] { column1: value1, column2: value2 }&lt;br /&gt;
&lt;br /&gt;
;cursor = cnx.cursor(buffered=True)&lt;br /&gt;
:Create a cursor that retrieves the complete result at once so you can check rowcount immediately. Beware of overloading your memory if you expect large results. &lt;br /&gt;
&lt;br /&gt;
;cursor.execute(query)&lt;br /&gt;
:Execute &#039;query&#039;. Traverse the cursor to fetch the data. The cursor returns a tuple for each row by default.&amp;lt;br&amp;gt;&lt;br /&gt;
:;cursor.rowcount&lt;br /&gt;
::The number of rows fetched (SELECT) or affected (INSERT,UPDATE) by this query.&lt;br /&gt;
:;cursor.column_names&lt;br /&gt;
::The columnnames &lt;br /&gt;
&lt;br /&gt;
;cursor.fetchone()&lt;br /&gt;
:Return the next row from the cursor result.&lt;br /&gt;
&lt;br /&gt;
;cursor.fetchmany(size=2)&lt;br /&gt;
:Return the first two rows of the result in a list.&lt;br /&gt;
&lt;br /&gt;
;cursor.fetchall()&lt;br /&gt;
:Return all (remaining) rows of the result in a list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
for row in cursor:&lt;br /&gt;
 print(row)&lt;br /&gt;
 for column in row:&lt;br /&gt;
 	print(column)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;cursor.close()&lt;br /&gt;
:Close the cursor&lt;br /&gt;
;cnx.close()&lt;br /&gt;
:Close the database connection&lt;br /&gt;
&lt;br /&gt;
Code example showing all:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import mysql.connector &lt;br /&gt;
&lt;br /&gt;
cnxconfig = {&lt;br /&gt;
    &#039;host&#039;: &#039;hostname&#039;,&lt;br /&gt;
    &#039;port&#039;: 3306,&lt;br /&gt;
    &#039;user&#039;: &#039;username&#039;,&lt;br /&gt;
    &#039;password&#039;: &#039;&#039;,&lt;br /&gt;
    &#039;database&#039;: &#039;DBname&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#cnx = mysql.connector.connect(host=&#039;hostname&#039;, port=3306, user=&#039;username&#039;, database=&#039;DBname&#039;)&lt;br /&gt;
cnx = mysql.connector.connect(**cnxconfig)&lt;br /&gt;
&lt;br /&gt;
if cnx:&lt;br /&gt;
	print(&amp;quot;Connection, continue&amp;quot;)&lt;br /&gt;
else:&lt;br /&gt;
	print(&amp;quot;No connection, exit&amp;quot;)&lt;br /&gt;
	exit()&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;Tuple cursor&amp;quot;)	&lt;br /&gt;
cursor = cnx.cursor()&lt;br /&gt;
&lt;br /&gt;
query = (&amp;quot;SELECT * FROM table&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
cursor.execute(query)&lt;br /&gt;
for columname in cursor.column_names:&lt;br /&gt;
 print(columname)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
 print(row)&lt;br /&gt;
 for column in row:&lt;br /&gt;
 	print(column)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;Dictionary cursor&amp;quot;)&lt;br /&gt;
cursor = cnx.cursor(dictionary=True)&lt;br /&gt;
cursor.execute(query)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
	for columname in row.keys():&lt;br /&gt;
		print(&amp;quot;{0:25s}: {1:}&amp;quot;.format(columname, row[columname])) &lt;br /&gt;
&lt;br /&gt;
cursor.close()&lt;br /&gt;
cnx.close()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=mariadb=&lt;br /&gt;
The mariadb module works almost the same as the mysql.connecctor above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import mariadb&lt;br /&gt;
&lt;br /&gt;
# Connection parameters&lt;br /&gt;
config = {&lt;br /&gt;
    &#039;host&#039;: &#039;xxx&#039;,&lt;br /&gt;
    &#039;port&#039;: 3306,&lt;br /&gt;
    &#039;user&#039;: &#039;user&#039;,&lt;br /&gt;
    &#039;password&#039;: &#039;password&#039;,&lt;br /&gt;
    &#039;database&#039;: &#039;db&#039; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Connect to MariaDB&lt;br /&gt;
conn = mariadb.connect(**config)&lt;br /&gt;
cursor = conn.cursor()&lt;br /&gt;
cursor.execute(&amp;lt;query&amp;gt;)&lt;br /&gt;
for row in cursor:&lt;br /&gt;
    print(row)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rows are tuples with a counter (id) as first element. &amp;lt;code&amp;gt;&#039;dictionary&#039;: True&amp;lt;/code&amp;gt; in the connection config should return dictionaries&lt;br /&gt;
;cursor.description&lt;br /&gt;
:Spec of the tuples in cursor&lt;br /&gt;
;cursor.metadata[&#039;field&#039;]&lt;br /&gt;
:The fields in the cursor&lt;br /&gt;
&lt;br /&gt;
= ODBC connections =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import pyodbc&lt;br /&gt;
&lt;br /&gt;
dsn = &#039;DSN=&amp;lt;name of ODBC-DNS&amp;gt;&#039;&lt;br /&gt;
&lt;br /&gt;
cnx = pyodbc.connect(dsn,autocommit=True)&lt;br /&gt;
cursor = cnx.cursor()&lt;br /&gt;
&lt;br /&gt;
query = &#039;show databases&#039;&lt;br /&gt;
&lt;br /&gt;
result = cursor.execute(query)&lt;br /&gt;
columnnames = [e[0] for e in cursor.description]&lt;br /&gt;
for row in result:&lt;br /&gt;
    field1 = row[0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Works with [[Pandas#Reading Data|pandas.read_sql]] too.&lt;br /&gt;
&lt;br /&gt;
= MySqlAlchemy =&lt;br /&gt;
&lt;br /&gt;
For more information check the sqlalchemy.org basic usage page[https://docs.sqlalchemy.org/en/11/core/connections.html#basic-usage].&lt;br /&gt;
&lt;br /&gt;
Very basic example for mysql with the pymysql module&lt;br /&gt;
&amp;lt;syntaxhighlight lang=python&amp;gt;&lt;br /&gt;
import pymysql&lt;br /&gt;
import sqlalchemy&lt;br /&gt;
&lt;br /&gt;
dbconnect = &#039;mysql+pymysql://user:password@databaseserver/databasename&#039;&lt;br /&gt;
&lt;br /&gt;
engine = sqlalchemy.create_engine(dbconnect)&lt;br /&gt;
&lt;br /&gt;
query = &#039;select something from table&#039;&lt;br /&gt;
result = engine.execute(query)&lt;br /&gt;
for row in result:&lt;br /&gt;
    field1 = row[0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Podman&amp;diff=1698</id>
		<title>Podman</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Podman&amp;diff=1698"/>
		<updated>2026-01-14T12:50:06Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Linux/Unix]]&lt;br /&gt;
Podman is used to create containers, like [[Docker]]. In a container system resources are separated from each other e.g. to create a development environment where the developer can experiment freely without the risk of jeopardizing the host system.&lt;br /&gt;
&lt;br /&gt;
The main difference is podman does not need a daemon like docker. It is lighter and more secure [https://www.geeksforgeeks.org/devops/podman-vs-docker/#podman-vs-docker-a-detailed-comparison]&lt;br /&gt;
&lt;br /&gt;
A containerfile defines what will be in the podman image, running the image will create a container.&lt;br /&gt;
&lt;br /&gt;
Podman containterfiles have the same syntax as dockerfiles. The podman build command looks first for Containerfile and then for Dockerfile in the specified directory.&lt;br /&gt;
&lt;br /&gt;
=Basics=&lt;br /&gt;
;apt install podman&lt;br /&gt;
:Install podman&lt;br /&gt;
&lt;br /&gt;
;This containerfile creates a working container with a python virtual environment&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
FROM debian&lt;br /&gt;
LABEL name=&amp;quot;Hans de Ridder&amp;quot;&lt;br /&gt;
RUN apt-get update&lt;br /&gt;
RUN apt-get -y install python3-full&lt;br /&gt;
RUN python3 -m venv /home/ubuntu/venv&lt;br /&gt;
ENV PATH=&amp;quot;/home/ubuntu/venv/bin:$PATH&amp;quot;&lt;br /&gt;
RUN pip install pandas&lt;br /&gt;
CMD [&amp;quot;echo&amp;quot;, &amp;quot;I&#039;m alive&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;podman build -t &amp;lt;name&amp;gt;:&amp;lt;tag&amp;gt; &amp;lt;directory&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:This builds the image with a name and a tag&lt;br /&gt;
;podman pull &amp;lt;registry image&amp;gt;&lt;br /&gt;
:Create an image from the registry image (see [[#FROM]])&lt;br /&gt;
&lt;br /&gt;
;podman image ls&lt;br /&gt;
:List all existing images&lt;br /&gt;
;podman  image inspect &amp;lt;image ID&amp;gt;&lt;br /&gt;
:Return the whole image specification as json-string&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;podman run -v &amp;lt;hostdir&amp;gt;:&amp;lt;containerdir&amp;gt; --rm -it &amp;lt;image ID&amp;gt; bash&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Create the container and open a bash prompt in it (as root user). When leaving the shell the container is closed&lt;br /&gt;
:This way you can run any command in a container that only exists while the command is running.&lt;br /&gt;
:&amp;lt;hostdir&amp;gt; is mounted on &amp;lt;containerdir&amp;gt; which will be created automatically.&lt;br /&gt;
:NOTE: &amp;lt;hostdir&amp;gt; should not be a NFS filesystem, the container has no access to that.&lt;br /&gt;
;podman run -it --network=host &amp;lt;image ID&amp;gt;&lt;br /&gt;
:You will enter the container with the network settings (interface, hostname,...) from the host system. This enables mailing from the container.&lt;br /&gt;
;podman run --rm &amp;lt;image ID&amp;gt; &amp;lt;command&amp;gt;&lt;br /&gt;
:Run &amp;lt;command&amp;gt; in the container, remove the container on exit,&lt;br /&gt;
;podman exec -it &amp;lt;containerid&amp;gt; &amp;lt;command&amp;gt;&lt;br /&gt;
:Run &amp;lt;command&amp;gt; in a running container, -it is needed for interactive commands like bash&lt;br /&gt;
;podman stop &amp;lt;containerID&amp;gt;&lt;br /&gt;
:Stop a container&lt;br /&gt;
;podman rm &amp;lt;containerID&amp;gt;&lt;br /&gt;
:Remove a container&lt;br /&gt;
;podman image rm &amp;lt;imageID&amp;gt;&lt;br /&gt;
:Remove an image&lt;br /&gt;
&lt;br /&gt;
;podman ps -a&lt;br /&gt;
:List all containers&lt;br /&gt;
&lt;br /&gt;
;podman system prune&lt;br /&gt;
:Delete unused images and build caches&lt;br /&gt;
;podman system prune -a&lt;br /&gt;
:Delete unused images and all build caches&lt;br /&gt;
&lt;br /&gt;
=Containerfile commands=&lt;br /&gt;
&lt;br /&gt;
==FROM==&lt;br /&gt;
;FROM &amp;lt;Imagelocation&amp;gt;&lt;br /&gt;
:Specifies what is the base-image. Images are on a registry server like docker.io. You can use aliases like ubuntu or debian but that is not advised as you cannot be 100% sure where the images will be coming from. Therefor it is advised to user the full image path like docker.io/library/debian&lt;br /&gt;
;podman search docker.io/library/nginx&lt;br /&gt;
:List all images for nginx&lt;br /&gt;
&lt;br /&gt;
==RUN==&lt;br /&gt;
;RUN &amp;lt;command&amp;gt;&lt;br /&gt;
:Specify a command to run when the images is build. You can have a whole lot of these.&lt;br /&gt;
&lt;br /&gt;
==CMD==&lt;br /&gt;
;CMD &amp;lt;command&amp;gt;&lt;br /&gt;
:Command to run when the container starts&lt;br /&gt;
&lt;br /&gt;
==LABEL==&lt;br /&gt;
;LABEL name=&amp;quot;My Name&amp;quot;&lt;br /&gt;
:Give the container a label. You can have several labels of a container.&lt;br /&gt;
&lt;br /&gt;
==COPY==&lt;br /&gt;
;COPY &amp;lt;localfile&amp;gt; &amp;lt;containerpath&amp;gt;&lt;br /&gt;
:Copy &amp;lt;localfile&amp;gt;, that must be in Containerfile directory, to &amp;lt;containerpath&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
=Full-fledged container=&lt;br /&gt;
&lt;br /&gt;
==Containerfile==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
FROM docker.io/library/debian&lt;br /&gt;
LABEL name=&amp;quot;Full-fledged debian image&amp;quot;&lt;br /&gt;
LABEL maintainer=&amp;quot;Hans de Ridder&amp;quot;&lt;br /&gt;
RUN apt-get update&lt;br /&gt;
RUN apt-get -y install less joe vim exim4 procps&lt;br /&gt;
RUN apt-get -y install python3-full&lt;br /&gt;
RUN python3 -m venv /opt/python/venv&lt;br /&gt;
ENV PATH=&amp;quot;/opt/python/venv/bin:$PATH&amp;quot;&lt;br /&gt;
RUN pip install pandas&lt;br /&gt;
COPY update-exim4.conf.conf /etc/exim4/&lt;br /&gt;
RUN update-exim4.conf&lt;br /&gt;
CMD [&amp;quot;bash&amp;quot;, &amp;quot;-i&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
;podman build -t debian &amp;lt;directory&amp;gt;&lt;br /&gt;
:Build the image&lt;br /&gt;
;podman run -it --name FF &amp;lt;image ID&amp;gt;&lt;br /&gt;
:You will enter the container.&lt;br /&gt;
;podman start -ia FF&lt;br /&gt;
:Re-enter the container after you left it. If the container is already running you will be in the same shell.&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Find&amp;diff=1697</id>
		<title>Find</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Find&amp;diff=1697"/>
		<updated>2026-01-13T13:10:58Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Linux/Unix]]&lt;br /&gt;
Find things in a directory tree&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;directory&amp;gt; -type f -name &#039;&amp;lt;pattern&amp;gt;&#039; &amp;lt;/code&amp;gt;&lt;br /&gt;
:Find files in and below &amp;lt;directory&amp;gt; that match &amp;lt;pattern&amp;gt;. Type f is for files, d for directory&#039;s, no type finds all.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find -L &amp;lt;directory&amp;gt;&#039; &amp;lt;/code&amp;gt;&lt;br /&gt;
:Do follow symbolic links, default behavior is not to follow.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;directory&amp;gt; -xdev -name &amp;lt;pattern&amp;gt;&#039; &amp;lt;/code&amp;gt;&lt;br /&gt;
:Limit the search to the current file-system, do not go into mounted filesystems.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;directory&amp;gt; -type f -name &#039;&amp;lt;pattern&amp;gt;&#039; -execdir &amp;lt;command&amp;gt; {} \;&amp;lt;/code&amp;gt;&lt;br /&gt;
:For each file found execute &amp;lt;command&amp;gt; in the directory containing the file. {} represents the found file. NOTE!! Do not forget the \; at the end.&lt;br /&gt;
: -exec works too but is less secure as mistakes main lead to execution in an unexpected place.&lt;br /&gt;
: If more commands need to be executed specify -exec &amp;lt;command&amp;gt; {} \;  for each command.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;directory&amp;gt; -type f -mtime 1 &amp;lt;/code&amp;gt;&lt;br /&gt;
:Find files modified 1 day ago (between 24 and 48 hours).&lt;br /&gt;
:Negative numbers find all files modified max 1 day ago.&lt;br /&gt;
:Positive numbers (explicitly signed with +) find all files at modified at least 1 day ago.&lt;br /&gt;
:&amp;lt;code&amp;gt;-mmin&amp;lt;/code&amp;gt; counts minutes instead of days.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;directory&amp;gt; -type f -newer &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Find files modified after the modification time of &amp;lt;filename&amp;gt;&lt;br /&gt;
:You can set the modification time of &amp;lt;filename&amp;gt; like &amp;lt;code&amp;gt;touch -t YYYYmmddHHMM &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;directory&amp;gt; -type f -printf &#039;%T@ %p\n&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Print the files modification times in [https://www.epochconverter.com/ epoch] (seconds since Jan 1, 1970) and the filename. Can be used e.g. to find the last files modified (with sort -n  and tail)&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;dir&amp;gt; -printf &#039;%s %p\n&#039;| sort -nr | head -10&amp;lt;/code&amp;gt;&lt;br /&gt;
:Find the top 10 largest files under a directory&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;dir&amp;gt; -type f -mtime +30 -ls|awk &#039;BEGIN {} {totsize+=$7} END { print totsize/1000000}&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Find the total size of all files older than 30 days.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;dir&amp;gt; -type f -inum &amp;lt;inode number&amp;gt; -delete&amp;lt;/code&amp;gt;&lt;br /&gt;
:Find file by inode number and delete it. This can be used to removed files with weird names. This does not delete the inode, if files have more hardlinks all must be deleted.&lt;br /&gt;
&lt;br /&gt;
Other options to select specific files are (among many others):&lt;br /&gt;
 -user  (username)&lt;br /&gt;
 -uid   (user id)&lt;br /&gt;
 -group (group name)&lt;br /&gt;
 -gid   (group id)&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;find &amp;lt;dir&amp;gt; -depth -type d -empty -delete&amp;lt;/code&amp;gt;&lt;br /&gt;
:Find empty directories and delete them&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Nftables&amp;diff=1696</id>
		<title>Nftables</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Nftables&amp;diff=1696"/>
		<updated>2026-01-12T21:31:16Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:networking]]&lt;br /&gt;
[[category:Linux/Unix]]&lt;br /&gt;
nftables is the successor of [[iptables]] for managing firewall rules.&lt;br /&gt;
&lt;br /&gt;
At first glance [https://wiki.debian.org/nftables] it looks a bit like a [[iptables#ufw|ufw]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:35%&amp;quot;&lt;br /&gt;
|+ Address families&lt;br /&gt;
! Family&lt;br /&gt;
! Remark&lt;br /&gt;
|-&lt;br /&gt;
| ip&lt;br /&gt;
| IPv4 This is the default if no family is specified&lt;br /&gt;
|-&lt;br /&gt;
| ip6&lt;br /&gt;
| IPv6&lt;br /&gt;
|-&lt;br /&gt;
| inet&lt;br /&gt;
| IPv4 + IPv6&lt;br /&gt;
|-&lt;br /&gt;
| arp&lt;br /&gt;
| arp&lt;br /&gt;
|-&lt;br /&gt;
| bridge&lt;br /&gt;
| bridge&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Install and activate=&lt;br /&gt;
Debian comes with nftables installed since Buster.&lt;br /&gt;
;apt install nftables&lt;br /&gt;
:Install if needed&lt;br /&gt;
;systemctl enable nftables.service&lt;br /&gt;
:Create the service&lt;br /&gt;
;systemctl start nftables&lt;br /&gt;
;service nftables start&lt;br /&gt;
:Start the service&lt;br /&gt;
;systemctl status nftables&lt;br /&gt;
;service nftables status&lt;br /&gt;
:Show status&lt;br /&gt;
&lt;br /&gt;
=Confiuration=&lt;br /&gt;
The configuration is in /etc/nftables.conf&lt;br /&gt;
&lt;br /&gt;
=Commands=&lt;br /&gt;
;nft list table &amp;lt;family&amp;gt; filter&lt;br /&gt;
:Show the current filters for &amp;lt;family&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Ubuntu&amp;diff=1695</id>
		<title>Ubuntu</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Ubuntu&amp;diff=1695"/>
		<updated>2026-01-07T21:48:21Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* NetworkManager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Linux/Unix]]&lt;br /&gt;
[https://www.ubuntu.com/ Ubuntu] is a linux distribution derived from [https://www.debian.org/ debian]. It&#039;s a very nice plug&amp;amp;play OS with all features I need.&lt;br /&gt;
&lt;br /&gt;
;cat /etc/os-release&lt;br /&gt;
;cat /etc/lsb-release&lt;br /&gt;
;lsb_release -a&lt;br /&gt;
:Show the currently installed version. os-release has most information.&lt;br /&gt;
&lt;br /&gt;
==Modfications made==&lt;br /&gt;
&lt;br /&gt;
The few things I needed to tweak are listed here.&lt;br /&gt;
&lt;br /&gt;
===NetworkManager===&lt;br /&gt;
&lt;br /&gt;
[[NetworkManager]] is a bad idea, just use &amp;lt;code&amp;gt;/etc/network/[[Networking#Interfaces|interfaces]]&amp;lt;/code&amp;gt; and /etc/resolv.conf to configure your network. Having a DHCP server to supply network configuration is fine, everything else is making things complex. &lt;br /&gt;
&lt;br /&gt;
* Make sure you have ifupdown installed&lt;br /&gt;
* Edit /etc/network/interface. See [[Networking#Interfaces]].&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt-get purge network-manager&amp;lt;/code&amp;gt;&lt;br /&gt;
* If installed uninstall openresolv&lt;br /&gt;
These 2 needed to be done on a raspberry pi running debian buster&lt;br /&gt;
* uninstall wicd&lt;br /&gt;
* disable avahi  (systemctl disable avahi-daemon)&lt;br /&gt;
&lt;br /&gt;
===Snap===&lt;br /&gt;
Another bad and confusing idea is snap. E.g. [[Jupyter]] I could not get working the way I want it with the Jupyter snap.&lt;br /&gt;
Remove it like described by [https://techwiser.com/remove-snap-ubuntu/ techwiser].&lt;br /&gt;
First remove all snaps, then removed snap itself and make sure it will not reappear.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
snap list&lt;br /&gt;
snap remove --purge &amp;lt;package-name&amp;gt;&lt;br /&gt;
rm -rf /var/cache/snapd/&lt;br /&gt;
apt autoremove --purge snapd gnome-software-plugin-snap&lt;br /&gt;
rm -fr ~/snap&lt;br /&gt;
apt-mark hold snapd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When using this anyhow. Some snaps (like firefox) may send daily warnings an update is pending. For some reason this does not happen automatically and you need to execute &amp;lt;code&amp;gt;sudo snap refresh&amp;lt;/code&amp;gt; to do the update.&lt;br /&gt;
&lt;br /&gt;
The snap-store cannot be updated from the ubuntu software catalog as the process is running always. To update:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;snap-store --quit &amp;amp;&amp;amp; sudo snap refresh snap-store&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Settings GUI===&lt;br /&gt;
&lt;br /&gt;
One day I could not start the settings GUI anymore. &lt;br /&gt;
Removing the unity-control-center fixed the problem one time. On another install it didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sudo apt-get remove unity-control-center&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
When I connect a monitor to my laptop on HDMI automatically a 3&amp;lt;sup&amp;gt;rd&amp;lt;/sup&amp;gt; VGA display is found.&lt;br /&gt;
;xrandr --listactivemonitors&lt;br /&gt;
:Show all active monitors&lt;br /&gt;
&lt;br /&gt;
;xrandr --output VGA-1-2 --off&lt;br /&gt;
:Turn off the VGA display. The name may differ on other configurations.&lt;br /&gt;
&lt;br /&gt;
===Slow boot===&lt;br /&gt;
# If /var/log/syslog is full of messages like &#039;&amp;lt;code&amp;gt;failed to bind to /tmp/.X11-unix/X....&amp;lt;/code&amp;gt;&#039;, make sure / is owned by root.&lt;br /&gt;
# Check [[Networking#Interfaces]] for allow-hotplug&lt;br /&gt;
&lt;br /&gt;
===Tracker===&lt;br /&gt;
Tracker is a part of nautilus scanning your filesystem. I don´t need that.&lt;br /&gt;
 apt purge nautilus&lt;br /&gt;
 apt install thunar&lt;br /&gt;
&lt;br /&gt;
===Get a visible border on the gnome terminal===&lt;br /&gt;
 vi .config/gtk-3.0/gtk.css&lt;br /&gt;
&lt;br /&gt;
 terminal-window notebook {&lt;br /&gt;
   border-width: 0px 1px 1px 1px;&lt;br /&gt;
   border-style: solid;&lt;br /&gt;
   border-color: grey;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 terminal-window.maximized notebook,&lt;br /&gt;
   terminal-window.fullscreen notebook {&lt;br /&gt;
   border-style: none;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Application management==&lt;br /&gt;
&lt;br /&gt;
;apt install &amp;lt;package&amp;gt;&lt;br /&gt;
:Install a new package&lt;br /&gt;
;apt remove --purge &amp;lt;package&amp;gt;&lt;br /&gt;
:Remove a package and all related files&lt;br /&gt;
;apt update&lt;br /&gt;
;apt full-upgrade&lt;br /&gt;
:Update the package meta-data and update all&lt;br /&gt;
;apt-mark hold &amp;lt;package&amp;gt;&lt;br /&gt;
:Prevent updates of &amp;lt;package&amp;gt;, they will be show as upgradable by &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt; but will be held back by &amp;lt;code&amp;gt;apt (full-)upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
;apt-mark unhold &amp;lt;package&amp;gt;&lt;br /&gt;
:Allow updates on &amp;lt;package&amp;gt; again&lt;br /&gt;
;apt-mark showhold&lt;br /&gt;
:SHow all packages that are held back&lt;br /&gt;
&lt;br /&gt;
;apt-get autoclean&lt;br /&gt;
:Remove all obsolete package files from /var/cache/apt/archives. Do this every now and then&lt;br /&gt;
&lt;br /&gt;
;do-release-upgrade&lt;br /&gt;
:Upgrade to the latest Ubuntu release, latest LTS if that is what you run.&lt;br /&gt;
&lt;br /&gt;
;dpkg -i &amp;lt;packagefile&amp;gt;&lt;br /&gt;
:Install from the packagefile &lt;br /&gt;
&lt;br /&gt;
====apt update reports NO PUBKEY====&lt;br /&gt;
When apt update reports things like: &amp;quot;The following signatures couldn&#039;t be verified because the public key is not available: NO_PUBKEY [KEY_ID]&amp;quot; you can repair as described on linuxblog.io[https://linuxblog.io/how-to-fix-gpg-no_pubkey-error-the-following-signatures-couldnt-be/]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys [KEY_ID]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then store it in you keyrings directory&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;gpg --export [KEY_ID] | sudo tee /etc/apt/keyrings/ubuntu.gpg &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In /apt/sources.d/xxxxx.list make sure &#039;Signed By&#039; points to the .gpg file or to have &#039;[signed-by=/etc/apt/keyrings/ubuntu.gpg]&#039; when you have a 1-line source file&lt;br /&gt;
&lt;br /&gt;
The same thing works for Debian too. I would expect Debian a keyserver of its own but I&#039;ve not found it yet.&lt;br /&gt;
&lt;br /&gt;
===Add applications===&lt;br /&gt;
To add an application to the &#039;Open with&#039; list edit /usr/share/applications/&amp;lt;newapp&amp;gt;.desktop.&lt;br /&gt;
&lt;br /&gt;
For opening jupyter notebooks I added jupyter.desktop that looks like below.&lt;br /&gt;
I don&#039;t think everything is needed but it works. &lt;br /&gt;
&lt;br /&gt;
 [Desktop Entry]&lt;br /&gt;
 Type=Application&lt;br /&gt;
 Version=1.0&lt;br /&gt;
 Name=Jupyter&lt;br /&gt;
 GenericName=Jupyter notebook&lt;br /&gt;
 Comment=Prototyping and documentation &lt;br /&gt;
 Exec=jupyter notebook %F&lt;br /&gt;
 Icon=jupyter&lt;br /&gt;
 Terminal=false&lt;br /&gt;
 Categories=GTK;Development;IDE;&lt;br /&gt;
 MimeType=text/plain;text/x-python;&lt;br /&gt;
 StartupNotify=true&lt;br /&gt;
 Keywords=Python;Editor;&lt;br /&gt;
&lt;br /&gt;
===Autostart applications===&lt;br /&gt;
To automatically start an application when a user logs in put a link to /usr/share/applications/&amp;lt;newapp&amp;gt;.desktop or a new &amp;lt;newapp&amp;gt;.desktop in ~/.config/autostart&lt;br /&gt;
&lt;br /&gt;
===Problem upgrading package like &#039;errors were encountered while processing&#039;===&lt;br /&gt;
It is pretty old but some good hints can be found on [https://journalxtra.com/linux/fixing-the-dreaded-errors-were-encountered-while-processing-errors/ journalxtra.com]&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Ubuntu&amp;diff=1694</id>
		<title>Ubuntu</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Ubuntu&amp;diff=1694"/>
		<updated>2026-01-07T19:43:13Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Linux/Unix]]&lt;br /&gt;
[https://www.ubuntu.com/ Ubuntu] is a linux distribution derived from [https://www.debian.org/ debian]. It&#039;s a very nice plug&amp;amp;play OS with all features I need.&lt;br /&gt;
&lt;br /&gt;
;cat /etc/os-release&lt;br /&gt;
;cat /etc/lsb-release&lt;br /&gt;
;lsb_release -a&lt;br /&gt;
:Show the currently installed version. os-release has most information.&lt;br /&gt;
&lt;br /&gt;
==Modfications made==&lt;br /&gt;
&lt;br /&gt;
The few things I needed to tweak are listed here.&lt;br /&gt;
&lt;br /&gt;
===NetworkManager===&lt;br /&gt;
&lt;br /&gt;
[[NetworkManager]] is a bad idea, just use &amp;lt;code&amp;gt;/etc/network/[[Networking#Interfaces|interfaces]]&amp;lt;/code&amp;gt; and /etc/resolv.conf to configure your network. Having a DHCP server to supply network configuration is fine, everything else is making things complex. You may need to install ifupdown and disable the netplan thing to achieve this.&lt;br /&gt;
* sudo apt-get purge network-manager&lt;br /&gt;
* Uninstall dhcpcd&lt;br /&gt;
* Uninstall openresolv&lt;br /&gt;
These 2 needed to be done on a raspberry pi running debian buster&lt;br /&gt;
* uninstall wicd&lt;br /&gt;
* disable avahi  (systemctl disable avahi-daemon)&lt;br /&gt;
&lt;br /&gt;
===Snap===&lt;br /&gt;
Another bad and confusing idea is snap. E.g. [[Jupyter]] I could not get working the way I want it with the Jupyter snap.&lt;br /&gt;
Remove it like described by [https://techwiser.com/remove-snap-ubuntu/ techwiser].&lt;br /&gt;
First remove all snaps, then removed snap itself and make sure it will not reappear.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
snap list&lt;br /&gt;
snap remove --purge &amp;lt;package-name&amp;gt;&lt;br /&gt;
rm -rf /var/cache/snapd/&lt;br /&gt;
apt autoremove --purge snapd gnome-software-plugin-snap&lt;br /&gt;
rm -fr ~/snap&lt;br /&gt;
apt-mark hold snapd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When using this anyhow. Some snaps (like firefox) may send daily warnings an update is pending. For some reason this does not happen automatically and you need to execute &amp;lt;code&amp;gt;sudo snap refresh&amp;lt;/code&amp;gt; to do the update.&lt;br /&gt;
&lt;br /&gt;
The snap-store cannot be updated from the ubuntu software catalog as the process is running always. To update:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;snap-store --quit &amp;amp;&amp;amp; sudo snap refresh snap-store&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Settings GUI===&lt;br /&gt;
&lt;br /&gt;
One day I could not start the settings GUI anymore. &lt;br /&gt;
Removing the unity-control-center fixed the problem one time. On another install it didn&#039;t.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sudo apt-get remove unity-control-center&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
When I connect a monitor to my laptop on HDMI automatically a 3&amp;lt;sup&amp;gt;rd&amp;lt;/sup&amp;gt; VGA display is found.&lt;br /&gt;
;xrandr --listactivemonitors&lt;br /&gt;
:Show all active monitors&lt;br /&gt;
&lt;br /&gt;
;xrandr --output VGA-1-2 --off&lt;br /&gt;
:Turn off the VGA display. The name may differ on other configurations.&lt;br /&gt;
&lt;br /&gt;
===Slow boot===&lt;br /&gt;
# If /var/log/syslog is full of messages like &#039;&amp;lt;code&amp;gt;failed to bind to /tmp/.X11-unix/X....&amp;lt;/code&amp;gt;&#039;, make sure / is owned by root.&lt;br /&gt;
# Check [[Networking#Interfaces]] for allow-hotplug&lt;br /&gt;
&lt;br /&gt;
===Tracker===&lt;br /&gt;
Tracker is a part of nautilus scanning your filesystem. I don´t need that.&lt;br /&gt;
 apt purge nautilus&lt;br /&gt;
 apt install thunar&lt;br /&gt;
&lt;br /&gt;
===Get a visible border on the gnome terminal===&lt;br /&gt;
 vi .config/gtk-3.0/gtk.css&lt;br /&gt;
&lt;br /&gt;
 terminal-window notebook {&lt;br /&gt;
   border-width: 0px 1px 1px 1px;&lt;br /&gt;
   border-style: solid;&lt;br /&gt;
   border-color: grey;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 terminal-window.maximized notebook,&lt;br /&gt;
   terminal-window.fullscreen notebook {&lt;br /&gt;
   border-style: none;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Application management==&lt;br /&gt;
&lt;br /&gt;
;apt install &amp;lt;package&amp;gt;&lt;br /&gt;
:Install a new package&lt;br /&gt;
;apt remove --purge &amp;lt;package&amp;gt;&lt;br /&gt;
:Remove a package and all related files&lt;br /&gt;
;apt update&lt;br /&gt;
;apt full-upgrade&lt;br /&gt;
:Update the package meta-data and update all&lt;br /&gt;
;apt-mark hold &amp;lt;package&amp;gt;&lt;br /&gt;
:Prevent updates of &amp;lt;package&amp;gt;, they will be show as upgradable by &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt; but will be held back by &amp;lt;code&amp;gt;apt (full-)upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
;apt-mark unhold &amp;lt;package&amp;gt;&lt;br /&gt;
:Allow updates on &amp;lt;package&amp;gt; again&lt;br /&gt;
;apt-mark showhold&lt;br /&gt;
:SHow all packages that are held back&lt;br /&gt;
&lt;br /&gt;
;apt-get autoclean&lt;br /&gt;
:Remove all obsolete package files from /var/cache/apt/archives. Do this every now and then&lt;br /&gt;
&lt;br /&gt;
;do-release-upgrade&lt;br /&gt;
:Upgrade to the latest Ubuntu release, latest LTS if that is what you run.&lt;br /&gt;
&lt;br /&gt;
;dpkg -i &amp;lt;packagefile&amp;gt;&lt;br /&gt;
:Install from the packagefile &lt;br /&gt;
&lt;br /&gt;
====apt update reports NO PUBKEY====&lt;br /&gt;
When apt update reports things like: &amp;quot;The following signatures couldn&#039;t be verified because the public key is not available: NO_PUBKEY [KEY_ID]&amp;quot; you can repair as described on linuxblog.io[https://linuxblog.io/how-to-fix-gpg-no_pubkey-error-the-following-signatures-couldnt-be/]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys [KEY_ID]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then store it in you keyrings directory&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;gpg --export [KEY_ID] | sudo tee /etc/apt/keyrings/ubuntu.gpg &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In /apt/sources.d/xxxxx.list make sure &#039;Signed By&#039; points to the .gpg file or to have &#039;[signed-by=/etc/apt/keyrings/ubuntu.gpg]&#039; when you have a 1-line source file&lt;br /&gt;
&lt;br /&gt;
The same thing works for Debian too. I would expect Debian a keyserver of its own but I&#039;ve not found it yet.&lt;br /&gt;
&lt;br /&gt;
===Add applications===&lt;br /&gt;
To add an application to the &#039;Open with&#039; list edit /usr/share/applications/&amp;lt;newapp&amp;gt;.desktop.&lt;br /&gt;
&lt;br /&gt;
For opening jupyter notebooks I added jupyter.desktop that looks like below.&lt;br /&gt;
I don&#039;t think everything is needed but it works. &lt;br /&gt;
&lt;br /&gt;
 [Desktop Entry]&lt;br /&gt;
 Type=Application&lt;br /&gt;
 Version=1.0&lt;br /&gt;
 Name=Jupyter&lt;br /&gt;
 GenericName=Jupyter notebook&lt;br /&gt;
 Comment=Prototyping and documentation &lt;br /&gt;
 Exec=jupyter notebook %F&lt;br /&gt;
 Icon=jupyter&lt;br /&gt;
 Terminal=false&lt;br /&gt;
 Categories=GTK;Development;IDE;&lt;br /&gt;
 MimeType=text/plain;text/x-python;&lt;br /&gt;
 StartupNotify=true&lt;br /&gt;
 Keywords=Python;Editor;&lt;br /&gt;
&lt;br /&gt;
===Autostart applications===&lt;br /&gt;
To automatically start an application when a user logs in put a link to /usr/share/applications/&amp;lt;newapp&amp;gt;.desktop or a new &amp;lt;newapp&amp;gt;.desktop in ~/.config/autostart&lt;br /&gt;
&lt;br /&gt;
===Problem upgrading package like &#039;errors were encountered while processing&#039;===&lt;br /&gt;
It is pretty old but some good hints can be found on [https://journalxtra.com/linux/fixing-the-dreaded-errors-were-encountered-while-processing-errors/ journalxtra.com]&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=NetworkManager&amp;diff=1693</id>
		<title>NetworkManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=NetworkManager&amp;diff=1693"/>
		<updated>2026-01-07T19:40:49Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Linux/Unix]]&lt;br /&gt;
[[Category:Networking]]&lt;br /&gt;
I prefer using old style network configuration as described in [[Networking#Interfaces]]. How to disable it is described in [[Ubuntu#NetworkManager]].&lt;br /&gt;
&lt;br /&gt;
Some distributions come with NetworkManager that provides a working standard configuration. If you want to use it, here some tricks to do non-standard things with it.&lt;br /&gt;
&lt;br /&gt;
Configuration is stored in /etc/NetworkManager/system-connections/ in a file per connection.&lt;br /&gt;
&lt;br /&gt;
To specify addresses use below. In the ipv6 section put auto to have the full SLAAC configurationon the interfaces to. With manual only the addresses specified and the routes provided my Route Advertisement are configured. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
[ipv4]&lt;br /&gt;
address1=&amp;lt;CIDR&amp;gt;, &amp;lt;gateway&amp;gt;&lt;br /&gt;
dns=&amp;lt;DNSserverIP&amp;gt;;&lt;br /&gt;
dns-search=&amp;lt;search domain&amp;gt;;&lt;br /&gt;
method=manual&lt;br /&gt;
&lt;br /&gt;
[ipv6]&lt;br /&gt;
addr-gen-mode=default&lt;br /&gt;
address1=&amp;lt;CIDR&amp;gt;,&amp;lt;gateway&amp;gt;&lt;br /&gt;
dns=&amp;lt;DNSserverIP&amp;gt;;&lt;br /&gt;
dns-search=&amp;lt;serach domain&amp;gt;;&lt;br /&gt;
method=auto&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=IPv4&amp;diff=1692</id>
		<title>IPv4</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=IPv4&amp;diff=1692"/>
		<updated>2026-01-04T21:15:37Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: Created page with &amp;quot;Category:networking Category:Linux/Unix IPv4 is the original addressing scheme for IP networks.  IPv4 addresses are 32 bits long so that is some more than 4 billion addresses. That is a lot but not enough when everything that needs communication get at least 1 address. That is why IPv6 has been invented that has 128 bit addresses that is really a lot (3.402823669×10³⁸)   An address looks like aaa.bbb.ccc.xxx  The netmask defines how many addresses are wit...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:networking]]&lt;br /&gt;
[[Category:Linux/Unix]]&lt;br /&gt;
IPv4 is the original addressing scheme for IP networks.&lt;br /&gt;
&lt;br /&gt;
IPv4 addresses are 32 bits long so that is some more than 4 billion addresses. That is a lot but not enough when everything that needs communication get at least 1 address. That is why [[IPv6]] has been invented that has 128 bit addresses that is really a lot (3.402823669×10³⁸) &lt;br /&gt;
&lt;br /&gt;
An address looks like aaa.bbb.ccc.xxx&lt;br /&gt;
&lt;br /&gt;
The netmask defines how many addresses are within the subnet and where packets are routed to. Addresses within the subnet are routed to the interface, address outside the subnet to the default gateway (router). &lt;br /&gt;
Net netmask is traditionally expressed in the same format as an address (e.g. 255.255.255.0), later CIDR was invented that just specified the number of bits that specify the subnetwork.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class &lt;br /&gt;
! Addresses&lt;br /&gt;
! Netmask&lt;br /&gt;
! CIDR&lt;br /&gt;
! Remark&lt;br /&gt;
|-&lt;br /&gt;
| A&lt;br /&gt;
| style=&amp;quot;text-align:right&amp;quot;| 1-126.xxx.xxx.xxx&lt;br /&gt;
| 255.0.0.0&lt;br /&gt;
| /8&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| A private&lt;br /&gt;
| style=&amp;quot;text-align:right&amp;quot;| 10.xxx.xxx.xxx&lt;br /&gt;
| 255.0.0.0&lt;br /&gt;
| /8&lt;br /&gt;
| Private range, not routed&lt;br /&gt;
|-&lt;br /&gt;
| B&lt;br /&gt;
| style=&amp;quot;text-align:right&amp;quot;| 128-191.xxx.xxx.xxx&lt;br /&gt;
| 255.255.0.0&lt;br /&gt;
| /16&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| B private&lt;br /&gt;
| style=&amp;quot;text-align:right&amp;quot;| 172.16-31.xxx.xxx&lt;br /&gt;
| 255.255.0.0&lt;br /&gt;
| /16&lt;br /&gt;
| Private, not routed&lt;br /&gt;
|-&lt;br /&gt;
| C&lt;br /&gt;
| 192-223.xxx.xxx.xxx&lt;br /&gt;
| 255.255.255.0&lt;br /&gt;
| /24&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| C private&lt;br /&gt;
| style=&amp;quot;text-align:right&amp;quot;| 192.168-xxx.xxx&lt;br /&gt;
| 255.255.255.0&lt;br /&gt;
| /24&lt;br /&gt;
| Private, not routed&lt;br /&gt;
|-&lt;br /&gt;
| D&lt;br /&gt;
| style=&amp;quot;text-align:right&amp;quot;| 224-239.xxx.xxx.xxx&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| Multicasting addresses, not for host assignment&lt;br /&gt;
|-&lt;br /&gt;
| E&lt;br /&gt;
| style=&amp;quot;text-align:right&amp;quot;| 240-255.xxx.xxx.xxx&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| Reserved addresses, not for public use&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=IPv6&amp;diff=1691</id>
		<title>IPv6</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=IPv6&amp;diff=1691"/>
		<updated>2026-01-04T20:32:03Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:networking]]&lt;br /&gt;
[[Category:Linux/Unix]]&lt;br /&gt;
Testing your IPv6 connection:&lt;br /&gt;
;https://ifconfig.co/&lt;br /&gt;
:Including CLI-support&lt;br /&gt;
;https://ready.chair6.net/&lt;br /&gt;
:Nice as simple interface&lt;br /&gt;
;https://test-ipv6.com/&lt;br /&gt;
Testing website security and connectivity&lt;br /&gt;
;https://internet.nl&lt;br /&gt;
&lt;br /&gt;
Below seems to be broken December 2025&lt;br /&gt;
;https://ipv6-test.com/&lt;br /&gt;
:Check your IPv6 configuration&lt;br /&gt;
;http://ipv6-test.com/validate.php&lt;br /&gt;
:Check IPv6 support for websites&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Address Assignment==&lt;br /&gt;
&lt;br /&gt;
The [http://www.iana.org/assignments/ipv6-address-space IPv6 address assignment] is handled by IANA. Most important prefixes are:&lt;br /&gt;
&amp;lt;table class=&amp;quot;plain&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;2000::/3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Global Unicast&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Global scope&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;FC00::/7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Unique Local Unicast&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Local Unicast. For intranets, not routed, like IPv4 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. Currently FC00::/8 is undefined, only FD00::/8 is used&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;FE80::/10&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Link Local Unicast&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Link Identification, addresses can be based on the interface MAC address&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;FF00::/8&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Multicast&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Local Unicast (ULA)==&lt;br /&gt;
Users were advised to generate a 40 bits Global ID for their intranets but it is unclear if there a valid use case for it[[https://en.wikipedia.org/wiki/Unique_local_address]]. It is advised to calculate the Global Id using a specified procedure to maximize the probability of an unique address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;[http://tools.ietf.org/html/rfc4193#section-3.2 Local Unicast Address-format]:&amp;lt;/strong&amp;gt;&lt;br /&gt;
&amp;lt;table&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt; &lt;br /&gt;
&amp;lt;th align=left&amp;gt;Prefix&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;th align=left&amp;gt;L&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;th align=left&amp;gt;Global ID&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;th align=left&amp;gt;Subnet ID&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;th align=left&amp;gt;Interface ID&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;7 bits&amp;lt;br /&amp;gt;&lt;br /&gt;
FC00::/7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;1 bit&amp;lt;br /&amp;gt;&lt;br /&gt;
Locally assigned&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;40 bits&amp;lt;br /&amp;gt;&lt;br /&gt;
User defined&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;16 bits&amp;lt;br /&amp;gt;&lt;br /&gt;
Local subnet&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;64 bits&amp;lt;br /&amp;gt;&lt;br /&gt;
Locally assigned or by dhcp&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;1111110&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
The Interface ID is in the so-called &amp;amp;#8216;Modified EUI-64 Format&amp;amp;#8217;. How to go from a MAC address to Modified EUI-64 format is described in appendix A of [href=&amp;quot;http://tools.ietf.org/html/rfc4291 RFC 4291]. When using ULA prefixes you must have Routing Advertising (radvd) to tell the network it should configure addresses and routes for it&lt;br /&gt;
&lt;br /&gt;
==Route Advertisement==&lt;br /&gt;
Provides information for &amp;amp;#8216;Stateless Autoconfiguration&amp;amp;#8217; to the local nodes.&lt;br /&gt;
&lt;br /&gt;
IPv6 systems can send a Route Solicitation (RS) messages. These are answered by a Route Advertisement (RA) message that tells with prefixes exist and, when needed where the gateway for that prefix is. The client then can configure IPv6 addresses and routes. &lt;br /&gt;
&lt;br /&gt;
On linux systems there is the radvd deamon to provide RA.&lt;br /&gt;
&lt;br /&gt;
To advertise there is a ULA prefix in the network put this in /etc/radvd.conf&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
interface eth0&lt;br /&gt;
{&lt;br /&gt;
    AdvSendAdvert on;&lt;br /&gt;
    AdvDefaultLifetime 0;&lt;br /&gt;
    prefix fdxx:xx:xx::/48&lt;br /&gt;
    {&lt;br /&gt;
    };&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Disable IPv6 on a system==&lt;br /&gt;
&lt;br /&gt;
At the end of &amp;lt;code&amp;gt;/etc/sysctl.conf&amp;lt;/code&amp;gt; add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
net.ipv6.conf.all.disable_ipv6 = 1&lt;br /&gt;
net.ipv6.conf.default.disable_ipv6 = 1&lt;br /&gt;
net.ipv6.conf.lo.disable_ipv6 = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;sysctl -p&lt;br /&gt;
:Force reload of the kernel parameters as in /etc/sysctl.conf&lt;br /&gt;
&lt;br /&gt;
;cat /proc/sys/net/ipv6/conf/all/disable_ipv6&lt;br /&gt;
:Check if IPv6 has been disabled:&lt;br /&gt;
:0 =&amp;gt; IPv6 is not disabled&lt;br /&gt;
:1 =&amp;gt; IPv6 is disabled&lt;br /&gt;
&lt;br /&gt;
==Check IPv6 autoconfiguration==&lt;br /&gt;
;&amp;lt;code&amp;gt;cat /proc/sys/net/ipv6/conf/eth0/autoconf&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 =&amp;gt; autoconf is disabled&lt;br /&gt;
:1 =&amp;gt; autoconf is enabled&lt;br /&gt;
&lt;br /&gt;
==Misc commands==&lt;br /&gt;
&lt;br /&gt;
;/sbin/ip -6 addr del &amp;lt;ipv6address&amp;gt;/&amp;lt;prefixlength&amp;gt; dev &amp;lt;interface&amp;gt;&lt;br /&gt;
:Remove ipv6 addres from an interface&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Dhcp&amp;diff=1690</id>
		<title>Dhcp</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Dhcp&amp;diff=1690"/>
		<updated>2026-01-04T20:31:35Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:networking]]&lt;br /&gt;
[[Category:Linux/Unix]]&lt;br /&gt;
Dynamic Host Configuration Protocol&lt;br /&gt;
&lt;br /&gt;
Provide IP addresses for your network from a central server.&lt;br /&gt;
==IPv6==&lt;br /&gt;
&lt;br /&gt;
[[IPv6]] addresses can be advertised by the radvd (often on your ISP&#039;s router). These are based on the MAC address of the client or pseudo randomly generated. For more control over the addresses you can run a dhcp server. When the [https://www.isc.org/dhcp/ ISC dhcp server] is used you need separate instances for the IPv4 and the IPv6 server.&lt;br /&gt;
&lt;br /&gt;
=KEA=&lt;br /&gt;
KEA is the successor of the isc-dhcp-server.&lt;br /&gt;
;apt install kea&lt;br /&gt;
:Install all packages for the KEA-server&lt;br /&gt;
&lt;br /&gt;
=isc-dhcp-server=&lt;br /&gt;
Sample configuration file (/etc/dhcp/dhcpd6.conf).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
log-facility local7;&lt;br /&gt;
default-lease-time 86400;&lt;br /&gt;
max-lease-time 604800;&lt;br /&gt;
&lt;br /&gt;
subnet6 your:site:ipv6:prefix::/64 {&lt;br /&gt;
#  range6 your:ipv6:prefix:address:1::f000 your:ipv6:prefix:address:1::ffff;&lt;br /&gt;
&lt;br /&gt;
  option dhcp6.domain-search &amp;quot;local.domain.tld&amp;quot;;&lt;br /&gt;
  option dhcp6.name-servers &amp;lt;name-server-address&amp;gt;;&lt;br /&gt;
  option ntp-servers ntp.domain.tld;&lt;br /&gt;
&lt;br /&gt;
  host host1name {&lt;br /&gt;
   host-identifier option dhcp6.client-id 00:a4:00:01:45:26:4d:8e:98:8e:76:d1:09:32;&lt;br /&gt;
   fixed-address6 &amp;lt;full ipv6-address&amp;gt;;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hosts for fixed addresses are found by their DUID. Only way I know to find it on the server is from the logfile (/var/log/syslog). On the client it is in var/lib/dhcpcd/duid&lt;br /&gt;
 &lt;br /&gt;
The firewall on the client needs to be open on the Link Local address (in the FE80::/10) range on port 546&lt;br /&gt;
&lt;br /&gt;
==IPv4==&lt;br /&gt;
Sample configuration file (/etc/dhcp/dhcpd.conf).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
ddns-update-style none;&lt;br /&gt;
&lt;br /&gt;
# option definitions common to all supported networks.&lt;br /&gt;
option domain-name &amp;quot;domain.tld&amp;quot;;&lt;br /&gt;
option domain-name-servers 192.168.1.2, 208.67.222.222;&lt;br /&gt;
option routers 192.168.1.254;&lt;br /&gt;
option broadcast-address 192.168.1.255;&lt;br /&gt;
option ntp-servers 192.168.1.4;&lt;br /&gt;
&lt;br /&gt;
# 1 day (fine for home networks, e.g. hotspots should have far shorter lease times) &lt;br /&gt;
default-lease-time 86400;&lt;br /&gt;
# 1 week&lt;br /&gt;
max-lease-time 604800;&lt;br /&gt;
&lt;br /&gt;
authoritative;&lt;br /&gt;
&lt;br /&gt;
log-facility local7;&lt;br /&gt;
&lt;br /&gt;
# Known hosts get fixed IP address defined in DNS-server&lt;br /&gt;
group {&lt;br /&gt;
 deny unknown-clients;&lt;br /&gt;
 # One week, these are sort of fixed addresses.&lt;br /&gt;
 default-lease-time 604800;&lt;br /&gt;
&lt;br /&gt;
 host host1name {&lt;br /&gt;
  hardware ethernet ff:ff:ff:ff:ff:ff;&lt;br /&gt;
  fixed-address host1name.domain.tld;&lt;br /&gt;
 }&lt;br /&gt;
 host host2name {&lt;br /&gt;
  hardware ethernet ff:ff:ff:ff:ff:ff;&lt;br /&gt;
  fixed-address host2name.domain.tld;&lt;br /&gt;
 }&lt;br /&gt;
}&lt;br /&gt;
# All other get an address from the range&lt;br /&gt;
subnet 192.168.1.0 netmask 255.255.255.0 {&lt;br /&gt;
 range 192.168.1.100 192.168.1.199;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The leases are kept track of in /var/lib/dhcp/dhcpd.leases&lt;br /&gt;
An ordinary entry looks like:&lt;br /&gt;
tstp and cltt are for the failover protocol, most other entries are self-explaining I think.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
lease 192.168.1.133 {&lt;br /&gt;
  starts 6 2021/03/18 11:22:00;&lt;br /&gt;
  ends 0 2021/03/19 11:22:00;&lt;br /&gt;
  tstp 0 2021/03/19 11:22:00;&lt;br /&gt;
  cltt 6 2021/03/19 11:22:00;&lt;br /&gt;
  binding state active;&lt;br /&gt;
  next binding state free;&lt;br /&gt;
  rewind binding state free;&lt;br /&gt;
  hardware ethernet ff:ff:ff:ff:ff:ff;&lt;br /&gt;
  client-hostname &amp;quot;host3name&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=DHCP clients=&lt;br /&gt;
;dhcpcd -k &amp;lt;interface&amp;gt;&lt;br /&gt;
:Release lease&lt;br /&gt;
;dhcpcd -n &amp;lt;interface&amp;gt;&lt;br /&gt;
:Renew lease&lt;br /&gt;
&lt;br /&gt;
=Traffic check=&lt;br /&gt;
;tcpdump -i eth0 port 547&lt;br /&gt;
:Check on server side&lt;br /&gt;
;tcpdump -i eth0 port 546&lt;br /&gt;
:Check on client side&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Networking&amp;diff=1689</id>
		<title>Networking</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Networking&amp;diff=1689"/>
		<updated>2026-01-04T20:17:29Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:networking]]&lt;br /&gt;
[[Category:Linux/Unix]]&lt;br /&gt;
&lt;br /&gt;
=Basics=&lt;br /&gt;
For IP networks there are 2 address schemes, [[IPv4]] and [[IPv6]]&lt;br /&gt;
;ping &amp;lt;address&amp;gt;&lt;br /&gt;
:Get response from &amp;lt;address&amp;gt; interface&lt;br /&gt;
;&amp;lt;code&amp;gt;for i in $(seq 1 254); do ping -c1 -t 1 10.117.192.$i; done&amp;lt;/code&amp;gt;&lt;br /&gt;
:Scan a subnet&lt;br /&gt;
&lt;br /&gt;
=Check network connectivity=&lt;br /&gt;
&lt;br /&gt;
;netstat -na  # deprecated&lt;br /&gt;
;ss -na &lt;br /&gt;
:Show port status (LISTEN, ESTABLISHED, .....)&lt;br /&gt;
:If you are root -p adds the process that owns the socket&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;nc -v -z &amp;lt;host&amp;gt; &amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Netcat: Tell me if we can open a connection to &amp;lt;host&amp;gt; on &amp;lt;port&amp;gt;. Without -z it works like telnet&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;nc -v -u -z &amp;lt;host&amp;gt; &amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Tell me if we can open a connection to &amp;lt;host&amp;gt; on a UDP &amp;lt;port&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;curl -vvv -k  --proxy1.0 &amp;lt;proxyIP&amp;gt;:&amp;lt;proxyPort&amp;gt; &amp;lt;Remote URL&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Get the data from &amp;lt;remote URL&amp;gt; via &amp;lt;proxyIP&amp;gt; -k allows insecure SSL connections&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;curl -vvv telnet://&amp;lt;IP&amp;gt;:&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Just test connectivity to a port&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=$1&lt;br /&gt;
&lt;br /&gt;
TARGETS=&amp;quot;999.999.999.999&lt;br /&gt;
888.888.888.888&lt;br /&gt;
777.777.777.777&lt;br /&gt;
666.666.666.666&lt;br /&gt;
&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for TARGET in ${TARGETS}&lt;br /&gt;
do&lt;br /&gt;
  curl  http://${TARGET}:${PORT} --connect-timeout 1 &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
  if [ $? == 28 ]    # 28 is the curl code for connection timeout&lt;br /&gt;
   then&lt;br /&gt;
    echo No connection to ${TARGET}:${PORT}&lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Interfaces=&lt;br /&gt;
;ifconfig -a   # Deprecated, replaced by ip&lt;br /&gt;
:Show all network interfaces&lt;br /&gt;
&lt;br /&gt;
;ifconfig &amp;lt;interface&amp;gt; &amp;lt;ipaddress&amp;gt;&lt;br /&gt;
:Assign &amp;lt;ipaddress&amp;gt; to &amp;lt;interface&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;ip address&lt;br /&gt;
:Show all IP addresses&lt;br /&gt;
;ip -6 address&lt;br /&gt;
:Show all IPv6 addresses&lt;br /&gt;
&lt;br /&gt;
;ip -6 addr add &amp;lt;ipv6address&amp;gt;/&amp;lt;prefixlength&amp;gt; dev &amp;lt;interface&amp;gt;&lt;br /&gt;
:Add an IPv6 address to &amp;lt;interface&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;mii-tool &amp;lt;interface&amp;gt;&lt;br /&gt;
:Show interface link status (speed)&lt;br /&gt;
&lt;br /&gt;
When not using confusing things like [[NetworkManager]] network configuration is controlled by the interfaces file.&lt;br /&gt;
;/etc/network/interfaces&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
auto &amp;lt;interface&amp;gt;             # Boot process waits until the interface is up or a time-out (5 minutes)&lt;br /&gt;
allow-hotplug &amp;lt;interface&amp;gt;    # Boot process does not wait for the interface.&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet dhcp&lt;br /&gt;
    wpa-ssid &amp;lt;ssid&amp;gt;&lt;br /&gt;
    wpa-psk &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# For static ipv4&lt;br /&gt;
interface &amp;lt;interface&amp;gt; inet static&lt;br /&gt;
    address xxx.xxx.xxx.xxx/&amp;lt;masklen&amp;gt;&lt;br /&gt;
    gateway xxx.xxx.xxx.xxx&lt;br /&gt;
# To have ipv6 auto-configured (by SLAAC)&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet6 auto&lt;br /&gt;
&lt;br /&gt;
# To have ipv6 auto-configured (by SLAAC) and add own address&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet6 static&lt;br /&gt;
    address unique:local:address:prefix:your:own:host:address&lt;br /&gt;
    autoconf 1&lt;br /&gt;
    netmask 64&lt;br /&gt;
&lt;br /&gt;
# Add another address to &amp;lt;interface&amp;gt;(work for IPv4 addresses too&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet6 static&lt;br /&gt;
    address unique:local:address:prefix:your:own:host:address&lt;br /&gt;
    netmask 64&lt;br /&gt;
&lt;br /&gt;
# To have ipv6 auto-configured (by SLAAC) and query a dhcp-server&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet6 dhcp&lt;br /&gt;
    autoconf 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Disable an interface completely (even not shown by ifconfig)&lt;br /&gt;
:vi /etc/modprobe.d/blackllst.conf&lt;br /&gt;
:Put in the driver for your interface like: &amp;lt;code&amp;gt;blacklist ath9k&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Wireless=&lt;br /&gt;
;iwscan &amp;lt;interface&amp;gt; scanning&lt;br /&gt;
:Show available accesspoints&lt;br /&gt;
;iwconfig &amp;lt;interface&amp;gt;&lt;br /&gt;
:Show details of the wireless connection&lt;br /&gt;
&lt;br /&gt;
=Routing=&lt;br /&gt;
;route add -net default gw &amp;lt;IPaddress&amp;gt;  # Deprecated&lt;br /&gt;
;ip route add -net default gw &amp;lt;IPaddress&amp;gt; &lt;br /&gt;
:Add a default route using &amp;lt;IPaddress&amp;gt;  as gateway&lt;br /&gt;
&lt;br /&gt;
=Tunneling=&lt;br /&gt;
;&amp;lt;code&amp;gt;ssh -L 8080:remotehost:3006 proxy&amp;lt;/code&amp;gt;&lt;br /&gt;
:Login over ssh to proxy and there connect to remotehost port 3006. Connect local port 8080 to the remote connection.&lt;br /&gt;
:Now if you connect to port 8080 on your local server you are connected to port 3006 on the remotehost&lt;br /&gt;
:Using &amp;lt;code&amp;gt;-nNT&amp;lt;/code&amp;gt; prevents that the ssh command opens a terminal on the proxy. The ssh command however must remain active.&lt;br /&gt;
&lt;br /&gt;
=Tracing=&lt;br /&gt;
For tracing traffic see [[Tcpdump]]&lt;br /&gt;
&lt;br /&gt;
;traceroute &amp;lt;destination&amp;gt;&lt;br /&gt;
:Show which route a package takes to reach destination&lt;br /&gt;
&lt;br /&gt;
;ip route get &amp;lt;IPaddress&amp;gt;&lt;br /&gt;
:Show the interface used to go to &amp;lt;IPaddress&amp;gt;&lt;br /&gt;
To get just the interface name you can use this[https://unix.stackexchange.com/questions/14961/how-to-find-out-which-interface-am-i-using-for-connecting-to-the-internet]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
host=&amp;lt;fqdn&amp;gt;&lt;br /&gt;
host_ip=$(getent ahosts &amp;quot;$host&amp;quot; | awk &#039;{print $1; exit}&#039;)&lt;br /&gt;
ip route get &amp;quot;$host_ip&amp;quot; | grep -Po &#039;(?&amp;lt;=(dev ))(\S+)&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Other=&lt;br /&gt;
;&amp;lt;code&amp;gt;wget &amp;lt;URL&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Get the data from &amp;lt;URL&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Networking&amp;diff=1688</id>
		<title>Networking</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Networking&amp;diff=1688"/>
		<updated>2026-01-04T20:12:10Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* Interfaces */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:networking]]&lt;br /&gt;
[[Category:Linux/Unix]]&lt;br /&gt;
&lt;br /&gt;
=Basics=&lt;br /&gt;
;ping &amp;lt;address&amp;gt;&lt;br /&gt;
:Get response from &amp;lt;address&amp;gt; interface&lt;br /&gt;
;&amp;lt;code&amp;gt;for i in $(seq 1 254); do ping -c1 -t 1 10.117.192.$i; done&amp;lt;/code&amp;gt;&lt;br /&gt;
:Scan a subnet&lt;br /&gt;
&lt;br /&gt;
=Check network connectivity=&lt;br /&gt;
&lt;br /&gt;
;netstat -na  # deprecated&lt;br /&gt;
;ss -na &lt;br /&gt;
:Show port status (LISTEN, ESTABLISHED, .....)&lt;br /&gt;
:If you are root -p adds the process that owns the socket&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;nc -v -z &amp;lt;host&amp;gt; &amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Netcat: Tell me if we can open a connection to &amp;lt;host&amp;gt; on &amp;lt;port&amp;gt;. Without -z it works like telnet&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;nc -v -u -z &amp;lt;host&amp;gt; &amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Tell me if we can open a connection to &amp;lt;host&amp;gt; on a UDP &amp;lt;port&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;curl -vvv -k  --proxy1.0 &amp;lt;proxyIP&amp;gt;:&amp;lt;proxyPort&amp;gt; &amp;lt;Remote URL&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Get the data from &amp;lt;remote URL&amp;gt; via &amp;lt;proxyIP&amp;gt; -k allows insecure SSL connections&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;curl -vvv telnet://&amp;lt;IP&amp;gt;:&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Just test connectivity to a port&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=$1&lt;br /&gt;
&lt;br /&gt;
TARGETS=&amp;quot;999.999.999.999&lt;br /&gt;
888.888.888.888&lt;br /&gt;
777.777.777.777&lt;br /&gt;
666.666.666.666&lt;br /&gt;
&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for TARGET in ${TARGETS}&lt;br /&gt;
do&lt;br /&gt;
  curl  http://${TARGET}:${PORT} --connect-timeout 1 &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
  if [ $? == 28 ]    # 28 is the curl code for connection timeout&lt;br /&gt;
   then&lt;br /&gt;
    echo No connection to ${TARGET}:${PORT}&lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Interfaces=&lt;br /&gt;
;ifconfig -a   # Deprecated, replaced by ip&lt;br /&gt;
:Show all network interfaces&lt;br /&gt;
&lt;br /&gt;
;ifconfig &amp;lt;interface&amp;gt; &amp;lt;ipaddress&amp;gt;&lt;br /&gt;
:Assign &amp;lt;ipaddress&amp;gt; to &amp;lt;interface&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;ip address&lt;br /&gt;
:Show all IP addresses&lt;br /&gt;
;ip -6 address&lt;br /&gt;
:Show all IPv6 addresses&lt;br /&gt;
&lt;br /&gt;
;ip -6 addr add &amp;lt;ipv6address&amp;gt;/&amp;lt;prefixlength&amp;gt; dev &amp;lt;interface&amp;gt;&lt;br /&gt;
:Add an IPv6 address to &amp;lt;interface&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;mii-tool &amp;lt;interface&amp;gt;&lt;br /&gt;
:Show interface link status (speed)&lt;br /&gt;
&lt;br /&gt;
When not using confusing things like [[NetworkManager]] network configuration is controlled by the interfaces file.&lt;br /&gt;
;/etc/network/interfaces&lt;br /&gt;
&amp;lt;syntaxhighlight lang=text&amp;gt;&lt;br /&gt;
auto &amp;lt;interface&amp;gt;             # Boot process waits until the interface is up or a time-out (5 minutes)&lt;br /&gt;
allow-hotplug &amp;lt;interface&amp;gt;    # Boot process does not wait for the interface.&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet dhcp&lt;br /&gt;
    wpa-ssid &amp;lt;ssid&amp;gt;&lt;br /&gt;
    wpa-psk &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# For static ipv4&lt;br /&gt;
interface &amp;lt;interface&amp;gt; inet static&lt;br /&gt;
    address xxx.xxx.xxx.xxx/&amp;lt;masklen&amp;gt;&lt;br /&gt;
    gateway xxx.xxx.xxx.xxx&lt;br /&gt;
# To have ipv6 auto-configured (by SLAAC)&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet6 auto&lt;br /&gt;
&lt;br /&gt;
# To have ipv6 auto-configured (by SLAAC) and add own address&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet6 static&lt;br /&gt;
    address unique:local:address:prefix:your:own:host:address&lt;br /&gt;
    autoconf 1&lt;br /&gt;
    netmask 64&lt;br /&gt;
&lt;br /&gt;
# Add another address to &amp;lt;interface&amp;gt;(work for IPv4 addresses too&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet6 static&lt;br /&gt;
    address unique:local:address:prefix:your:own:host:address&lt;br /&gt;
    netmask 64&lt;br /&gt;
&lt;br /&gt;
# To have ipv6 auto-configured (by SLAAC) and query a dhcp-server&lt;br /&gt;
iface &amp;lt;interface&amp;gt; inet6 dhcp&lt;br /&gt;
    autoconf 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Disable an interface completely (even not shown by ifconfig)&lt;br /&gt;
:vi /etc/modprobe.d/blackllst.conf&lt;br /&gt;
:Put in the driver for your interface like: &amp;lt;code&amp;gt;blacklist ath9k&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Wireless=&lt;br /&gt;
;iwscan &amp;lt;interface&amp;gt; scanning&lt;br /&gt;
:Show available accesspoints&lt;br /&gt;
;iwconfig &amp;lt;interface&amp;gt;&lt;br /&gt;
:Show details of the wireless connection&lt;br /&gt;
&lt;br /&gt;
=Routing=&lt;br /&gt;
;route add -net default gw &amp;lt;IPaddress&amp;gt;  # Deprecated&lt;br /&gt;
;ip route add -net default gw &amp;lt;IPaddress&amp;gt; &lt;br /&gt;
:Add a default route using &amp;lt;IPaddress&amp;gt;  as gateway&lt;br /&gt;
&lt;br /&gt;
=Tunneling=&lt;br /&gt;
;&amp;lt;code&amp;gt;ssh -L 8080:remotehost:3006 proxy&amp;lt;/code&amp;gt;&lt;br /&gt;
:Login over ssh to proxy and there connect to remotehost port 3006. Connect local port 8080 to the remote connection.&lt;br /&gt;
:Now if you connect to port 8080 on your local server you are connected to port 3006 on the remotehost&lt;br /&gt;
:Using &amp;lt;code&amp;gt;-nNT&amp;lt;/code&amp;gt; prevents that the ssh command opens a terminal on the proxy. The ssh command however must remain active.&lt;br /&gt;
&lt;br /&gt;
=Tracing=&lt;br /&gt;
For tracing traffic see [[Tcpdump]]&lt;br /&gt;
&lt;br /&gt;
;traceroute &amp;lt;destination&amp;gt;&lt;br /&gt;
:Show which route a package takes to reach destination&lt;br /&gt;
&lt;br /&gt;
;ip route get &amp;lt;IPaddress&amp;gt;&lt;br /&gt;
:Show the interface used to go to &amp;lt;IPaddress&amp;gt;&lt;br /&gt;
To get just the interface name you can use this[https://unix.stackexchange.com/questions/14961/how-to-find-out-which-interface-am-i-using-for-connecting-to-the-internet]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
host=&amp;lt;fqdn&amp;gt;&lt;br /&gt;
host_ip=$(getent ahosts &amp;quot;$host&amp;quot; | awk &#039;{print $1; exit}&#039;)&lt;br /&gt;
ip route get &amp;quot;$host_ip&amp;quot; | grep -Po &#039;(?&amp;lt;=(dev ))(\S+)&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Other=&lt;br /&gt;
;&amp;lt;code&amp;gt;wget &amp;lt;URL&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:Get the data from &amp;lt;URL&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Raspberry_Pi&amp;diff=1687</id>
		<title>Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Raspberry_Pi&amp;diff=1687"/>
		<updated>2026-01-04T12:58:23Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: /* System configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A [[https://www.raspberrypi.com/ Raspberry Pi]] is a amazingly cheap but working computer at the size of a deck of cards.&lt;br /&gt;
&lt;br /&gt;
=Installation=&lt;br /&gt;
Put the installation imaged on a USB device stick and boot from that.&amp;lt;br&amp;gt;&lt;br /&gt;
After installing it works fine as as headless server but if you want to use it as your desktop system there as some thinks to take care of.&amp;lt;br&amp;gt;&lt;br /&gt;
You may need a lot more storage locally (e.g. to sync with your [[nextcloud|cloud-storage]]). You can plug in any USB device and use that.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=System configuration=&lt;br /&gt;
;raspi-config&lt;br /&gt;
:Configuration utility&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;/etc/NetworkManager/system-connections&amp;lt;/code&amp;gt;&lt;br /&gt;
:Has files with the network configuration&lt;br /&gt;
&lt;br /&gt;
==Disable wifi and bluetooth==&lt;br /&gt;
Edit /boot/firmware/config.txt &amp;lt;br/&amp;gt;&lt;br /&gt;
Add following lines after the line &amp;lt;code&amp;gt;# Additional overlays and parameters are documented&amp;lt;/code&amp;gt;&lt;br /&gt;
 dtoverlay=disable-wifi&lt;br /&gt;
 dtoverlay=disable-bt&lt;br /&gt;
&lt;br /&gt;
=X11 applications=&lt;br /&gt;
RaspiOS is using [https://wiki.debian.org/Wayland wayland] as backend for the displan server backend. Although it is said wayland is the future and does have xwayland that should allow X11 applications to run some don&#039;t. Applications will just show you &#039;cannot open display&#039; or something similar&lt;br /&gt;
&lt;br /&gt;
With this help [https://geeks3d.com/20240509/how-to-switch-from-wayland-to-x11-on-raspberry-pi-os-bookworm/] I found the solution.&lt;br /&gt;
&lt;br /&gt;
;echo $XDG_SESSION_TYPE&lt;br /&gt;
:If this shows &#039;wayland&#039; that is your backend&lt;br /&gt;
&lt;br /&gt;
In raspi-config &#039;Advanced Options&#039; - &#039;A6 Wayland&#039; select X11 and reboot your system.&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
	<entry>
		<id>https://wiki.antiperfect.org/index.php?title=Cron&amp;diff=1686</id>
		<title>Cron</title>
		<link rel="alternate" type="text/html" href="https://wiki.antiperfect.org/index.php?title=Cron&amp;diff=1686"/>
		<updated>2026-01-01T13:41:20Z</updated>

		<summary type="html">&lt;p&gt;Hdridder: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timed execution of commands. The cron daemon is checking the crontab every minute to see if anything needs to be done&lt;br /&gt;
&lt;br /&gt;
;Format of crontab&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! minute &lt;br /&gt;
! hour &lt;br /&gt;
! day-of-month&lt;br /&gt;
! month&lt;br /&gt;
! day-of-week&lt;br /&gt;
! command&lt;br /&gt;
|-&lt;br /&gt;
| 1-59&lt;br /&gt;
| 1-23&lt;br /&gt;
| 1-31&lt;br /&gt;
| 1-12&lt;br /&gt;
| 0-7&lt;br /&gt;
| doit&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In scheduling fields (all except the command) following applies:&lt;br /&gt;
&lt;br /&gt;
* * means each tick is matched.&lt;br /&gt;
* */5 means each 5th tick is matched (0,5,10,...)&lt;br /&gt;
* A range is defined by a dash. E.g.   2-5 in minute   -&amp;gt; execute command on minute 2,3,4 and 5&lt;br /&gt;
* A list is defined by comma&#039;s  E.g.   2,4,6 in minute -&amp;gt; execute command on minute 2, 4 and 6&lt;br /&gt;
* For month and day-of-week also names can be used by giving the first 3 characters (case insensitive)&lt;br /&gt;
* In day-of-week numbers 0 and 7 are Sunday &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Every Sunday at noon execute my script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=bash&amp;gt;&lt;br /&gt;
00 12 * * sun /usr/local/bin/myscript.sh&lt;br /&gt;
00 12 * * 0 /usr/local/bin/myscript2.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Who can use cron can be limited in /etc/cron.[allow|deny]&lt;br /&gt;
* if cron.allow exists - only users listed into it can use crontab&lt;br /&gt;
* If cron.allow does not exist - all users except the users listed into cron.deny can use crontab&lt;br /&gt;
* If neither of the file exists - only the root can use crontab&lt;br /&gt;
* If a user is listed in both cron.allow and cron.deny - that user can use crontab.&lt;br /&gt;
&lt;br /&gt;
;crontab -l&lt;br /&gt;
:List the current crontab&lt;br /&gt;
&lt;br /&gt;
;crontab &amp;lt;crontabfile&amp;gt;&lt;br /&gt;
:Load the file into the crontab, all existing content will be replaced. A user&#039;s crontab is stored in /var/spool/cron/crontabs/&amp;lt;username&amp;gt;. Don&#039;t edit it there, the cron daemon will only read it if told so by the crontab command.&lt;br /&gt;
&lt;br /&gt;
;crontab -e&lt;br /&gt;
:Edit the current crontab directly in the default editor. Change the default editor by setting the EDITOR environment variable.&lt;/div&gt;</summary>
		<author><name>Hdridder</name></author>
	</entry>
</feed>