[med-svn] [Git][med-team/cycle][upstream] New upstream version 0.3.2

Andreas Tille (@tille) gitlab at salsa.debian.org
Fri Oct 14 07:13:13 BST 2022



Andreas Tille pushed to branch upstream at Debian Med / cycle


Commits:
a60ea424 by Andreas Tille at 2022-10-14T07:43:11+02:00
New upstream version 0.3.2
- - - - -


17 changed files:

- + .gitignore
- CHANGELOG
- − README
- − README.Debian
- + README.de.md
- − README.html
- + README.md
- + README.ru.md
- − README_de.html
- − README_ru.html
- + bitmaps/export.png
- cal_year.py
- cycle.py
- dialogs.py
- p_rotor.py
- save_load.py
- setup.py


Changes:

=====================================
.gitignore
=====================================
@@ -0,0 +1,3 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]


=====================================
CHANGELOG
=====================================
@@ -1,3 +1,40 @@
+#======================================================================
+#	Cycle - calendar for women
+#	Distributed under GNU General Public License
+# Original Author: Oleg S. Gints (altgo at users.sourceforge.net)
+# Adopted by: Konstantin L. Metlov (metlov at donfti.ru, metlov at fti.dn.ua)
+# Other contributors are listed alongside their changes
+# Home page: https://github.com/metlov/cycle
+#======================================================================
+0.3.2 (13.10.2022)
+    - removed outdated Readme.Debian
+    - converted README files to Markdown
+    - fix heading syntax in README.ru.md
+    - readded forgotten export.png bitmap from Ana Guerrero López
+    - added gitignore file
+
+    from Ana Guerrero López <ana at debian.org>:
+    - Fix diaglogs
+    - Line breaks in dialog message  (with Miriam Ruiz)
+    - Enhance dialog strings
+    - Fix calendar string format
+    - Report as ical
+    - Export to ical
+
+    from  Miriam Ruiz <little_miry at yahoo.es>:
+    - Use hashlib when saving / loading
+    - Fix spelling
+
+    from Olly Betts <olly at survex.com> (as per https://bugs.debian.org/758955)
+    - Update for wxPython 3.0
+    - Fix initial size of main window
+
+    from Konstantin L. Metlov <metlov at donfti.ru>
+    - ported to Python 3 using the 2to3 script
+    - reformatted the sources using autopep8
+    - ported to wxGTK 4
+    - fixed the encryption (to stay compatible with Python 2 version)
+
 #====================================================
 #	Cycle - calendar for women
 #	Distributed under GNU Public License


=====================================
README deleted
=====================================
@@ -1,2 +0,0 @@
-Please, help me write README in your language!
-


=====================================
README.Debian deleted
=====================================
@@ -1,30 +0,0 @@
-There seems to be some bug in python (python2.3, 2.3.4-19) and because
-of that catalan ('ca.po') and galego ('gl.po') are not loaded from locale.py.
-
-I had to add a couple of lines to the definition of locale_alias in
-/usr/lib/python2.3/locale.py :
-
-
---- locale.py.orig	2005-04-12 22:15:37.000000000 +0200
-+++ locale.py	2005-04-12 22:21:34.000000000 +0200
-@@ -487,6 +487,8 @@
-         'c-french':                      'fr_CA.ISO8859-1',
-         'c':                             'C',
-         'c_c':                           'C',
-+        'ca':                            'ca_ES.ISO8859-1',
-+        'ca_es':                         'ca_ES.ISO8859-1',
-         'cextend':                       'en_US.ISO8859-1',
-         'chinese-s':                     'zh_CN.eucCN',
-         'chinese-t':                     'zh_TW.eucTW',
-@@ -554,6 +556,8 @@
-         'ger_de':                        'de_DE.ISO8859-1',
-         'german':                        'de_DE.ISO8859-1',
-         'german_germany':                'de_DE.ISO8859-1',
-+        'gl':                            'gl_ES.ISO8859-1',
-+        'gl_es':                         'gl_ES.ISO8859-1',
-         'greek':                         'el_GR.ISO8859-7',
-         'hebrew':                        'iw_IL.ISO8859-8',
-         'hr':                            'hr_HR.ISO8859-2',
-
-
-Miriam Ruiz, 15-Apr-2005


=====================================
README.de.md
=====================================
@@ -0,0 +1,56 @@
+[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
+[![de](https://img.shields.io/badge/lang-de-green.svg)](README.de.md)
+[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
+
+# CYCLE - Ein Kalender für Frauen
+
+**13.10.2022 Version 0.3.2**  
+2002-2005 (c) Oleg Gints (altgo at users.sourceforge.net)  
+2002-2005 (c) "CONERO lab", http://conero.lrn.ru  
+2022 (c) Konstantin L. Metlov (metlov at donfti.ru , metlov at fti.dn.ua)  
+
+### PROGRAMMFEATURES
+
+*   Berechnung der Menstruationstage basierend auf der Länge des Zyklus oder der letzten Perioden
+*   Berechnung der Tage des "sicheren" Sex, erhöhter Fruchtbarkeit und Eisprungs
+*   Voraussage des Tages der Empfängnis eines Kindes
+*   Notizfunktion
+*   Hilft bei der Einnahme von hormonellen Empfängnispillen
+
+### WIE ES FUNKTIONIERT
+
+Das Programm verwendet die _Kalendermethode_ für die Berechnung der fruchtbaren Tage. Dafür ist es notwendig, die Dauer von mindestens sechs vergangenen Perioden zu kennen. Für die Berechnung wird folgender Algorithmus verwendet:
+
+*   Erster Tag: Dauer des kürzesten Zyklus minus 18
+*   Letzter Tag: Dauer des längsten Zyklus minus 11
+*   Eisprung: Wird in der Mitte der fruchtbaren Tage vermutet (Mit der Kalendermethode ist die exakte Berechnung nicht möglich)
+
+Mehr Informationen über die Kalendermethode sind unter [http://www.mama.ru/gynecolog/STA/st18.htm](http://www.mama.ru/gynecolog/STA/st18.htm) (in russisch) verfügbar.
+
+Der Tag der Empfängnis (Geburt) eines Kindes wird vom Beginn der letzten Menstruation gezählt. Dieses Datum wird mit der Dauer eines Zyklus korrigiert (Es wird die Anzahl der Tage addiert/subtrahiert, die die Zyklusdauer von 28 Tagen abweicht). Es ist möglich, das Ergebnis unter folgender Adresse zu überprüfen: [http://cir.msk.ru/sroki.shtml](http://cir.msk.ru/sroki.shtml) (in russisch)
+
+### PROGRAMMNUTZUNG
+
+Es ist notwendig, den Beginn der letzten Menstruationen per Hand zu markieren. Dies geschieht durch einen Klick mit der rechten Maustaste auf einen Tag im Kalender und der Auswahl von "Zyklusbeginn". Auf dieselbe Art kann die Markierung entfernt werden. Mit Hilfe der Dauer der letzten sechs Zyklen wird das Programm folgendes berechnen:
+
+*   Fruchtbare Tage - grüne Zellen
+*   Eisprung (Mitte der fruchtbaren Tage) - hellgrüne Zelle
+*   Beginn der nächsten Menstruation - pinke Zelle
+
+Die Zyklusdauer kann in den Einstellungen festgelegt werden oder über den Durchschnitt der Dauer der letzten 6 Zyklen berechnet werden.
+
+Um den voraussichtlichen Tag der Geburt des Kindes zu berechnen ist es nötig, den ersten Tag des letzten Zyklus zusätzlich als "Schwanger" zu markieren.
+
+Abhängig von Ihren Absichten können sowohl Tage des "sicheren" Sex als auch nur fruchtbare Tage angezeigt werden. Informationen über interessante Tage können mit einem Linksklick auf den entsprechenden Tag aufgerufen werden.
+
+Es ist möglich, Notizen zu einem Tag hinzuzufügen. Tage mit Notiz werden unterstrichen dargestellt.
+
+_Hinweis:_ Die Fehlerrate der Kalendermethod liegt bei ca. 10 Prozent. Sie ist nur für Frauen mit einer regelmäßigen Periode zu empfehlen.
+
+Wenn Ihnen Ihr Arzt die Pille verschrieben hat, wird Ihnen das Programm bei der Einhaltung der regelmäßigen Einnahme helfen. Machen Sie sich aber trotzdem mit den Hinweisen auf der Packungsbeilage vertraut! Eine Packung kann 21 Tabletten (Der Zyklus dauert 21 Tage, danach 7 Tage Pause) oder 28 Tabletten enthalten - diese werden dann jeden Tag eingenommen. Im Programm wird nur der Tag markiert, an dem die erste Tablette eingenommen werden muss.
+
+### VERTEILUNGSBESTIMMUNGEN
+
+Das Programm "Cycle" wird unter der **GNU General Public License** verteilt in der Hoffnung, dass es nützlich sein wird. Es gibt aber keine Garantie, dass es korrekt oder überhaupt funktioniert. (Siehe Datei "COPYRIGHT")
+
+Übersetzung: Christian Weiske (cweiske at users.sourceforge.net)


=====================================
README.html deleted
=====================================
@@ -1,107 +0,0 @@
-<html>
-<head>
-    <meta http-equiv="Content-Type" content="text/html;">
-    <title>
-	CYCLE - menstrual cycle tracker for women
-    </title>
-</head>
-<body BGCOLOR=white>
-<h2 align=center>
-    CYCLE<br>
-    menstrual cycle tracker for women
-</h2>
-<div align=center>
-<strong>15.09.2005 Version 0.3.1</strong><br>
-2002-2005 (c) Oleg Gints (altgo at users.sourceforge.net)<br>
-2002-2005 (c) "CONERO lab", http://conero.lrn.ru<br>
-</div>
-
-<h3 align=center>PROGRAM FEATURES</h3>
-<ul>
-    <li> Calculation of days of menstruation, based on length of cycle or
-        period statistics       
-    <li> Calculation of "safe" sex days, fertile period and days to ovulation
-    <li> Calculation of D.O.B. (Date Of Birth) of a child
-    <li> Allows you to write notes
-    <li> Helps you decide when to take the pill.
-</ul>
-
-<h3 align=center>HOW IT WORKS</h3>
-<p>
-It uses the <em>calendar (or rhythm) method</em> for the definition of fertile days.
-For this you need to determine the duration, of last six 
-cycles at least.
-   
-To determine the fertile days it uses this algorithm:
-<ul>
-    <li> First day: duration of shortest cycle minus 18
-    <li> Last day: duration of longest cycle minus 11
-    <li> Ovulation: is considered to be in the middle of fertile period (To determine the exact day isn't possible with the calendar method)
-</ul>   
-
-More information about the calendar method is available
-at: <A HREF="http://www.mama.ru/gynecolog/STA/st18.htm">
-    http://www.mama.ru/gynecolog/STA/st18.htm</A> (in Russian)
-
-<p>
-Date of birth of the child is counted from
-the beginning of last menstruation (in obstetrics 40 weeks is normally used). 
-This date is corrected with the duration of a cycle (the number of days that
-the cycle differs from 28 days is added or subtracted).
-It is possible to check the results at:
-<A HREF="http://cir.msk.ru/sroki.shtml">http://cir.msk.ru/sroki.shtml</A> (in Russian)
-
-<H3 align=center>HOW TO USE THE PROGRAM</H3>
-
-<p>
-Mark the beginning of menstruation.
-This is done by clicking with the right button on the date and chosing 
-"beginning of cycle". Similarly the mark can be removed.
-Using duration of the last six cycles, the program will calculate and display the:
-<ul>
-    <li> Fertile period - green cells
-    <li> Ovulation day (the middle of the fertile period) - brightly green cell
-    <li> Beginning of following menstruation - pink cells
-</ul>
-<p>
-Cycle duration is set in options or is calculated as an average of last six periods.
-
-
-<p>To determine the likely date of birth of the child, it is necessary
-to mark the first day of the last cycle as "Pregnancy".
-
-<p> 
-Depending on your preferences, you can display only "Safe" sex days
-or only fertile days.
-Information about a day can be seen at the bottom, by left clicking on the day.
-
-<p>
-It is possible to add a note to any date using a right click.
-Days with a note are underlined.
-
-<p>
-There is a 10 percent failure rate of the calendar contraception method
-This method is suitable only for women with a regular enough cycle.
-
-<p>
-If your doctor has recommended oral contraceptive pills
-this program can help you take them at the right date. Familiarize yourself
-thorougly with the instructions that come with the strip of tablets.
-The strip can contain 21 tablets (a tablet a day for 21 days,
-then 7 days pause) or 28 tablets (in this case a table a day without
-interuption, over 28 days).
-In the program, only the day when you first start on a strip is noted.
-
-
-<H3 align=center>CONDITIONS OF DISTRIBUTION</H3>
-<p>
-Program "Cycle" is distributed under <strong>GNU General Public License</strong>,
-in the hope that it will be useful, but <strong>WITHOUT ANY WARRANTY</strong> (see file COPYRIGHT).
-
-<p align=right>
-<font size=-1>
-    Translation - Marco Papa Manzillo (mpapamanz at users.sourceforge.net)
-</font>
-</body>
-</html>
-


=====================================
README.md
=====================================
@@ -0,0 +1,56 @@
+[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
+[![de](https://img.shields.io/badge/lang-de-green.svg)](README.de.md)
+[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
+
+# CYCLE - menstrual cycle tracker for women
+
+**13.10.2022 Version 0.3.2**  
+2002-2005 (c) Oleg Gints (altgo at users.sourceforge.net)  
+2002-2005 (c) "CONERO lab", http://conero.lrn.ru  
+2022 (c) Konstantin L. Metlov (metlov at donfti.ru , metlov at fti.dn.ua)  
+
+### PROGRAM FEATURES
+
+*   Calculation of days of menstruation, based on length of cycle or period statistics
+*   Calculation of "safe" sex days, fertile period and days to ovulation
+*   Calculation of D.O.B. (Date Of Birth) of a child
+*   Allows you to write notes
+*   Helps you decide when to take the pill.
+
+### HOW IT WORKS
+
+It uses the _calendar (or rhythm) method_ for the definition of fertile days. For this you need to determine the duration, of last six cycles at least. To determine the fertile days it uses this algorithm:
+
+*   First day: duration of shortest cycle minus 18
+*   Last day: duration of longest cycle minus 11
+*   Ovulation: is considered to be in the middle of fertile period (To determine the exact day isn't possible with the calendar method)
+
+More information about the calendar method is available at: [http://www.mama.ru/gynecolog/STA/st18.htm](http://www.mama.ru/gynecolog/STA/st18.htm) (in Russian)
+
+Date of birth of the child is counted from the beginning of last menstruation (in obstetrics 40 weeks is normally used). This date is corrected with the duration of a cycle (the number of days that the cycle differs from 28 days is added or subtracted). It is possible to check the results at: [http://cir.msk.ru/sroki.shtml](http://cir.msk.ru/sroki.shtml) (in Russian)
+
+### HOW TO USE THE PROGRAM
+
+Mark the beginning of menstruation. This is done by clicking with the right button on the date and chosing "beginning of cycle". Similarly the mark can be removed. Using duration of the last six cycles, the program will calculate and display the:
+
+*   Fertile period - green cells
+*   Ovulation day (the middle of the fertile period) - brightly green cell
+*   Beginning of following menstruation - pink cells
+
+Cycle duration is set in options or is calculated as an average of last six periods.
+
+To determine the likely date of birth of the child, it is necessary to mark the first day of the last cycle as "Pregnancy".
+
+Depending on your preferences, you can display only "Safe" sex days or only fertile days. Information about a day can be seen at the bottom, by left clicking on the day.
+
+It is possible to add a note to any date using a right click. Days with a note are underlined.
+
+There is a 10 percent failure rate of the calendar contraception method This method is suitable only for women with a regular enough cycle.
+
+If your doctor has recommended oral contraceptive pills this program can help you take them at the right date. Familiarize yourself thorougly with the instructions that come with the strip of tablets. The strip can contain 21 tablets (a tablet a day for 21 days, then 7 days pause) or 28 tablets (in this case a table a day without interuption, over 28 days). In the program, only the day when you first start on a strip is noted.
+
+### CONDITIONS OF DISTRIBUTION
+
+Program "Cycle" is distributed under **GNU General Public License**, in the hope that it will be useful, but **WITHOUT ANY WARRANTY** (see file COPYRIGHT).
+
+Translation - Marco Papa Manzillo (mpapamanz at users.sourceforge.net)


=====================================
README.ru.md
=====================================
@@ -0,0 +1,44 @@
+[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
+[![de](https://img.shields.io/badge/lang-de-green.svg)](README.de.md)
+[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
+
+# ЦИКЛ - календарь для женщин
+
+**13.10.2022 Версия 0.3.2*  
+2002-2005 (c) Олег Гинц (altgo at users.sourceforge.net)  
+2002-2005 (c) "CONERO lab", http://conero.lrn.ru  
+2022 (c) Константин Л. Метлов (metlov at donfti.ru , metlov at fti.dn.ua)  
+
+### Возможности программы:
+
+*   по заданной продолжительности цикла или по набранной статистике за несколько периодов спрогнозировать дни начала менструаций
+*   рассчитать дни "безопасного" секса, фертильный период и день овуляции
+*   определить дату рождения ребенка
+*   позволяет вести заметки
+*   помогает контролировать прием противозачаточных гормональных таблеток
+
+### Принцип работы.
+
+Для определения фертильных дней использован _календарный метод_. По этому методу необходимо определить длительность как минимум шести последних циклов. От количества дней в самом длинном цикле отнимается 11, это будет последний фертильный день. От продолжительности самого короткого цикла вычитается 18, это будет первый фертильный день. Условно день овуляции определяется как середина фертильного периода. Точно определить день овуляции расчетным путем на основании только продолжительности цикла не представляется возможным. Более подробно с календарным методом можно ознакомиться здесь: [http://www.mama.ru/gynecolog/STA/st18.htm](http://www.mama.ru/gynecolog/STA/st18.htm)
+
+Дата рождения ребенка определяется (как принято в акушерстве) 40 недель от начала последней менструации. Эта дата корректируется в зависимости от продолжительности цикла - вычитается или добавляется количество дней, насколько цикл отличается от 28 дней. Проверить работу программы можно здесь: [http://cir.msk.ru/sroki.shtml](http://cir.msk.ru/sroki.shtml)
+
+### Как пользоваться программой.
+
+Вам необходимо отмечать в календаре дни начала менструаций. Для этого на выбранной дате нажмите правую кнопку мышки, и появившемся меню выберете пункт "Начало цикла". Аналогичным образом отметку можно удалить. На основании длительности шести последних циклов программа рассчитает фертильный период (клетки светло-зеленого цвета). Ярко зеленым цветом выделяется предполагаемый день овуляции (середина фертильного периода). Розовый цвет - предполагаемая дата начала следующей менструации. Продолжительность цикла устанавливается в настройках программы. Здесь Вы можете задать длительность цикла непосредственно в днях, либо включить расчет по среднему. В таком случае программа использует среднюю продолжительность цикла за шесть последних периодов.
+
+Чтобы определить предполагаемую дату рождения ребенка, необходимо последнее начало цикла пометить дополнительно как "Беременность".
+
+В зависимости от Ваших целей вы можете включить отображение только дней "безопасного" секса или только фертильных дней.
+
+Информацию по интересующей дате можно получить, щелкнув по ней левой кнопкой мышки.
+
+Для удобства к любой дате можно добавить заметку, выбрав соответствующий пункт меню. Дата с заметкой помечается подчеркнутым шрифтом.
+
+Необходимо отметить, что коэффициент неудач у календарного метода контрацепции около 10 процентов. Пользоваться таким методом могут женщины с достаточно регулярным менструальным циклом.
+
+Если врач порекомендовал и подобрал для Вас гормональные противозачаточные средства, то программа поможет контролировать их прием. Внимательно ознакомьтесь с инструкцией, прилагаемой к выбранному препарату. Упаковка может содержать 21 таблетку - схема приема 21 день по одной таблетке, затем 7 дней перерыв, либо 28 таблеток - в таком случае таблетки принимаются по одной без перерыва все 28 дней. В программе отмечается только день приема каждой 1-ой таблетки упаковки.
+
+### Условия распространения.
+
+Программа Cycle распространяется под лицензией **GNU General Public License**, без каких либо гарантий (см. файл COPYRIGHT). Автор не несет никакой ответственности за последствия использования этой программы.


=====================================
README_de.html deleted
=====================================
@@ -1,109 +0,0 @@
-<html>
-<head>
-    <meta http-equiv="Content-Type" content="text/html;">
-    <title>
-    CYCLE - Ein Kalender für Frauen
-    </title>
-</head>
-<body bgcolor="white">
-<h2 align=center>
-    CYCLE<br>
-    Ein Kalender für Frauen
-</h2>
-<div align="center">
-<strong>15.09.2005 Version 0.3.1</strong><br>
-2002-2005 (c) Oleg Gints (altgo at users.sourceforge.net)<br>
-2002-2005 (c) "CONERO lab", http://conero.lrn.ru<br>
-</div>
-
-<h3 align="center">PROGRAMMFEATURES</h3>
-<ul>
-    <li>Berechnung der Menstruationstage basierend auf der Länge des Zyklus
-         oder der letzten Perioden</li>
-    <li>Berechnung der Tage des "sicheren" Sex, erhöhter Fruchtbarkeit und Eisprungs</li>
-    <li>Voraussage des Tages der Empfängnis eines Kindes</li>
-    <li>Notizfunktion</li>
-    <li>Hilft bei der Einnahme von hormonellen Empfängnispillen</li>
-</ul>
-
-<h3 align="center">WIE ES FUNKTIONIERT</h3>
-<p>
-Das Programm verwendet die <em>Kalendermethode</em> für die Berechnung der
-fruchtbaren Tage.
-Dafür ist es notwendig, die Dauer von mindestens sechs vergangenen Perioden
-zu kennen.
-   
-Für die Berechnung wird folgender Algorithmus verwendet:
-<ul>
-    <li>Erster Tag: Dauer des kürzesten Zyklus minus 18</li>
-    <li>Letzter Tag: Dauer des längsten Zyklus minus 11</li>
-    <li>Eisprung: Wird in der Mitte der fruchtbaren Tage vermutet (Mit der Kalendermethode ist die exakte Berechnung nicht möglich)</li>
-</ul>   
-
-Mehr Informationen über die Kalendermethode sind unter
-<a href="http://www.mama.ru/gynecolog/STA/st18.htm">
-    http://www.mama.ru/gynecolog/STA/st18.htm</a> (in russisch)
-verfügbar.
-
-<p>
-Der Tag der Empfängnis (Geburt) eines Kindes wird vom Beginn der
-letzten Menstruation gezählt.
-Dieses Datum wird mit der Dauer eines Zyklus korrigiert (Es wird die Anzahl
-der Tage addiert/subtrahiert, die die Zyklusdauer von 28 Tagen abweicht)..
-Es ist möglich, das Ergebnis unter folgender Adresse zu überprüfen:
-<a href="http://cir.msk.ru/sroki.shtml">http://cir.msk.ru/sroki.shtml</a> (in russisch)
-
-<H3 align="center">PROGRAMMNUTZUNG</H3>
-
-<p>
-Es ist notwendig, den Beginn der letzten Menstruationen per Hand zu 
-markieren. Dies geschieht durch einen Klick mit der rechten Maustaste
-auf einen Tag im Kalender und der Auswahl von "Zyklusbeginn".
-Auf dieselbe Art kann die Markierung entfernt werden.
-Mit Hilfe der Dauer der letzten sechs Zyklen wird das Programm
-folgendes berechnen:
-<ul>
-    <li>Fruchtbare Tage - grüne Zellen</li>
-    <li>Eisprung (Mitte der fruchtbaren Tage) - hellgrüne Zelle</li>
-    <li>Beginn der nächsten Menstruation - pinke Zelle</li>
-</ul>
-<p>
-Die Zyklusdauer kann in den Einstellungen festgelegt werden oder über
-den Durchschnitt der Dauer der letzten 6 Zyklen berechnet werden.</p>
-
-<p>Um den voraussichtlichen Tag der Geburt des Kindes zu berechnen
-ist es nötig, den ersten Tag des letzten Zyklus zusätzlich als
-"Schwanger" zu markieren.</p>
-
-<p>Abhängig von Ihren Absichten können sowohl Tage des "sicheren" Sex
-als auch nur fruchtbare Tage angezeigt werden.
-Informationen über interessante Tage können mit einem Linksklick
-auf den entsprechenden Tag aufgerufen werden.</p>
-
-<p>Es ist möglich, Notizen zu einem Tag hinzuzufügen. Tage
-mit Notiz werden unterstrichen dargestellt.</p>
-
-<p><em>Hinweis:</em> Die Fehlerrate der Kalendermethod liegt bei
-ca. 10 Prozent. Sie ist nur für Frauen mit einer regelmäßigen Periode
-zu empfehlen.</p>
-
-<p>Wenn Ihnen Ihr Arzt die Pille verschrieben hat, wird Ihnen das Programm
-bei der Einhaltung der regelmäßigen Einnahme helfen.
-Machen Sie sich aber trotzdem mit den Hinweisen auf der 
-Packungsbeilage vertraut!
-Eine Packung kann 21 Tabletten (Der Zyklus dauert 21 Tage, danach 7 Tage Pause)
-oder 28 Tabletten enthalten - diese werden dann jeden Tag eingenommen.
-Im Programm wird nur der Tag markiert, an dem die erste Tablette eingenommen
-werden muss.</p>
-
-<H3 align="center">VERTEILUNGSBESTIMMUNGEN</H3>
-<p>Das Programm "Cycle" wird unter der <strong>GNU General Public License</strong>
-verteilt in der Hoffnung, dass es nützlich sein wird. Es gibt aber keine Garantie,
-dass es korrekt oder überhaupt funktioniert. (Siehe Datei "COPYRIGHT")</p>
-
-<p align="right">
-<font size="-1">
-    Übersetzung: Christian Weiske (cweiske at users.sourceforge.net)
-</font>
-</body>
-</html>


=====================================
README_ru.html deleted
=====================================
@@ -1,94 +0,0 @@
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=koi8-r">
-<title>
-     -   
-</title>
-</head>
-<body BGCOLOR=white>
-<h2 align=center>
-<br>
-  .
-</h2>
-<div align=center>
-<strong>15.09.2005   0.3.1</strong><br>
-2002-2005 (c)   (altgo at users.sourceforge.net)<br>
-2002-2005 (c) "CONERO lab", http://conero.lrn.ru<br>
-</div>
-
-<h3 align=center> :</h3>
-<ul>
-<li>        
-        
-<li>   "" ,     
-<li>    
-<li>   
-<li>      
-</ul>
-
-<h3 align=center> .</h3>
-<p>
-     <em> </em>. 
-       
- .        
-11,     .   
-   18,     .
-       .
-        
-    .
-       :
-<A HREF="http://www.mama.ru/gynecolog/STA/st18.htm">
-    http://www.mama.ru/gynecolog/STA/st18.htm </A>
-<p>
-    (   ) 40 
-   .     
-   -     ,
-    28 .    
-:
-<A HREF="http://cir.msk.ru/sroki.shtml">http://cir.msk.ru/sroki.shtml</A>
-
-<H3 ALIGN=center>  .</H3>
-
-<P>       . 
-       ,   
-  " ".    
-.       
-   ( - ). 
-      (
- ).   -   
- .    
- .      
-  ,     .  
-       
- .
-<P>
-     , 
-      "".
-<P>        
-  ""     .
-<P>     ,   
-  .
-<P>       , 
-  .     
-.
-<P> ,      
-  10 .   
-      .
-<P>       
- ,    
- .    ,   
-.    21  -  
-21    ,  7  ,  28  -  
-        28 .
-       1-  .
-
-
-
-<H3 ALIGN=center> .</H3>
-    
-<P> Cycle   
-<STRONG>GNU General Public License</STRONG>,
-    (.  COPYRIGHT).   
-      .
-</body>
-</html>


=====================================
bitmaps/export.png
=====================================
Binary files /dev/null and b/bitmaps/export.png differ


=====================================
cal_year.py
=====================================
@@ -1,324 +1,322 @@
 # coding: koi8-r
-#====================================================
+# ====================================================
 #	Cycle - calendar for women
 #	Distributed under GNU Public License
 # Author: Oleg S. Gints (altgo at users.sourceforge.net)
 # Home page: http://cycle.sourceforge.net
-#===================================================    
+# ===================================================
 
 import wx
-import wx.calendar
+import wx.adv
 import calendar
 import operator
+from functools import reduce
+
 
 class Val:
     pass
-    
-MARK_BEGIN  = 1
-MARK_FERT   = 1<<1
-MARK_OVUL   = 1<<2
-MARK_SAFESEX= 1<<3
-MARK_TODAY  = 1<<4
-MARK_NOTE   = 1<<5
-MARK_PROG   = 1<<6
-MARK_LAST   = 1<<7 #last cycle, conception begin
-MARK_BIRTH  = 1<<8
-MARK_TABLET = 1<<9 #1-st hormonal tablet
-MARK_T22_28 = 1<<10 #tablets 22-28 or pause 7 days
-MARK_NEXT_TABLET = 1<<11 
-
-#-------------------- class Month_Cal -------------------
-class Month_Cal(wx.calendar.CalendarCtrl):
+
+
+MARK_BEGIN = 1
+MARK_FERT = 1 << 1
+MARK_OVUL = 1 << 2
+MARK_SAFESEX = 1 << 3
+MARK_TODAY = 1 << 4
+MARK_NOTE = 1 << 5
+MARK_PROG = 1 << 6
+MARK_LAST = 1 << 7  # last cycle, conception begin
+MARK_BIRTH = 1 << 8
+MARK_TABLET = 1 << 9  # 1-st hormonal tablet
+MARK_T22_28 = 1 << 10  # tablets 22-28 or pause 7 days
+MARK_NEXT_TABLET = 1 << 11
+
+# -------------------- class Month_Cal -------------------
+
+
+class Month_Cal(wx.adv.GenericCalendarCtrl):
     def __init__(self, parent, id, dt, pos=wx.DefaultPosition,
-		size=wx.DefaultSize, style=0 ):
-		
-	style = wx.calendar.CAL_NO_YEAR_CHANGE | wx.calendar.CAL_NO_MONTH_CHANGE | wx.NO_BORDER
-	if cycle.first_week_day==0:
-	    style = style | wx.calendar.CAL_MONDAY_FIRST
-	else:
-	    style = style | wx.calendar.CAL_SUNDAY_FIRST
-	try:
-	    style = style | wx.calendar.CAL_SEQUENTIAL_MONTH_SELECTION
-	except NameError:
-	    pass
-		    
-	wx.calendar.CalendarCtrl.__init__(self, parent, id, dt, pos, size, style)
-	self.SetBackgroundColour(wx.WHITE)
-	self.SetHeaderColours(wx.BLACK,wx.WHITE)
-	if '__WXMSW__' in wx.PlatformInfo:
-	    font = self.GetFont()
-	    font.SetFaceName("MS Sans Serif")
-	    self.SetFont(font)
-	
-	self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
-	self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
-	self.Bind(wx.EVT_KEY_UP, self.OnKey)
-	self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
-	self.d_click=wx.DateTime()#FromDMY(1, 0,2002)
-	
+                 size=wx.DefaultSize, style=0):
+
+        style = wx.adv.CAL_NO_MONTH_CHANGE | wx.NO_BORDER
+        if cycle.first_week_day == 0:
+            style = style | wx.adv.CAL_MONDAY_FIRST
+        else:
+            style = style | wx.adv.CAL_SUNDAY_FIRST
+        try:
+            style = style | wx.adv.CAL_SEQUENTIAL_MONTH_SELECTION
+        except NameError:
+            pass
+
+        wx.adv.GenericCalendarCtrl.__init__(
+            self, parent, id, dt, pos, size, style)
+        self.SetBackgroundColour(wx.WHITE)
+        self.SetHeaderColours(wx.BLACK, wx.WHITE)
+        if '__WXMSW__' in wx.PlatformInfo:
+            font = self.GetFont()
+            font.SetFaceName("MS Sans Serif")
+            self.SetFont(font)
+
+        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
+        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+        self.Bind(wx.EVT_KEY_UP, self.OnKey)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
+        self.d_click = wx.DateTime()  # FromDMY(1, 0,2002)
+
     def OnLeftDown(self, event):
-	#HitTest(Point pos) -> (result, date, weekday) 
-	res,d,w=self.HitTest(event.GetPosition())
-	if res==wx.calendar.CAL_HITTEST_DAY:
-	    Val.frame.SetStatusText(info(d))
+        # HitTest(Point pos) -> (result, date, weekday)
+        res, d, w = self.HitTest(event.GetPosition())
+        if res == wx.adv.CAL_HITTEST_DAY:
+            Val.frame.SetStatusText(info(d))
 
     def OnRightDown(self, event):
-	res,d,w=self.HitTest(event.GetPosition())
-	if res==wx.calendar.CAL_HITTEST_DAY:
-	    #now d contain clicked day
-	    self.d_click=d
-	    menu = wx.Menu()
-	    menu.Append(1, d.Format('%d %B'))
-	    menu.AppendSeparator()
-	    menu.AppendCheckItem(2, _('Begin of cycle'))
-	    menu.Check(2,is_set_mark(d, MARK_BEGIN, d.GetYear()))
-	    menu.AppendCheckItem(5, _('1-st tablet'))
-	    menu.Check(5,is_set_mark(d, MARK_TABLET, d.GetYear()))
-	    if is_set_mark(d, MARK_BEGIN, d.GetYear()):
-		menu.AppendCheckItem(3, _('Conception'))
-		menu.Check(3,is_set_mark(d, MARK_LAST, d.GetYear()))
-	    menu.AppendCheckItem(4, _('Note'))
-	    menu.Check(4,is_set_mark(d, MARK_NOTE, d.GetYear()))
-	    
-	    self.Bind(wx.EVT_MENU, self.OnBegin, id=2)
-	    self.Bind(wx.EVT_MENU, self.OnLast, id=3)
-	    self.Bind(wx.EVT_MENU, self.OnNote, id=4)
-	    self.Bind(wx.EVT_MENU, self.OnTablet, id=5)
-	    self.PopupMenu(menu, event.GetPosition())
-	    menu.Destroy()
+        res, d, w = self.HitTest(event.GetPosition())
+        if res == wx.adv.CAL_HITTEST_DAY:
+            # now d contain clicked day
+            self.d_click = d
+            menu = wx.Menu()
+            menu.Append(1, d.Format('%d %B'))
+            menu.AppendSeparator()
+            menu.AppendCheckItem(2, _('Beginning of cycle'))
+            menu.Check(2, is_set_mark(d, MARK_BEGIN, d.GetYear()))
+            menu.AppendCheckItem(5, _('1-st tablet'))
+            menu.Check(5, is_set_mark(d, MARK_TABLET, d.GetYear()))
+            if is_set_mark(d, MARK_BEGIN, d.GetYear()):
+                menu.AppendCheckItem(3, _('Conception'))
+                menu.Check(3, is_set_mark(d, MARK_LAST, d.GetYear()))
+            menu.AppendCheckItem(4, _('Note'))
+            menu.Check(4, is_set_mark(d, MARK_NOTE, d.GetYear()))
+
+            self.Bind(wx.EVT_MENU, self.OnBegin, id=2)
+            self.Bind(wx.EVT_MENU, self.OnLast, id=3)
+            self.Bind(wx.EVT_MENU, self.OnNote, id=4)
+            self.Bind(wx.EVT_MENU, self.OnTablet, id=5)
+            self.PopupMenu(menu, event.GetPosition())
+            menu.Destroy()
 
     def OnBegin(self, event):
-	if self.d_click in cycle.begin:
-	    cycle.begin.remove(self.d_click)
-	    if self.d_click in cycle.last:
-		cycle.last.remove(self.d_click)
-	    remove_mark(self.d_click, MARK_BEGIN, self.d_click.GetYear())
-	    remove_mark(self.d_click, MARK_LAST, self.d_click.GetYear())
-	else:
-	    cycle.begin.append(self.d_click)
-	    cycle.begin.sort()
-	    add_mark(self.d_click, MARK_BEGIN, self.d_click.GetYear())
-	Val.Cal.Draw_Mark()
+        if self.d_click in cycle.begin:
+            cycle.begin.remove(self.d_click)
+            if self.d_click in cycle.last:
+                cycle.last.remove(self.d_click)
+            remove_mark(self.d_click, MARK_BEGIN, self.d_click.GetYear())
+            remove_mark(self.d_click, MARK_LAST, self.d_click.GetYear())
+        else:
+            cycle.begin.append(self.d_click)
+            cycle.begin.sort()
+            add_mark(self.d_click, MARK_BEGIN, self.d_click.GetYear())
+        Val.Cal.Draw_Mark()
 
     def OnLast(self, event):
-  	if self.d_click in cycle.begin:
-	    if self.d_click in cycle.last:
-		cycle.last.remove(self.d_click)
-		remove_mark(self.d_click, MARK_LAST, self.d_click.GetYear())
-	    else:
-		cycle.last.append(self.d_click)
-		cycle.last.sort()
-		add_mark(self.d_click, MARK_LAST, self.d_click.GetYear())
-	    Val.Cal.Draw_Mark()
- 
+        if self.d_click in cycle.begin:
+            if self.d_click in cycle.last:
+                cycle.last.remove(self.d_click)
+                remove_mark(self.d_click, MARK_LAST, self.d_click.GetYear())
+            else:
+                cycle.last.append(self.d_click)
+                cycle.last.sort()
+                add_mark(self.d_click, MARK_LAST, self.d_click.GetYear())
+            Val.Cal.Draw_Mark()
+
     def OnNote(self, event):
-	txt=get_note(self.d_click)
-	dlg = Note_Dlg(self, self.d_click.Format('%d %B'), txt)
-	ret = dlg.ShowModal()
-	t= dlg.Get_Txt()
-	dlg.Destroy()
-	if ret == wx.ID_OK:
-	    add_note(self.d_click, t )
-	    add_mark(self.d_click, MARK_NOTE, self.d_click.GetYear())
-	elif ret == False:
-	    remove_note(self.d_click)
-	    remove_mark(self.d_click, MARK_NOTE, self.d_click.GetYear())
-	elif ret ==wx.ID_CANCEL:
-	    return
-	Val.Cal.Draw_Mark()
+        txt = get_note(self.d_click)
+        dlg = Note_Dlg(self, self.d_click.Format('%d %B'), txt)
+        ret = dlg.ShowModal()
+        t = dlg.Get_Txt()
+        dlg.Destroy()
+        if ret == wx.ID_OK:
+            add_note(self.d_click, t)
+            add_mark(self.d_click, MARK_NOTE, self.d_click.GetYear())
+        elif ret == False:
+            remove_note(self.d_click)
+            remove_mark(self.d_click, MARK_NOTE, self.d_click.GetYear())
+        elif ret == wx.ID_CANCEL:
+            return
+        Val.Cal.Draw_Mark()
 
     def OnTablet(self, event):
-	if self.d_click in cycle.tablet:
-	    cycle.tablet.remove(self.d_click)
-	    remove_mark(self.d_click, MARK_TABLET, self.d_click.GetYear())
-	else:
-	    cycle.tablet.append(self.d_click)
-	    cycle.tablet.sort()
-	    add_mark(self.d_click, MARK_TABLET, self.d_click.GetYear())
-	Val.Cal.Draw_Mark()
+        if self.d_click in cycle.tablet:
+            cycle.tablet.remove(self.d_click)
+            remove_mark(self.d_click, MARK_TABLET, self.d_click.GetYear())
+        else:
+            cycle.tablet.append(self.d_click)
+            cycle.tablet.sort()
+            add_mark(self.d_click, MARK_TABLET, self.d_click.GetYear())
+        Val.Cal.Draw_Mark()
 
     def OnKey(self, event):
-	k=event.GetKeyCode()
-	if k==WXK_LEFT or k==WXK_RIGHT or \
-	   k==WXK_UP or k==WXK_DOWN:
-	    pass
-	else:
-	    event.Skip()
-	    
-
-#-------------------- class Cal_Year -------------------
+        k = event.GetKeyCode()
+        if k == wx.WXK_LEFT or k == wx.WXK_RIGHT or \
+           k == wx.WXK_UP or k == wx.WXK_DOWN:
+            pass
+        else:
+            event.Skip()
+
+
+# -------------------- class Cal_Year -------------------
 class Cal_Year(wx.ScrolledWindow):
     def __init__(self, parent):
-	wx.ScrolledWindow.__init__(self, parent,-1)
+        wx.ScrolledWindow.__init__(self, parent, -1)
 #	self.SetScrollbars(20, 20, 39, 40)
-	self.SetBackgroundColour(wx.NamedColour('LIGHT BLUE'))
-	
-	dt=wx.DateTime_Today()
-	self.year=dt.GetYear()
-
-	self.day_of_year=[]
-	self.month=[]
-	Val.Cal=self
-	self.Init_Year()
-#	self.Draw_Mark()
+        self.SetBackgroundColour('LIGHT BLUE')
+
+        dt = wx.DateTime.Today()
+        self.year = dt.GetYear()
 
+        self.day_of_year = []
+        self.month = []
+        Val.Cal = self
+        self.Init_Year()
+#	self.Draw_Mark()
 
     def Inc_Year(self):
-	self.year += 1
-	self.Draw_Year()
-	reset_mark(self.year)
-	self.Draw_Mark()
+        self.year += 1
+        self.Draw_Year()
+        reset_mark(self.year)
+        self.Draw_Mark()
 
     def Dec_Year(self):
-	self.year -= 1
-	self.Draw_Year()
-	reset_mark(self.year)
-	self.Draw_Mark()
-
-    def Set_Year(self,year):
-	self.year=year
-	self.Draw_Year()
-	reset_mark(self.year)
-	self.Draw_Mark()
+        self.year -= 1
+        self.Draw_Year()
+        reset_mark(self.year)
+        self.Draw_Mark()
 
+    def Set_Year(self, year):
+        self.year = year
+        self.Draw_Year()
+        reset_mark(self.year)
+        self.Draw_Mark()
 
     def Init_Year(self):
-	m=0
-	box = wx.BoxSizer(wx.VERTICAL)
-	box.Add(wx.StaticLine(self,-1,style=wx.LI_HORIZONTAL), 0, wx.EXPAND )
-	for y in range(3):
-	    row_box=wx.BoxSizer(wx.HORIZONTAL)
-	    for x in range(4):
-		t=wx.DateTimeFromDMY(1, m, self.year)
-		id=wx.NewId()
-		self.month.append(Month_Cal(self, id, t, ))
-		row_box.Add(self.month[m], 0, wx.ALL, 5)
-		m+=1
-	    box.Add(row_box, 0, wx.LEFT|wx.RIGHT, 10)
-	
-	self.SetAutoLayout(True)
+        m = 0
+        box = wx.BoxSizer(wx.VERTICAL)
+        box.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND)
+        for y in range(3):
+            row_box = wx.BoxSizer(wx.HORIZONTAL)
+            for x in range(4):
+                t = wx.DateTime.FromDMY(1, m, self.year)
+                id = wx.NewId()
+                self.month.append(Month_Cal(self, id, t, ))
+                row_box.Add(self.month[m], 0, wx.ALL, 5)
+                m += 1
+            box.Add(row_box, 0, wx.LEFT | wx.RIGHT, 10)
+
+        self.SetAutoLayout(True)
         self.SetSizer(box)
-	box.Fit(self)
-	w = box.GetSize().GetWidth()
-	h = box.GetSize().GetHeight()
-	Val.frame.SetSize( wx.Size(w+10,h+90) )
-	self.SetScrollbars(20, 20, w/20, h/20)
+        box.Fit(self)
+        w = box.GetSize().GetWidth()
+        h = box.GetSize().GetHeight()
+        Val.frame.SetClientSize(wx.Size(w+10, h+90))
+        self.SetScrollbars(20, 20, w/20, h/20)
 
     def Draw_Year(self):
-	Val.frame.SetTitle(cycle.name+" - "+str(self.year))
-	for m in range(12):
-	    t=wx.DateTimeFromDMY(1, m, self.year)
-	    self.month[m].EnableYearChange(True)
-	    self.month[m].EnableMonthChange(True)
-	    self.month[m].SetDate(t)
-	    self.month[m].EnableYearChange(False)
-	    self.month[m].EnableMonthChange(False)
-	    self.month[m].Refresh()
+        Val.frame.SetTitle(cycle.name+" - "+str(self.year))
+        for m in range(12):
+            t = wx.DateTime.FromDMY(1, m, self.year)
+            self.month[m].EnableMonthChange(True)
+            self.month[m].SetDate(t)
+            self.month[m].EnableMonthChange(False)
+            self.month[m].Refresh()
 
     def Draw_Mark(self):
-	
-	f_norm=self.month[1].GetFont()
-	f_norm.SetUnderlined(False)
-	f_ul=self.month[1].GetFont()
-	f_ul.SetUnderlined(True)
-
-	dt=wx.DateTime_Today()
-	if self.year==dt.GetYear():
-	    add_mark(dt, MARK_TODAY, self.year)
-
-	calc_fert(self.year)
-	calc_tablet(self.year)
-	k=1
-	for m in range(12):
-	    sel_hide=True# need hide selection
-	    for d in range(1,wx.DateTime_GetNumberOfDaysInMonth(m, self.year)+1):
-		can_hide=True
-		lab=cycle.mark.get(k,0)
-		at=self.month[m].GetAttr(d)
-		if at is None :
-		    at=wx.calendar.CalendarDateAttr(wx.BLACK)
-		    self.month[m].SetAttr(d,at)
-		
-		# reset attributes
-		at.SetBorder(wx.calendar.CAL_BORDER_NONE)
-		at.SetBackgroundColour(wx.WHITE)
-		at.SetTextColour(wx.BLACK)
-		at.SetFont(f_norm)
-		
-		dt=wx.DateTimeFromDMY(d, m, self.year)
-		if not dt.IsWorkDay(): # mark weekend
-		    at.SetTextColour(wx.NamedColour('firebrick'))
-
-		if lab & MARK_BEGIN:
-		    at.SetBackgroundColour(cycle.colour_set['begin'])
-		    at.SetTextColour(wx.WHITE)
-		
-		if lab & MARK_PROG:
-		    at.SetBackgroundColour(cycle.colour_set['prog begin'])
-		    at.SetTextColour(wx.BLACK)
-
-		if lab & MARK_SAFESEX and (cycle.disp==0 or cycle.disp==2):
-		    at.SetBackgroundColour(cycle.colour_set['safe sex'])
-		    
-		if lab & MARK_FERT and (cycle.disp==1 or cycle.disp==2):
-		    at.SetBackgroundColour(cycle.colour_set['fertile'])
-
-		if lab & MARK_OVUL and (cycle.disp==1 or cycle.disp==2):
-		    at.SetBackgroundColour(cycle.colour_set['ovule'])
-	        
-		if lab & MARK_TODAY :
-		    at.SetBorderColour(wx.NamedColour('NAVY'))
-		    at.SetBorder(wx.calendar.CAL_BORDER_SQUARE)
-		    can_hide=False
-
-		if lab & MARK_LAST :
-		    at.SetBackgroundColour(cycle.colour_set['conception'])
-
-		if lab & MARK_NOTE:
-		    at.SetFont(f_ul)
-		    can_hide=False
-
-   		if lab & MARK_BIRTH :
-		    at.SetBackgroundColour(cycle.colour_set['ovule'])
-		    
-   		if lab & MARK_TABLET :
-		    at.SetBackgroundColour(cycle.colour_set['1-st tablet'])
-		
-   		if lab & MARK_T22_28 :
-		    at.SetBackgroundColour(cycle.colour_set['pause'])
-   		
-		if lab & MARK_NEXT_TABLET :
-		    at.SetBackgroundColour(cycle.colour_set['next 1-st tablet'])
-		
-		if sel_hide and can_hide:
-		    #we can hide selection when don't use border and underlined
-		    sel_hide=False
-		    self.month[m].SetDate(dt)
-		    self.month[m].SetHighlightColours(at.GetTextColour(),
-				at.GetBackgroundColour())
-
-		k+=1
-
-	# so visual refresh is more fast
-	for m in range(12):
-	    self.month[m].Refresh()
-
-
-#-------------------- work with cycle -------------------
+
+        f_norm = self.month[1].GetFont()
+        f_norm.SetUnderlined(False)
+        f_ul = self.month[1].GetFont()
+        f_ul.SetUnderlined(True)
+
+        dt = wx.DateTime.Today()
+        if self.year == dt.GetYear():
+            add_mark(dt, MARK_TODAY, self.year)
+
+        calc_fert(self.year)
+        calc_tablet(self.year)
+        k = 1
+        for m in range(12):
+            sel_hide = True  # need hide selection
+            for d in range(1, wx.DateTime.GetNumberOfDays(m, self.year)+1):
+                can_hide = True
+                lab = cycle.mark.get(k, 0)
+                at = wx.adv.CalendarDateAttr(wx.BLACK)
+                at.SetBackgroundColour(wx.WHITE)
+                at.SetFont(f_norm)
+
+                dt = wx.DateTime.FromDMY(d, m, self.year)
+                if not dt.IsWorkDay():  # mark weekend
+                    at.SetTextColour('firebrick')
+
+                if lab & MARK_BEGIN:
+                    at.SetBackgroundColour(cycle.colour_set['begin'])
+                    at.SetTextColour(wx.WHITE)
+
+                if lab & MARK_PROG:
+                    at.SetBackgroundColour(cycle.colour_set['prog begin'])
+                    at.SetTextColour(wx.BLACK)
+
+                if lab & MARK_SAFESEX and (cycle.disp == 0 or cycle.disp == 2):
+                    at.SetBackgroundColour(cycle.colour_set['safe sex'])
+
+                if lab & MARK_FERT and (cycle.disp == 1 or cycle.disp == 2):
+                    at.SetBackgroundColour(cycle.colour_set['fertile'])
+
+                if lab & MARK_OVUL and (cycle.disp == 1 or cycle.disp == 2):
+                    at.SetBackgroundColour(cycle.colour_set['ovule'])
+
+                if lab & MARK_TODAY:
+                    at.SetBorderColour('NAVY')
+                    at.SetBorder(wx.adv.CAL_BORDER_SQUARE)
+                    can_hide = False
+
+                if lab & MARK_LAST:
+                    at.SetBackgroundColour(cycle.colour_set['conception'])
+
+                if lab & MARK_NOTE:
+                    at.SetFont(f_ul)
+                    can_hide = False
+
+                if lab & MARK_BIRTH:
+                    at.SetBackgroundColour(cycle.colour_set['ovule'])
+
+                if lab & MARK_TABLET:
+                    at.SetBackgroundColour(cycle.colour_set['1-st tablet'])
+
+                if lab & MARK_T22_28:
+                    at.SetBackgroundColour(cycle.colour_set['pause'])
+
+                if lab & MARK_NEXT_TABLET:
+                    at.SetBackgroundColour(
+                        cycle.colour_set['next 1-st tablet'])
+
+                if sel_hide and can_hide:
+                    # we can hide selection when don't use border and underlined
+                    sel_hide = False
+                    self.month[m].SetDate(dt)
+                    self.month[m].SetHighlightColours(at.GetTextColour(),
+                                                      at.GetBackgroundColour())
+
+                self.month[m].SetAttr(d, at)
+
+                k += 1
+
+        # so visual refresh is more fast
+        for m in range(12):
+            self.month[m].Refresh()
+
+
+# -------------------- work with cycle -------------------
 class cycle:
-    begin=[]
-    last=[]
-    tablet=[]
-    period=28
-    mark={}
-    passwd="123"
-    name="empty"
-    file="empty"
-    by_average=False
-    disp=0
-    first_week_day=0
-    note={}
-    colour_set={}
+    begin = []
+    last = []
+    tablet = []
+    period = 28
+    mark = {}
+    passwd = "123"
+    name = "empty"
+    file = "empty"
+    by_average = False
+    disp = 0
+    first_week_day = 0
+    note = {}
+    colour_set = {}
 #    colour_set={'begin':wx.NamedColour('red'),
 #	'prog begin':wx.NamedColour('pink'),
 #        'conception':wx.NamedColour('MAGENTA'),
@@ -329,308 +327,377 @@ class cycle:
 #	'pause':wx.NamedColour('light blue'),
 #	'next 1-st tablet':wx.NamedColour('pink')}
 
+
 def min_max(i):
     """Return length max and min of 6 last cycles
     from i item cycle.begin"""
 
-    if len(cycle.begin)<2 or i==0:
-	return cycle.period, cycle.period
+    if len(cycle.begin) < 2 or i == 0:
+        return cycle.period, cycle.period
 
-    last_6=[]
-    for k in range(i,0,-1):
-	span=(cycle.begin[k]-cycle.begin[k-1]+wx.TimeSpan.Hours(1)).GetDays()
-	# wx.TimeSpan.Hours(1) -      
-	if 20 < span <36: #     
-	    last_6.append(span)
-	    if len(last_6)>=6: break
+    last_6 = []
+    for k in range(i, 0, -1):
+        span = (cycle.begin[k]-cycle.begin[k-1]+wx.TimeSpan.Hours(1)).GetDays()
+        # wx.TimeSpan.Hours(1) -      
+        if 20 < span < 36:  #     
+            last_6.append(span)
+            if len(last_6) >= 6:
+                break
 
     if cycle.by_average and len(last_6) != 0:
-	s=float(reduce( operator.add, last_6 )) # sum of last_6
-	cycle.period=int(round(s/len(last_6),0))
-	
-    if last_6==[]:
-	return cycle.period, cycle.period
-    return min(last_6),max(last_6)
+        s = float(reduce(operator.add, last_6))  # sum of last_6
+        cycle.period = int(round(s/len(last_6), 0))
+
+    if last_6 == []:
+        return cycle.period, cycle.period
+    return min(last_6), max(last_6)
 
 
 def calc_fert(year):
     """    year"""
 
-    for k in cycle.mark.keys():
-	cycle.mark[k]=cycle.mark[k] & ~MARK_FERT &\
-	~MARK_OVUL & ~MARK_PROG & ~MARK_SAFESEX & ~MARK_BIRTH &\
-	~MARK_T22_28 & ~MARK_NEXT_TABLET
-    
-    #  
-    if cycle.begin==[]: return
-    year_b=wx.DateTimeFromDMY(1, 0, year)
-    year_e=wx.DateTimeFromDMY(31, 11, year)
+    for k in list(cycle.mark.keys()):
+        cycle.mark[k] = cycle.mark[k] & ~MARK_FERT &\
+            ~MARK_OVUL & ~MARK_PROG & ~MARK_SAFESEX & ~MARK_BIRTH &\
+            ~MARK_T22_28 & ~MARK_NEXT_TABLET
+
+    #   
+    if cycle.begin == []:
+        return
+    year_b = wx.DateTime.FromDMY(1, 0, year)
+    year_e = wx.DateTime.FromDMY(31, 11, year)
     for d in cycle.begin:
-	i=cycle.begin.index(d)
-	if i<len(cycle.begin)-1:
-	    if (cycle.begin[i+1]-cycle.begin[i]+wx.TimeSpan.Hours(1)).GetDays()<21:
-		# wx.TimeSpan.Hours(1) -      
-		#  
-		continue
-
-	min, max = min_max(i)
-	begin = d+wx.DateSpan.Days( min-18 ) # begin fertile
-	end = d+wx.DateSpan.Days( max-11 ) # end fertile
-        ovul=end-wx.DateSpan.Days(((max-11)-(min-18))/2) #day of ovul
-	if year_b<=ovul<=year_e:
-	    add_mark(ovul, MARK_OVUL, year)
-
-	start=d+wx.DateSpan_Day()
-	if i<len(cycle.begin)-1:
-	    last_cycle=(cycle.begin[i+1]-cycle.begin[i]+wx.TimeSpan.Hours(1)).GetDays()
-	    if last_cycle>35:
-		stop=d+wx.DateSpan.Days( 35 )
-	    else:
-		stop=cycle.begin[i+1]-wx.DateSpan_Day()
-	else:
-	    stop=d+wx.DateSpan.Days( cycle.period-1 )
-
-	if (stop<year_b or start>year_e) and (d not in cycle.last):
-	    continue
-	f=start
-	while f.IsBetween(start, stop):
-	    if f.IsBetween(begin, end):
-		add_mark(f, MARK_FERT, year)
-	    else:
-		add_mark(f, MARK_SAFESEX, year)
-	    f=f+wx.DateSpan_Day()
-	
-	if d in cycle.last: # calc birthday
-	    birth = d+wx.DateSpan.Days(280+cycle.period-28)
-	    if i<len(cycle.begin)-1: # not last item
-		if birth < cycle.begin[i+1]:
-		    add_mark(birth, MARK_BIRTH, year)
-	    else: #last item
-		add_mark(birth, MARK_BIRTH, year)
-		return
-		
+        i = cycle.begin.index(d)
+        if i < len(cycle.begin)-1:
+            if (cycle.begin[i+1]-cycle.begin[i]+wx.TimeSpan.Hours(1)).GetDays() < 21:
+                # wx.TimeSpan.Hours(1) -      
+                #  
+                continue
+
+        min, max = min_max(i)
+        begin = d+wx.DateSpan.Days(min-18)  # begin fertile
+        end = d+wx.DateSpan.Days(max-11)  # end fertile
+        ovul = end-wx.DateSpan.Days(((max-11)-(min-18))/2)  # day of ovul
+        if year_b <= ovul <= year_e:
+            add_mark(ovul, MARK_OVUL, year)
+
+        start = d+wx.DateSpan.Day()
+        if i < len(cycle.begin)-1:
+            last_cycle = (cycle.begin[i+1]-cycle.begin[i] +
+                          wx.TimeSpan.Hours(1)).GetDays()
+            if last_cycle > 35:
+                stop = d+wx.DateSpan.Days(35)
+            else:
+                stop = cycle.begin[i+1]-wx.DateSpan.Day()
+        else:
+            stop = d+wx.DateSpan.Days(cycle.period-1)
+
+        if (stop < year_b or start > year_e) and (d not in cycle.last):
+            continue
+        f = start
+        while f.IsBetween(start, stop):
+            if f.IsBetween(begin, end):
+                add_mark(f, MARK_FERT, year)
+            else:
+                add_mark(f, MARK_SAFESEX, year)
+            f = f+wx.DateSpan.Day()
+
+        if d in cycle.last:  # calc birthday
+            birth = d+wx.DateSpan.Days(280+cycle.period-28)
+            if i < len(cycle.begin)-1:  # not last item
+                if birth < cycle.begin[i+1]:
+                    add_mark(birth, MARK_BIRTH, year)
+            else:  # last item
+                add_mark(birth, MARK_BIRTH, year)
+                return
+
     # prognosis to future cycles
-    cycle.prog_begin=[]
-    d=d+wx.DateSpan.Days( cycle.period )
-    while d.GetYear()<=year:
-	if cycle.tablet<>[] and cycle.tablet[-1]<=d and \
-	    cycle.begin[-1]<=cycle.tablet[-1]: return
-	if d.GetYear()==year: 
-	    #	    cycle.prog_begin.append(d)
-	    add_mark(d, MARK_PROG, year)
-
-	begin = d+wx.DateSpan.Days( min-18 ) # 
-	end = d+wx.DateSpan.Days( max-11 ) # 
-	ovul=end-wx.DateSpan.Days(((max-11)-(min-18))/2) #day of ovul
-	if year_b<=ovul<=year_e:
-	    add_mark(ovul, MARK_OVUL, year)
-
-	start=d+wx.DateSpan.Day()
-	stop=d+wx.DateSpan.Days( cycle.period-1 )
-	d=d+wx.DateSpan.Days( cycle.period )
-	
-        if stop<year_b or start>year_e : continue
-	
-	f=start
-	while f.IsBetween(start, stop):
-	    if f.IsBetween(begin, end):
-		add_mark(f, MARK_FERT, year)
-	    else:
-		add_mark(f, MARK_SAFESEX, year)
-	    f=f+wx.DateSpan_Day()
+    cycle.prog_begin = []
+    d = d+wx.DateSpan.Days(cycle.period)
+    while d.GetYear() <= year:
+        if cycle.tablet != [] and cycle.tablet[-1] <= d and \
+                cycle.begin[-1] <= cycle.tablet[-1]:
+            return
+        if d.GetYear() == year:
+            #	    cycle.prog_begin.append(d)
+            add_mark(d, MARK_PROG, year)
+
+        begin = d+wx.DateSpan.Days(min-18)  #  
+        end = d+wx.DateSpan.Days(max-11)  #  
+        ovul = end-wx.DateSpan.Days(((max-11)-(min-18))/2)  # day of ovul
+        if year_b <= ovul <= year_e:
+            add_mark(ovul, MARK_OVUL, year)
+
+        start = d+wx.DateSpan.Day()
+        stop = d+wx.DateSpan.Days(cycle.period-1)
+        d = d+wx.DateSpan.Days(cycle.period)
+
+        if stop < year_b or start > year_e:
+            continue
+
+        f = start
+        while f.IsBetween(start, stop):
+            if f.IsBetween(begin, end):
+                add_mark(f, MARK_FERT, year)
+            else:
+                add_mark(f, MARK_SAFESEX, year)
+            f = f+wx.DateSpan.Day()
 
 
 def calc_tablet(year):
     """calculation result of using hormonal tablets"""
-    
-    if cycle.tablet==[]: return
-    year_b=wx.DateTimeFromDMY(1, 0, year)
-    year_e=wx.DateTimeFromDMY(31, 11, year)
+
+    if cycle.tablet == []:
+        return
+    year_b = wx.DateTime.FromDMY(1, 0, year)
+    year_e = wx.DateTime.FromDMY(31, 11, year)
     for d in cycle.tablet:
-	i=cycle.tablet.index(d)
-	if i<len(cycle.tablet)-1:
-	    if (cycle.tablet[i+1]-cycle.tablet[i]+wx.TimeSpan.Hours(1)).GetDays()<28:
-		#incorrect using - must more 28 days
-		continue
-	for k in range(28):
-	    remove_mark(d+wx.DateSpan.Days(k), MARK_PROG | MARK_FERT |
-	    MARK_NEXT_TABLET | MARK_OVUL | MARK_SAFESEX | MARK_BIRTH, year)
-        for k in range(21,28):
-	    add_mark(d+wx.DateSpan.Days(k), MARK_T22_28, year)
-	add_mark(d+wx.DateSpan.Days(28), MARK_NEXT_TABLET, year)
-		
-
-	    
+        i = cycle.tablet.index(d)
+        if i < len(cycle.tablet)-1:
+            if (cycle.tablet[i+1]-cycle.tablet[i]+wx.TimeSpan.Hours(1)).GetDays() < 28:
+                # incorrect using - must more 28 days
+                continue
+        for k in range(28):
+            remove_mark(d+wx.DateSpan.Days(k), MARK_PROG | MARK_FERT |
+                        MARK_NEXT_TABLET | MARK_OVUL | MARK_SAFESEX | MARK_BIRTH, year)
+        for k in range(21, 28):
+            add_mark(d+wx.DateSpan.Days(k), MARK_T22_28, year)
+        add_mark(d+wx.DateSpan.Days(28), MARK_NEXT_TABLET, year)
+
+
 def add_mark(date, mark, year):
-    if date.GetYear()==year:
-        k=date.GetDayOfYear()
-	cycle.mark[k]=cycle.mark.get(k,0) | mark
+    if date.GetYear() == year:
+        k = date.GetDayOfYear()
+        cycle.mark[k] = cycle.mark.get(k, 0) | mark
+
 
 def remove_mark(date, mark, year):
-    if date.GetYear()==year:
-        k=date.GetDayOfYear()
-	cycle.mark[k]=cycle.mark.get(k,0) & ~mark
+    if date.GetYear() == year:
+        k = date.GetDayOfYear()
+        cycle.mark[k] = cycle.mark.get(k, 0) & ~mark
 
 
 def is_set_mark(date, mark, year):
-    if date.GetYear()==year:
-        k=date.GetDayOfYear()
-	return cycle.mark.get(k,0) & mark
+    if date.GetYear() == year:
+        k = date.GetDayOfYear()
+        return cycle.mark.get(k, 0) & mark
     else:
-	return False
+        return False
 
 
 def reset_mark(year):
     cycle.mark.clear()
     for k in cycle.begin:
-	if k.GetYear()==year:
-	    add_mark(k, MARK_BEGIN, year)
+        if k.GetYear() == year:
+            add_mark(k, MARK_BEGIN, year)
     for k in cycle.last:
-	if k.GetYear()==year:
-	    add_mark(k, MARK_LAST, year)
+        if k.GetYear() == year:
+            add_mark(k, MARK_LAST, year)
     for k in cycle.tablet:
-	if k.GetYear()==year:
-	    add_mark(k, MARK_TABLET, year)
-    for k in cycle.note.keys():
-	if str(year)==k[0:4]:
-	    d=wx.DateTimeFromDMY(int(k[6:8]), int(k[4:6])-1, int(k[0:4]))
-	    add_mark(d, MARK_NOTE, year)
-    
+        if k.GetYear() == year:
+            add_mark(k, MARK_TABLET, year)
+    for k in list(cycle.note.keys()):
+        if str(year) == k[0:4]:
+            d = wx.DateTime.FromDMY(int(k[6:8]), int(k[4:6])-1, int(k[0:4]))
+            add_mark(d, MARK_NOTE, year)
+
 
 def info(day):
     """     ."""
 
-    s=day.Format('%d %B')
-    if cycle.tablet<>[]:
-	for d in cycle.tablet:
-	    if day.IsBetween(d, d+wx.DateSpan.Days(28)):
-		t=(day-d+wx.TimeSpan.Hours(1)).GetDays()+1
-		s+=" - "
-		if t<=28:
-		    s+=_('tablet N ')+str(t)
-		if 22<= t <=28:
-		    s+=_(' or pause')
-		if t==29:
-		    s+=_('next 1-st tablet')
-		return s
-    
-    if cycle.begin==[]: return s
-    if day<cycle.begin[0]: return s #    
-
-    find=0
-    gestation=0
+    s = day.Format('%d %B')
+    if cycle.tablet != []:
+        for d in cycle.tablet:
+            if day.IsBetween(d, d+wx.DateSpan.Days(28)):
+                t = (day-d+wx.TimeSpan.Hours(1)).GetDays()+1
+                s += " - "
+                if t <= 28:
+                    s += _('tablet N ')+str(t)
+                if 22 <= t <= 28:
+                    s += _(' or pause')
+                if t == 29:
+                    s += _('next 1-st tablet')
+                return s
+
+    if cycle.begin == []:
+        return s
+    if day < cycle.begin[0]:
+        return s  #     
+
+    find = 0
+    gestation = 0
     for d in cycle.begin:
-	if day<d:
-	    find=1
-	    break
-
-    if find==0:
-	if d in cycle.last:
-	    gestation=1
-	    d2=d
-	else:
-	    #   
-	    while d<=day:
-		if cycle.tablet<>[] and cycle.tablet[-1]<=d and \
-		    cycle.begin[-1]<=cycle.tablet[-1]: return s
-		d=d+wx.DateSpan.Days(cycle.period)
-	    find=2
-
-
-    #   
-    if find==1:
-	i=cycle.begin.index(d)
-	d2=cycle.begin[i-1]
-	if d2 in cycle.last:
-	    gestation=1
-    elif find==2:
-        d2=d-wx.DateSpan.Days(cycle.period)
-    
+        if day < d:
+            find = 1
+            break
+
+    if find == 0:
+        if d in cycle.last:
+            gestation = 1
+            d2 = d
+        else:
+            #    
+            while d <= day:
+                if cycle.tablet != [] and cycle.tablet[-1] <= d and \
+                        cycle.begin[-1] <= cycle.tablet[-1]:
+                    return s
+                d = d+wx.DateSpan.Days(cycle.period)
+            find = 2
+
+    #    
+    if find == 1:
+        i = cycle.begin.index(d)
+        d2 = cycle.begin[i-1]
+        if d2 in cycle.last:
+            gestation = 1
+    elif find == 2:
+        d2 = d-wx.DateSpan.Days(cycle.period)
+
     if gestation:
-	k=(day-d2+wx.TimeSpan.Hours(1)).GetDays()+1
-	w=(k-1)/7
-	s+=" - "+str(k)+_(' day of gestation, ')+str(w)
-	if w == 1: s+=_(' week')
-	else: s+=_(' weeks')
-	s+=' + '+str(k-w*7)
-	if (k-w*7) == 1: s+=_(' day')
-	else: s+=_(' days')
+        k = (day-d2+wx.TimeSpan.Hours(1)).GetDays()+1
+        w = (k-1)/7
+        s += " - "+str(k)+_('% day of gestation, ')+str(w)
+        if w == 1:
+            s += _('1 week')
+        else:
+            s += _('% weeks')
+        s += ' + '+str(k-w*7)
+        if (k-w*7) == 1:
+            s += _('1 day')
+        else:
+            s += _('% days')
     else:
-	p=(d-d2+wx.TimeSpan.Hours(1)).GetDays()
-	k=(day-d2+wx.TimeSpan.Hours(1)).GetDays()+1
+        p = (d-d2+wx.TimeSpan.Hours(1)).GetDays()
+        k = (day-d2+wx.TimeSpan.Hours(1)).GetDays()+1
 
-	d=d-wx.DateSpan.Day()
-	s+=" - "+str(k)+_(' day of period from ')+d2.Format('%d %b')+_(' to ')+\
-	    d.Format('%d %b')+_(' length ')+str(p)+_(' days')
+        d = d-wx.DateSpan.Day()
+    s += " - "+_('%s day of period from %s to %s') % (str(k), d2.Format('%d %b'),
+                                                      d.Format('%d %b')) + ' ' + _('length %s days') % (str(p))
     return s
 
 
-#-------------------- Note --------------------
-def add_note(date,txt):
-    d=date.Format('%Y%m%d')
-    cycle.note[d]=txt
+# -------------------- Note --------------------
+def add_note(date, txt):
+    d = date.Format('%Y%m%d')
+    cycle.note[d] = txt
+
 
 def get_note(date):
-    d=date.Format('%Y%m%d')
-    return cycle.note.get(d,"")
+    d = date.Format('%Y%m%d')
+    return cycle.note.get(d, "")
+
 
 def remove_note(date):
-    d=date.Format('%Y%m%d')
-    if cycle.note.has_key(d):
-	del cycle.note[d]
+    d = date.Format('%Y%m%d')
+    if d in cycle.note:
+        del cycle.note[d]
+
+# -------------------- Report --------------------
+
 
-#-------------------- Report --------------------
 def report_year(year):
     if cycle.first_week_day == 0:
-	calendar.setfirstweekday(calendar.MONDAY)
-	days = range(1,7) + [0]
+        calendar.setfirstweekday(calendar.MONDAY)
+        days = list(range(1, 7)) + [0]
     else:
-	calendar.setfirstweekday(calendar.SUNDAY)
-	days = range(7)
+        calendar.setfirstweekday(calendar.SUNDAY)
+        days = list(range(7))
     #sp=' '
-    s='<html><body><H3 align=center>%s</H3><pre>' % year
+    s = '<html><body><H3 align=center>%s</H3><pre>' % year
     dn = ''
     for i in days:
-	dn += '%.2s ' % wx.DateTime_GetWeekDayName(i, wx.DateTime.Name_Abbr)
+        dn += '%.2s ' % wx.DateTime_GetWeekDayName(i, wx.DateTime.Name_Abbr)
     dn = dn[:-1]
     dn = '%s  %s  %s<br>\n' % (dn, dn, dn)  # week days names
-    for m in range(0,12,3):
-	s += '<br>\n%s  %s  %s<br>\n' % (
-	    wx.DateTime_GetMonthName( m ).center(20),
-	    wx.DateTime_GetMonthName( m+1 ).center(20),
-	    wx.DateTime_GetMonthName( m+2 ).center(20) )
-	s += dn
-	data = []
-	h = 0
-	for k in range(m+1, m+4):
-	    cal = calendar.monthcalendar(year, k)
-	    data.append( calendar.monthcalendar(year, k) )
-	    if h < len(cal):
-		h = len(cal)
-	for i in range(h):
-	    d_str = ''
-	    for n in range(3):
-		for k in range(7):
-		    if i< len(data[n]):
-			day_of_month = data[n][i][k]
-			if day_of_month:
-			    d = wx.DateTimeFromDMY(day_of_month, m+n, year)
-			    if is_set_mark(d, MARK_BEGIN, d.GetYear()):
-				d_str += '<u>%2s</u> ' % day_of_month
-			    else:
-				d_str += '%2s ' % day_of_month
-			else:
-			    d_str += '   '
-		    else:
-			d_str += '   '
-		d_str += ' '
-	    s += d_str[:-2] +'<br>\n'
-    
-
-    s+='</pre></body></html>'
-    print s
+    for m in range(0, 12, 3):
+        s += '<br>\n%s  %s  %s<br>\n' % (
+            wx.DateTime_GetMonthName(m).center(20),
+            wx.DateTime_GetMonthName(m+1).center(20),
+            wx.DateTime_GetMonthName(m+2).center(20))
+        s += dn
+        data = []
+        h = 0
+        for k in range(m+1, m+4):
+            cal = calendar.monthcalendar(year, k)
+            data.append(calendar.monthcalendar(year, k))
+            if h < len(cal):
+                h = len(cal)
+        for i in range(h):
+            d_str = ''
+            for n in range(3):
+                for k in range(7):
+                    if i < len(data[n]):
+                        day_of_month = data[n][i][k]
+                        if day_of_month:
+                            d = wx.DateTime.FromDMY(day_of_month, m+n, year)
+                            if is_set_mark(d, MARK_BEGIN, d.GetYear()):
+                                d_str += '<u>%2s</u> ' % day_of_month
+                            else:
+                                d_str += '%2s ' % day_of_month
+                        else:
+                            d_str += '   '
+                    else:
+                        d_str += '   '
+                d_str += ' '
+            s += d_str[:-2] + '<br>\n'
+
+    s += '</pre></body></html>'
+    print(s)
     return s
 
-#-------------------- Add import --------------------
-from dialogs import Note_Dlg 
-   
+
+def report_year_ical(year, fileobj):
+    import socket
+    hostname = socket.gethostname()
+
+    def get_string(mark):
+        if mark & MARK_LAST:
+            return _("Conception")
+        elif mark & MARK_BEGIN:
+            return _("Beginning of cycle")
+        elif mark & MARK_PROG:
+            return _("Probable beginning of cycle")
+        elif mark & MARK_TABLET:
+            return _("1-st tablet")
+        elif mark & MARK_OVUL:
+            return _("Ovulation")
+        elif mark & MARK_BIRTH:
+            return _("Birth")
+        else:
+            return ""
+
+    def make_event(description, mark, date):
+        date2 = date + wx.TimeSpan.Days(1)
+        datestr = "%04d%02d%02d" % (
+            date.GetYear(), date.GetMonth() + 1, date.GetDay())
+        datestr2 = "%04d%02d%02d" % (
+            date2.GetYear(), date2.GetMonth() + 1, date2.GetDay())
+        uid = "UID:cycle-%d-%sZ@%s" % (mark, datestr, hostname)
+        return ["BEGIN:VEVENT", uid,
+                "DTSTART;VALUE=DATE:" + datestr,
+                "DTEND;VALUE=DATE:" + datestr2,
+                "SUMMARY:" + description,
+                "DESCRIPTION:" + description,
+                "CLASS:PUBLIC",
+                "END:VEVENT"]
+
+    s = ["BEGIN:VCALENDAR",
+         "CALSCALE:GREGORIAN",
+         "PRODID:-//Cycle//NONSGML Cycle//EN",
+         "VERSION:2.0"]
+
+    days = list(cycle.mark.items())
+    days.sort()
+    for day, marks in days:
+        if get_string(marks):
+            d = wx.DateTime()
+            d.SetYear(year)
+            d.SetToYearDay(day)
+            s.extend(make_event(get_string(marks), marks, d))
+
+    s.append("END:VCALENDAR")
+
+    print("\n".join(s), file=fileobj)
+
+
+# -------------------- Add import --------------------


=====================================
cycle.py
=====================================
@@ -1,160 +1,183 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # coding: koi8-r
-#====================================================
+# ====================================================
 #	Cycle - calendar for women
 #	Distributed under GNU Public License
 # Author: Oleg S. Gints (altgo at users.sourceforge.net)
 # Home page: http://cycle.sourceforge.net
-#===================================================    
-import os, sys, gettext
-import locale
-
-import wxversion 
-wxversion.ensureMinimal('2.5.3')
-import wx
-import wx.html
+# ===================================================
+import builtins
+import gettext
+from set_dir import *
+from dialogs import *
+from save_load import *
+from cal_year import *
 import wx.lib.colourdb
+import wx.html
+import wx
+import os
+import sys
+import gettext
+import locale
 
-from cal_year import *
-from save_load import *
-from dialogs import *
-from set_dir import *
 #from prn import *
 
-import gettext
-import __builtin__
-lang_find=False
+lang_find = False
 if not '__WXMSW__' in wx.PlatformInfo:
     for lang_env_var in ('LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG'):
-	if lang_find:
-	    break
-	if os.environ.has_key(lang_env_var):
-	    env_language=os.environ[lang_env_var]
-	    for s_lang in env_language.split(':'): # if set more languages
-		os.environ[lang_env_var]=s_lang
-		try:
-		    dl=locale.getdefaultlocale()
-		    lang=[ dl[0][0:2] ]
-		    l=gettext.translation('cycle', msg_dir, lang)
-		    if wx.USE_UNICODE:
-			__builtin__.__dict__['_'] = lambda s: l.ugettext(s)
-		    else:
-			__builtin__.__dict__['_'] = lambda s: l.ugettext(s).encode(dl[1])
-		    _('try decode this string')
-		    lang_find=True
-		    break #language was found
-		except:
-		    pass
-else: #for MS Windows
+        if lang_find:
+            break
+        if lang_env_var in os.environ:
+            env_language = os.environ[lang_env_var]
+            for s_lang in env_language.split(':'):  # if set more languages
+                os.environ[lang_env_var] = s_lang
+                try:
+                    dl = locale.getdefaultlocale()
+                    lang = [dl[0][0:2]]
+                    l = gettext.translation('cycle', msg_dir, lang)
+                    if wx.USE_UNICODE:
+                        builtins.__dict__['_'] = lambda s: l.ugettext(s)
+                    else:
+                        builtins.__dict__['_'] = lambda s: l.ugettext(
+                            s).encode(dl[1])
+                    _('try decode this string')
+                    lang_find = True
+                    break  # language was found
+                except:
+                    pass
+else:  # for MS Windows
     try:
-        dl=locale.getdefaultlocale()
-        lang=[ dl[0][0:2] ]
-	l=gettext.translation('cycle', msg_dir, lang)
-	if wx.USE_UNICODE:
-	    __builtin__.__dict__['_'] = lambda s: l.ugettext(s)
-	else:
-	    __builtin__.__dict__['_'] = lambda s: l.ugettext(s).encode(dl[1])
-	_('try decode this string')
-	lang_find=True
+        dl = locale.getdefaultlocale()
+        lang = [dl[0][0:2]]
+        l = gettext.translation('cycle', msg_dir, lang)
+        if wx.USE_UNICODE:
+            builtins.__dict__['_'] = lambda s: l.ugettext(s)
+        else:
+            builtins.__dict__['_'] = lambda s: l.ugettext(s).encode(dl[1])
+        _('try decode this string')
+        lang_find = True
     except:
         pass
 
 if not lang_find:
-    __builtin__.__dict__['_'] = lambda s: s
-    lang=[""]
+    builtins.__dict__['_'] = lambda s: s
+    lang = [""]
 
 
 class MyFrame(wx.Frame):
     def __init__(self, parent, ID, title):
-	wx.Frame.__init__(self, parent, ID, title,
-		       wx.DefaultPosition, wx.Size(800, 600))
+        wx.Frame.__init__(self, parent, ID, title,
+                          wx.DefaultPosition, wx.Size(800, 600))
 
-	wx.Image_AddHandler(wx.PNGHandler())
 #	self.printer = wx.HtmlEasyPrinting()
-	icon = wx.Icon(os.path.join(icons_dir,'mini/cycle.xpm'), wx.BITMAP_TYPE_XPM)
-	self.SetIcon(icon)
+        icon = wx.Icon(os.path.join(
+            icons_dir, 'mini/cycle.xpm'), wx.BITMAP_TYPE_XPM)
+        self.SetIcon(icon)
 
-	Val.frame=self
-	self.CreateStatusBar()
+        Val.frame = self
+        self.CreateStatusBar()
         self.MakeToolMenu()  # toolbar
-	
-	self.cal=Cal_Year(self)
-	self.OnCurrent(self)
-	wx.EVT_CLOSE(self, self.OnCloseWindow)
+
+        self.cal = Cal_Year(self)
+        self.OnCurrent(self)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
     def OnCloseWindow(self, event):
-	Save_Cycle(cycle.name, cycle.passwd, cycle.file)
-	self.Destroy()
+        Save_Cycle(cycle.name, cycle.passwd, cycle.file)
+        self.Destroy()
 
     def TimeToQuit(self, event):
-	self.Close(True)
+        self.Close(True)
 
     def MakeToolMenu(self):
-	tb = self.CreateToolBar(wx.TB_HORIZONTAL|wx.NO_BORDER)
-	tb.SetToolBitmapSize( wx.Size(24,24) )
-
-	SetToolPath(self, tb, 10, os.path.join(bitmaps_dir,'dec.png'), _('Dec Year'))
-	wx.EVT_TOOL(self, 10, self.OnDecYear)
-
-	SetToolPath(self, tb, 20, os.path.join(bitmaps_dir,'curr.png'), _('Current Year'))
-	wx.EVT_TOOL(self, 20, self.OnCurrent)
-
-	SetToolPath(self, tb, 30, os.path.join(bitmaps_dir,'inc.png'), _('Inc Year'))
-	wx.EVT_TOOL(self, 30, self.OnIncYear)
-
-	tb.SetToolSeparation(50)
-	tb.AddSeparator()
-	
-	SetToolPath(self, tb, 40, os.path.join(bitmaps_dir,'legend.png'), _('Legend'))
-	wx.EVT_TOOL(self, 40, self.Legend)
-	
-	SetToolPath(self, tb, 50, os.path.join(bitmaps_dir,'set.png'), _('Settings'))
-	wx.EVT_TOOL(self, 50, self.Settings)
-	
-	SetToolPath(self, tb, 55, os.path.join(bitmaps_dir,'help.png'), _('Help'))
-	wx.EVT_TOOL(self, 55, self.Info)
+        tb = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER)
+        tb.SetToolBitmapSize(wx.Size(24, 24))
+
+        qDec=SetToolPath(self, tb, 10, os.path.join(
+                bitmaps_dir, 'dec.png'), _('Dec Year'))
+        self.Bind(wx.EVT_TOOL, self.OnDecYear, qDec)
+
+        qCurr=SetToolPath(self, tb, 20, os.path.join(
+                bitmaps_dir, 'curr.png'), _('Current Year'))
+        self.Bind(wx.EVT_TOOL, self.OnCurrent, qCurr)
+
+        qInc=SetToolPath(self, tb, 30, os.path.join(
+                bitmaps_dir, 'inc.png'), _('Inc Year'))
+        self.Bind(wx.EVT_TOOL, self.OnIncYear, qInc)
+
+        tb.SetToolSeparation(50)
+        tb.AddSeparator()
+
+        qLeg=SetToolPath(self, tb, 40, os.path.join(
+                bitmaps_dir, 'legend.png'), _('Legend'))
+        self.Bind(wx.EVT_TOOL, self.Legend, qLeg)
+
+        qExp=SetToolPath(self, tb, 45, os.path.join(
+                bitmaps_dir, 'export.png'), _('Export to iCal'))
+        self.Bind(wx.EVT_TOOL, self.Export, qExp)
+
+        qSett=SetToolPath(self, tb, 50, os.path.join(
+                bitmaps_dir, 'set.png'), _('Settings'))
+        self.Bind(wx.EVT_TOOL, self.Settings, qSett)
+
+        qHelp=SetToolPath(self, tb, 55, os.path.join(
+                bitmaps_dir, 'help.png'), _('Help'))
+        self.Bind(wx.EVT_TOOL, self.Info, qHelp)
 
 #	SetToolPath(self, tb, 57, os.path.join(bitmaps_dir,'help.png'), _('Print'))
 #	wx.EVT_TOOL(self, 57, self.test)
 
-	tb.AddSeparator()
+        tb.AddSeparator()
 
-	SetToolPath(self, tb, 60, os.path.join(bitmaps_dir,'exit.png'), _('Exit'))
-	wx.EVT_TOOL(self, 60, self.TimeToQuit)
+        qExit=SetToolPath(self, tb, 60, os.path.join(
+                bitmaps_dir, 'exit.png'), _('Exit'))
+        self.Bind(wx.EVT_TOOL, self.TimeToQuit, qExit)
 
-	tb.Realize()
+        tb.Realize()
 
     def test(self, event):
-	#rpt = report_year(self.cal.year)
-	#self.printer.PreviewText(rpt)
-	#self.printer.PreviewFile('2.html')
-	dlg = Colour_Dlg(self)
-	dlg.ShowModal()
-	dlg.Destroy()
-
-    def Legend(self,event):
-	dlg = Legend_Dlg(self)
+        #rpt = report_year(self.cal.year)
+        # self.printer.PreviewText(rpt)
+        # self.printer.PreviewFile('2.html')
+        dlg = Colour_Dlg(self)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    def Legend(self, event):
+        dlg = Legend_Dlg(self)
         dlg.ShowModal()
-	dlg.Destroy()
-        
-    def Settings(self,event):
-	dlg = Settings_Dlg(self)
+        dlg.Destroy()
+
+    def Export(self, event):
+        dlg = wx.FileDialog(self, _("Export to iCal"),
+                            style=wx.FD_SAVE)
+
         if dlg.ShowModal() == wx.ID_OK:
-	    self.cal.Set_Year(wx.DateTime_Today().GetYear())
+            try:
+                fileobj = file(dlg.GetPath(), "w")
+                report_year_ical(self.cal.year, fileobj)
+            except (IOError, OSError) as err:
+                wx.MessageDialog(
+                    self, str(err), _("Unable to export"), style=wx.OK).ShowModal()
+
+    def Settings(self, event):
+        dlg = Settings_Dlg(self)
+        if dlg.ShowModal() == wx.ID_OK:
+            self.cal.Set_Year(wx.DateTime.Today().GetYear())
         dlg.Destroy()
 
     def Info(self, event):
-	global lang
-	f_name=os.path.join(doc_dir,"README_"+lang[0]+".html")
-	if not os.path.isfile(f_name):
-	    f_name=os.path.join(doc_dir,"README.html")
-	f = open(f_name, "r")
-	msg = f.read()
-	dlg = Help_Dlg(self, _('Help'), msg)
-	dlg.ShowModal()
-
+        global lang
+        f_name = os.path.join(doc_dir, "README_"+lang[0]+".html")
+        if not os.path.isfile(f_name):
+            f_name = os.path.join(doc_dir, "README.html")
+        f = open(f_name, "r")
+        msg = f.read()
+        dlg = Help_Dlg(self, _('Help'), msg)
+        dlg.ShowModal()
 
     # increment and decrement toolbar controls
+
     def OnIncYear(self, event):
         self.cal.Inc_Year()
 
@@ -162,40 +185,41 @@ class MyFrame(wx.Frame):
         self.cal.Dec_Year()
 
     def OnCurrent(self, event):
-	self.cal.Set_Year(wx.DateTime_Today().GetYear())
-
+        self.cal.Set_Year(wx.DateTime.Today().GetYear())
 
 
-#----------------------------------------------
+# ----------------------------------------------
 def SetToolPath(self, tb, id, bmp, title):
     global dir_path
-    tb.AddSimpleTool(id, wx.Bitmap(os.path.join(dir_path, bmp), wx.BITMAP_TYPE_PNG),
-                     title, title)
+#    tb.AddSimpleTool(id, wx.Bitmap(os.path.join(dir_path, bmp), wx.BITMAP_TYPE_PNG),
+#                     title, title)
+    return tb.AddTool(id, "", wx.Bitmap(os.path.join(dir_path, bmp), wx.BITMAP_TYPE_PNG),
+                     wx.NullBitmap, wx.ITEM_NORMAL, title, title)
 
 
 class MyApp(wx.App):
     def OnInit(self):
-	wx.lib.colourdb.updateColourDB()
-	ret=first_login()
-	if ret=='bad_login':
-	    return True
-	elif ret=='not_first':
-	    dlg = Login_Dlg(None)
-	    if dlg.ShowModal() == wx.ID_CANCEL:
-		dlg.Destroy()
-		return True
-	    dlg.Destroy()
-	self.frame_init()
-	return True
+        wx.lib.colourdb.updateColourDB()
+        ret = first_login()
+        if ret == 'bad_login':
+            return True
+        elif ret == 'not_first':
+            dlg = Login_Dlg(None)
+            if dlg.ShowModal() == wx.ID_CANCEL:
+                dlg.Destroy()
+                return True
+            dlg.Destroy()
+        self.frame_init()
+        return True
 
     def frame_init(self):
-	frame = MyFrame(None, -1,"")
-	frame.Show(True)
-	self.SetTopWindow(frame)
+        frame = MyFrame(None, -1, "")
+        frame.Show(True)
+        self.SetTopWindow(frame)
 
-if __name__=='__main__':
-    locale.setlocale(locale.LC_ALL,"")
+
+if __name__ == '__main__':
+    locale.setlocale(locale.LC_ALL, "")
     dir_path = os.getcwd()
     app = MyApp(0)
     app.MainLoop()
-


=====================================
dialogs.py
=====================================
@@ -1,564 +1,601 @@
 # coding: koi8-r
-#====================================================
+# ====================================================
 #	Cycle - calendar for women
 #	Distributed under GNU Public License
 # Author: Oleg S. Gints (altgo at users.sourceforge.net)
 # Home page: http://cycle.sourceforge.net
-#===================================================    
+# ===================================================
+from cal_year import cycle, Val
+from set_dir import *
+from save_load import Load_Cycle, get_f_name, set_color_default
+import pickle
+import wx.html
+import wx
+import os
+import random, string
 import warnings
 # deprecated since release 2.3
 warnings.filterwarnings("ignore",
                         category=RuntimeWarning,
                         message='.*tempnam is a potential security risk to your program', module=__name__)
 
-import os
-import wx
-import wx.html
-import cPickle
-from cal_year import cycle , Val
-from save_load import Load_Cycle, get_f_name, set_color_default
-from set_dir import *
-#---------------------------------------------------------------------------
+# ---------------------------------------------------------------------------
+
+
 class Settings_Dlg(wx.Dialog):
     def __init__(self, parent):
-	wx.Dialog.__init__(self,parent,-1, _('Settings'), wx.DefaultPosition)
-	self.Centre(wx.BOTH)
-	#======================
-	box = wx.BoxSizer(wx.VERTICAL)
-        
-	b1=wx.StaticBoxSizer(wx.StaticBox(self,-1,_('Length of cycle')),wx.VERTICAL)
-	i=wx.NewId()
-	self.cb1 = wx.CheckBox(self, i, _(' by average'), style=wx.NO_BORDER)
-	b1.Add(self.cb1, 0, wx.ALL, 5)
-	self.Bind(wx.EVT_CHECKBOX, self.By_Average, id=i)
-	self.cb1.SetValue(cycle.by_average)
-
-	b2 = wx.BoxSizer(wx.HORIZONTAL)
-	i=wx.NewId()
-	self.sc = wx.SpinCtrl(self, i, "", size=wx.Size(50, -1))
-        self.sc.SetRange(21,35)
+        wx.Dialog.__init__(self, parent, -1, _('Settings'), wx.DefaultPosition)
+        self.Centre(wx.BOTH)
+        # ======================
+        box = wx.BoxSizer(wx.VERTICAL)
+
+        b1 = wx.StaticBoxSizer(wx.StaticBox(
+            self, -1, _('Length of cycle')), wx.VERTICAL)
+        i = wx.NewId()
+        self.cb1 = wx.CheckBox(self, i, _(' by average'), style=wx.NO_BORDER)
+        b1.Add(self.cb1, 0, wx.ALL, 5)
+        self.Bind(wx.EVT_CHECKBOX, self.By_Average, id=i)
+        self.cb1.SetValue(cycle.by_average)
+
+        b2 = wx.BoxSizer(wx.HORIZONTAL)
+        i = wx.NewId()
+        self.sc = wx.SpinCtrl(self, i, "", size=wx.Size(50, -1))
+        self.sc.SetRange(21, 35)
         self.sc.SetValue(cycle.period)
-	self.sc.Enable(not self.cb1.GetValue())
-	b2.Add(self.sc, 0)
-	b2.Add(wx.StaticText(self, -1, _(' days in cycle')), 0)
-	b1.Add(b2, 0, wx.ALL, 5)
-	box.Add(b1, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 10)
-	#======================
-	self.rb = wx.RadioBox(self, -1, _('Display'),
-	    choices=[_('safe sex days'),_('fertile days'),_('both')],
-	    majorDimension=1, style=wx.RA_SPECIFY_COLS)
-	box.Add(self.rb, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 10)
-	self.rb.SetSelection(cycle.disp)
-
-	#======================
-	self.rb1 = wx.RadioBox(self, -1, _('First week day'),
-	    choices=[_('monday'),_('sunday')],
-	    majorDimension=1, style=wx.RA_SPECIFY_COLS)
-	box.Add(self.rb1, 0, wx.EXPAND|wx.ALL, 10)
-	self.rb1.SetSelection(cycle.first_week_day)
-
-	#======================
-	i=wx.NewId()
-	txt1=_('Colours')
-	txt2=_('Change password')
-	w1,h=self.GetTextExtent(txt1)
-	w2,h=self.GetTextExtent(txt2)
-	w = max(w1, w2)
-	box.Add(wx.Button(self, i, txt1, size=wx.Size(w+10, -1)), 0, wx.ALIGN_CENTER)
-	self.Bind(wx.EVT_BUTTON, self.OnColours, id=i)
-	#======================
-	i=wx.NewId()
-	box.Add(wx.Button(self, i, txt2, size=wx.Size(w+10, -1)), 0, wx.TOP|wx.ALIGN_CENTER,10)
-	self.Bind(wx.EVT_BUTTON, self.OnChangePasswd, id=i)
-
-	#======================
-	but_box=wx.BoxSizer(wx.HORIZONTAL)
-	i=wx.NewId()
-	but_box.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
-	
-	i=wx.NewId()
-	but_box.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
-
-	box.Add(but_box, 0, wx.ALIGN_CENTER)
-
-	self.SetAutoLayout(True)
+        self.sc.Enable(not self.cb1.GetValue())
+        b2.Add(self.sc, 0)
+        b2.Add(wx.StaticText(self, -1, _(' days in cycle')), 0)
+        b1.Add(b2, 0, wx.ALL, 5)
+        box.Add(b1, 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 10)
+        # ======================
+        self.rb = wx.RadioBox(self, -1, _('Display'),
+                              choices=[_('safe sex days'), _(
+                                  'fertile days'), _('both')],
+                              majorDimension=1, style=wx.RA_SPECIFY_COLS)
+        box.Add(self.rb, 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 10)
+        self.rb.SetSelection(cycle.disp)
+
+        # ======================
+        self.rb1 = wx.RadioBox(self, -1, _('First week day'),
+                               choices=[_('monday'), _('sunday')],
+                               majorDimension=1, style=wx.RA_SPECIFY_COLS)
+        box.Add(self.rb1, 0, wx.EXPAND | wx.ALL, 10)
+        self.rb1.SetSelection(cycle.first_week_day)
+
+        # ======================
+        i = wx.NewId()
+        txt1 = _('Colours')
+        txt2 = _('Change password')
+        w1, h = self.GetTextExtent(txt1)
+        w2, h = self.GetTextExtent(txt2)
+        w = max(w1, w2)
+        box.Add(wx.Button(self, i, txt1, size=wx.Size(w+10, -1)),
+                0, wx.ALIGN_CENTER)
+        self.Bind(wx.EVT_BUTTON, self.OnColours, id=i)
+        # ======================
+        i = wx.NewId()
+        box.Add(wx.Button(self, i, txt2, size=wx.Size(w+10, -1)),
+                0, wx.TOP | wx.ALIGN_CENTER, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnChangePasswd, id=i)
+
+        # ======================
+        but_box = wx.BoxSizer(wx.HORIZONTAL)
+        i = wx.NewId()
+        but_box.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
+
+        i = wx.NewId()
+        but_box.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
+
+        box.Add(but_box, 0, wx.ALIGN_CENTER)
+
+        self.SetAutoLayout(True)
         self.SetSizer(box)
-	box.Fit(self)
+        box.Fit(self)
 
     def By_Average(self, event):
-	if event.Checked():
-	    self.sc.Enable(False)
-	else:
-	    self.sc.Enable(True)
+        if event.Checked():
+            self.sc.Enable(False)
+        else:
+            self.sc.Enable(True)
 
     def OnOk(self, event):
-	if not 21<=self.sc.GetValue()<=35:
-	    dlg = wx.MessageDialog(self, _('Period of cycle is invalid!'),
-            _('Error!'), wx.OK |wx.ICON_ERROR )
-	    dlg.ShowModal()
-	    dlg.Destroy()
-	    return
-	cycle.period=self.sc.GetValue()
-	cycle.by_average=self.cb1.GetValue()
-	cycle.disp=self.rb.GetSelection()
-	cycle.first_week_day=self.rb1.GetSelection()
-	self.EndModal(wx.ID_OK)
+        if not 21 <= self.sc.GetValue() <= 35:
+            dlg = wx.MessageDialog(self, _('Period of cycle is invalid!'),
+                                   _('Error!'), wx.OK | wx.ICON_ERROR)
+            dlg.ShowModal()
+            dlg.Destroy()
+            return
+        cycle.period = self.sc.GetValue()
+        cycle.by_average = self.cb1.GetValue()
+        cycle.disp = self.rb.GetSelection()
+        cycle.first_week_day = self.rb1.GetSelection()
+        self.EndModal(wx.ID_OK)
 
     def OnCancel(self, event):
-	self.EndModal(wx.ID_CANCEL)
+        self.EndModal(wx.ID_CANCEL)
 
     def OnChangePasswd(self, event):
         dlg = Ask_Passwd_Dlg(self)
         dlg.ShowModal()
-	dlg.Destroy()
+        dlg.Destroy()
 
     def OnColours(self, event):
         dlg = Colours_Dlg(self)
         dlg.ShowModal()
-	dlg.Destroy()
-#---------------------------------------------------------------------------
+        dlg.Destroy()
+# ---------------------------------------------------------------------------
+
+
 class Ask_Passwd_Dlg(wx.Dialog):
     def __init__(self, parent):
-	wx.Dialog.__init__(self,parent,-1, _('Password'))
-
-	#======================
-	box = wx.BoxSizer(wx.VERTICAL)
-        
-	box.Add(wx.StaticText(self, -1, _('Enter your password')), 0,
-	    wx.ALIGN_CENTER|wx.TOP|wx.LEFT|wx.RIGHT, 10)
-	self.pass1 = wx.TextCtrl(self, -1, "", wx.Point(10, 30),
-		size=(130, -1), style=wx.TE_PASSWORD)
-	box.Add(self.pass1, 0, wx.ALIGN_CENTER|wx.ALL, 10)
-	
-	box.Add(wx.StaticText(self, -1, _('Once more...')), 0,
-	    wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT, 10)
-	self.pass2 = wx.TextCtrl(self, -1, "", wx.Point(10, 80),
-		size=(130, -1), style=wx.TE_PASSWORD)
-	box.Add(self.pass2, 0, wx.ALIGN_CENTER|wx.ALL, 10)
-	
-
-	b1=wx.BoxSizer(wx.HORIZONTAL)
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
-	
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
-	self.pass1.SetFocus()
-	box.Add(b1, 0, wx.ALIGN_CENTER)
-
-	self.SetAutoLayout(True)
+        wx.Dialog.__init__(self, parent, -1, _('Password'))
+
+        # ======================
+        box = wx.BoxSizer(wx.VERTICAL)
+
+        box.Add(wx.StaticText(self, -1, _('Enter your password')), 0,
+                wx.ALIGN_CENTER | wx.TOP | wx.LEFT | wx.RIGHT, 10)
+        self.pass1 = wx.TextCtrl(self, -1, "", wx.Point(10, 30),
+                                 size=(130, -1), style=wx.TE_PASSWORD)
+        box.Add(self.pass1, 0, wx.ALIGN_CENTER | wx.ALL, 10)
+
+        box.Add(wx.StaticText(self, -1, _('Once more...')), 0,
+                wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 10)
+        self.pass2 = wx.TextCtrl(self, -1, "", wx.Point(10, 80),
+                                 size=(130, -1), style=wx.TE_PASSWORD)
+        box.Add(self.pass2, 0, wx.ALIGN_CENTER | wx.ALL, 10)
+
+        b1 = wx.BoxSizer(wx.HORIZONTAL)
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
+
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
+        self.pass1.SetFocus()
+        box.Add(b1, 0, wx.ALIGN_CENTER)
+
+        self.SetAutoLayout(True)
         self.SetSizer(box)
-	box.Fit(self)
-	
+        box.Fit(self)
 
     def OnOk(self, event):
-	err=""
-	if self.pass1.GetValue()=="" or self.pass2.GetValue()=="":
-	    err=_('Password must be not EMPTY!')
-	if self.pass1.GetValue() != self.pass2.GetValue():
-	    err=_('Entering password don\'t match!')
-	if err !=  "":
-	    dlg = wx.MessageDialog(self, err,
-            _('Error!'), wx.OK |wx.ICON_ERROR )
-	    dlg.ShowModal()
-	    dlg.Destroy()
-	    return
-	cycle.passwd=self.pass1.GetValue()
-	self.EndModal(wx.ID_OK)
+        err = ""
+        if self.pass1.GetValue() == "" or self.pass2.GetValue() == "":
+            err = _('Password must be not EMPTY!')
+        if self.pass1.GetValue() != self.pass2.GetValue():
+            err = _('Entering password don\'t match!')
+        if err != "":
+            dlg = wx.MessageDialog(self, err,
+                                   _('Error!'), wx.OK | wx.ICON_ERROR)
+            dlg.ShowModal()
+            dlg.Destroy()
+            return
+        cycle.passwd = self.pass1.GetValue()
+        self.EndModal(wx.ID_OK)
 
     def OnCancel(self, event):
-	self.EndModal(wx.ID_CANCEL)
+        self.EndModal(wx.ID_CANCEL)
 
 
-#---------------------------------------------------------------------------
+# ---------------------------------------------------------------------------
 def get_users():
-    #Get list of users
-    magic_str="UserName="
-    users=[] #array of (user, file) name
-    p, f_name=get_f_name()
+    # Get list of users
+    magic_str = b"UserName="
+    users = []  # array of (user, file) name
+    p, f_name = get_f_name()
     if os.path.exists(p):
-	files=os.listdir(p)
-    for f in files:
-	fd=open(os.path.join(p, f),"rb")
-	tmp=fd.read(len(magic_str))
-	if tmp == magic_str:
-	    tmp=fd.read(100)
-	    n=tmp.find("===") #find end string
-	    if n <> -1:
-		users.append((cPickle.loads(tmp[:n]), f))
-	else: # old format, user_name=file_name
-	    users.append((f,f))
-#    if not users:
-#	users=[(_('empty'),"empty")]
-    users.sort()
+        files = os.listdir(p)
+        for f in files:
+            fd = open(os.path.join(p, f), "rb")
+            tmp = fd.read(len(magic_str))
+            if tmp == magic_str:
+                tmp = fd.read(100)
+                n = tmp.find(b"===")  # find end string
+                if n != -1:
+                    users.append((pickle.loads(tmp[:n]), f))
+                else:  # old format, user_name=file_name
+                    users.append((f, f))
+        # if not users:
+        # users=[(_('empty'),"empty")]
+        users.sort()
     return users
 
-#---------------------------------------------------------------------------
+# ---------------------------------------------------------------------------
+
+
 class Login_Dlg(wx.Dialog):
     def __init__(self, parent):
-	wx.Dialog.__init__(self,parent,-1, _('Login'))
-	
-	self.name=""
-	self.file=""
-	
-	box = wx.BoxSizer(wx.VERTICAL)
-
-	#Get list of users
-	self.users = get_users()
-	
+        wx.Dialog.__init__(self, parent, -1, _('Login'))
+
+        self.name = ""
+        self.file = ""
+
+        box = wx.BoxSizer(wx.VERTICAL)
+
+        # Get list of users
+        self.users = get_users()
+
 #	p, f_name=get_f_name()
 #	if os.path.exists(p):
 #	    users=os.listdir(p)
 #	else:
 #	    users=[_('empty')]
 #   	users.sort()
-	
-	#======== List users ==============
-	i = wx.NewId()
-        self.il = wx.ImageList(16, 16,True)
-	bmp=wx.Bitmap(os.path.join(bitmaps_dir, 'smiles.bmp'), wx.BITMAP_TYPE_BMP)
-	mask = wx.Mask(bmp, wx.WHITE)
-	bmp.SetMask(mask)
-	
-	idx1 = self.il.Add(bmp)
+
+        # ======== List users ==============
+        i = wx.NewId()
+        self.il = wx.ImageList(16, 16, True)
+        bmp = wx.Bitmap(os.path.join(
+            bitmaps_dir, 'smiles.bmp'), wx.BITMAP_TYPE_BMP)
+        mask = wx.Mask(bmp, wx.WHITE)
+        bmp.SetMask(mask)
+
+        idx1 = self.il.Add(bmp)
 
         self.list = wx.ListCtrl(self, i, size=wx.Size(200, 200),
-                   style=wx.LC_REPORT|wx.SUNKEN_BORDER|wx.LC_SINGLE_SEL)
+                                style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_SINGLE_SEL)
         self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
-	self.list.InsertColumn(0, _('Your name'))
-	for k in range(len(self.users)):
-	    self.list.InsertImageStringItem(k, self.users[k][0], idx1)
-	self.list.SetColumnWidth(0, 180)
-	self.list.SetItemState(0, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
-	self.name=self.users[0][0]
-	self.file=self.users[0][1]
-	
-	self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list)
-	self.list.Bind(wx.EVT_LIST_KEY_DOWN, self.OnKeyDown, self.list)
-	
-	box.Add(self.list, 0, wx.ALL, 10)
-	
-        #========= Add user =============
-	i=wx.NewId()
-	box.Add(wx.Button(self, i, _('Add user')), 0, wx.ALIGN_CENTER)
-	self.Bind(wx.EVT_BUTTON, self.OnAdd, id=i)
-	
-	#========= Ok - Cancel =============
-	b1=wx.BoxSizer(wx.HORIZONTAL)
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
-	
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
-	box.Add(b1, 0, wx.ALIGN_CENTER)
-
-	self.SetAutoLayout(True)
+        self.list.InsertColumn(0, _('Your name'))
+        for k in range(len(self.users)):
+            self.list.InsertItem(k, self.users[k][0], idx1)
+        self.list.SetColumnWidth(0, 180)
+        self.list.SetItemState(0, wx.LIST_STATE_SELECTED,
+                               wx.LIST_STATE_SELECTED)
+        self.name = self.users[0][0]
+        self.file = self.users[0][1]
+
+        self.list.Bind(wx.EVT_LIST_ITEM_SELECTED,
+                       self.OnItemSelected, self.list)
+        self.list.Bind(wx.EVT_LIST_KEY_DOWN, self.OnKeyDown, self.list)
+
+        box.Add(self.list, 0, wx.ALL, 10)
+
+        # ========= Add user =============
+        i = wx.NewId()
+        box.Add(wx.Button(self, i, _('Add user')), 0, wx.ALIGN_CENTER)
+        self.Bind(wx.EVT_BUTTON, self.OnAdd, id=i)
+
+        # ========= Ok - Cancel =============
+        b1 = wx.BoxSizer(wx.HORIZONTAL)
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
+
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
+        box.Add(b1, 0, wx.ALIGN_CENTER)
+
+        self.SetAutoLayout(True)
         self.SetSizer(box)
-	box.Fit(self)
-	self.list.SetFocus()
+        box.Fit(self)
+        self.list.SetFocus()
 
     def OnItemSelected(self, event):
-	self.name=self.users[event.GetIndex()][0] #self.list.GetItemText(event.GetIndex())
-	self.file=self.users[event.GetIndex()][1]
-    
+        # self.list.GetItemText(event.GetIndex())
+        self.name = self.users[event.GetIndex()][0]
+        self.file = self.users[event.GetIndex()][1]
+
     def OnKeyDown(self, event):
-	if event.GetKeyCode()==ord(" ") or event.GetKeyCode()==wx.WXK_RETURN:
-	    self.OnOk()
-	else:
-	    event.Skip()
+        if event.GetKeyCode() == ord(" ") or event.GetKeyCode() == wx.WXK_RETURN:
+            self.OnOk()
+        else:
+            event.Skip()
 
     def OnAdd(self, event=None):
-	if ask_name(self):
-	    self.EndModal(wx.ID_OK)
+        if ask_name(self):
+            self.EndModal(wx.ID_OK)
 
     def OnOk(self, event=None):
-	dlg = wx.TextEntryDialog(self, self.name+_(', enter you password:'),_('Password'),'',
-	     style=wx.OK | wx.CANCEL |  wx.TE_PASSWORD)
-	while dlg.ShowModal() == wx.ID_OK:
-	    cycle.passwd=dlg.GetValue()
-	    cycle.name=self.name
-	    cycle.file=self.file
-	    if Load_Cycle(cycle.name, cycle.passwd, cycle.file):
-		dlg.Destroy()
-		self.EndModal(wx.ID_OK)
-		return
-	    else:
-		dlg2 = wx.MessageDialog(self, _('Password is invalid!'),
-		    _('Error!'), wx.OK |wx.ICON_ERROR )
-		dlg2.ShowModal()
-		dlg2.Destroy()
+        dlg = wx.TextEntryDialog(self, self.name+_(', enter you password:'), _('Password'), '',
+                                 style=wx.OK | wx.CANCEL | wx.TE_PASSWORD)
+        while dlg.ShowModal() == wx.ID_OK:
+            cycle.passwd = dlg.GetValue()
+            cycle.name = self.name
+            cycle.file = self.file
+            if Load_Cycle(cycle.name, cycle.passwd, cycle.file):
+                dlg.Destroy()
+                self.EndModal(wx.ID_OK)
+                return
+            else:
+                dlg2 = wx.MessageDialog(self, _('Password is invalid!'),
+                                        _('Error!'), wx.OK | wx.ICON_ERROR)
+                dlg2.ShowModal()
+                dlg2.Destroy()
         dlg.Destroy()
-	
+
     def OnCancel(self, event):
-	self.EndModal(wx.ID_CANCEL)
+        self.EndModal(wx.ID_CANCEL)
+
+# -------------------------------------------------------
+
 
-#-------------------------------------------------------
 def first_login():
-    #Get list of users
+    # Get list of users
     users = get_users()
     if users != []:
-        return 'not_first' #user(s) already exists
+        return 'not_first'  # user(s) already exists
     if ask_name():
-	return 'first'
+        return 'first'
     else:
-	return 'bad_login'
-#-------------------------------------------------------
+        return 'bad_login'
+# -------------------------------------------------------
+
+def randomword(length):
+   letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+   return ''.join(random.choice(letters) for i in range(length))
+
 def get_new_file_name():
     while True:
-        p, f = os.path.split( os.tempnam(None, "cycle") )
-	p, f_name=get_f_name(f)
+        f = "cycle"+randomword(6)
+        p, f_name = get_f_name(f)
         if not os.path.isfile(f_name):
-	    break
+            break
     return f
-#-------------------------------------------------------
+# -------------------------------------------------------
+
+
 def ask_name(parent=None):
     # nobody, it is first login
     wx.MessageBox(
-	_("This program is not a reliable contraceptive method. "
-        "Neither does it help to prevent sexually transmitted diseases "
-        "like HIV/AIDS.\n\nIt is just an electronic means of keeping track "
-        "of some of your medical data and extracting some statistical "
-        "conclusions from them. You cannot consider this program as a "
-        "substitute for your gynecologist in any way."))
-    dlg = wx.TextEntryDialog(parent, _('Enter you name:'),_('New user'),'',
-	 style=wx.OK | wx.CANCEL)
-    while dlg.ShowModal()==wx.ID_OK:
-	name=dlg.GetValue()
-	if name != "":
-	    users=get_users()
-	    exists=False
-	    for i in users:
-		if name == i[0]:
-		    exists=True
-		    break
-	    if not exists:
-		d=Ask_Passwd_Dlg(parent)
-		if d.ShowModal()==wx.ID_OK:
-		    cycle.file=get_new_file_name()
-		    cycle.name=name
-		    d.Destroy()
-		    dlg.Destroy()
-		    #self.EndModal(wx.ID_OK)
-		    set_color_default()
-		    return True
-		else:
-		    d.Destroy()
-		    continue
-	    else:
-		err=name+_(' - already exists!')
-	else:
-	    err=_('Name must be not EMPTY')
-	d2 = wx.MessageDialog(dlg, err,	_('Error!'), wx.OK |wx.ICON_ERROR )
-	d2.ShowModal()
-	d2.Destroy()
-	
+        _("This program is not a reliable contraceptive method.\n"
+          "Neither does it help to prevent sexually transmitted diseases\n"
+          "like HIV/AIDS.\n\nIt is just an electronic means of keeping track\n"
+          "of some of your medical data and extracting some statistical\n"
+          "conclusions from them. You cannot consider this program as a\n"
+          "substitute for your gynecologist in any way."))
+    dlg = wx.TextEntryDialog(parent, _('Enter your name:'), _('New user'), '',
+                             style=wx.OK | wx.CANCEL)
+    while dlg.ShowModal() == wx.ID_OK:
+        name = dlg.GetValue()
+        if name != "":
+            users = get_users()
+            exists = False
+            for i in users:
+                if name == i[0]:
+                    exists = True
+                    break
+            if not exists:
+                d = Ask_Passwd_Dlg(parent)
+                if d.ShowModal() == wx.ID_OK:
+                    cycle.file = get_new_file_name()
+                    cycle.name = name
+                    d.Destroy()
+                    dlg.Destroy()
+                    # self.EndModal(wx.ID_OK)
+                    set_color_default()
+                    return True
+                else:
+                    d.Destroy()
+                    continue
+            else:
+                err = name+_(' - already exists!')
+        else:
+            err = _('Name must be not EMPTY')
+        d2 = wx.MessageDialog(dlg, err,	_('Error!'), wx.OK | wx.ICON_ERROR)
+        d2.ShowModal()
+        d2.Destroy()
+
     dlg.Destroy()
     return False
 
-#---------------------------------------------------------------------------
+# ---------------------------------------------------------------------------
+
+
 class Legend_Dlg(wx.Dialog):
     def __init__(self, parent):
-	wx.Dialog.__init__(self,parent,-1, _('Legend'))
-
-	#======================
-	box = wx.BoxSizer(wx.VERTICAL)
-
-	self._add(box, _('today'), wx.NullColour,wx.SIMPLE_BORDER)
-	self._add(box, _('begin of cycle'), cycle.colour_set['begin'])
-	self._add(box, _('prognosis of cycle begin'), cycle.colour_set['prog begin'])
-	self._add(box, _('conception'), cycle.colour_set['conception'])
-	self._add(box, _('safe sex'), cycle.colour_set['safe sex'])
-	self._add(box, _('fertile'), cycle.colour_set['fertile'])
-	self._add(box, _('ovule, birth'), cycle.colour_set['ovule'])
-	self._add(box, _('1-st tablet'), cycle.colour_set['1-st tablet'])
-	self._add(box, _('tablets N 22-28 or pause'), cycle.colour_set['pause'])
-	self._add(box, _('next 1-st tablet'), cycle.colour_set['next 1-st tablet'])
-	
-	i=wx.NewId()
-	box.Add(wx.Button(self, i, _('Ok')), 0, wx.ALIGN_CENTER|wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
-	
-	self.SetAutoLayout(True)
+        wx.Dialog.__init__(self, parent, -1, _('Legend'))
+
+        # ======================
+        box = wx.BoxSizer(wx.VERTICAL)
+
+        self._add(box, _('today'), wx.NullColour, wx.SIMPLE_BORDER)
+        self._add(box, _('begin of cycle'), cycle.colour_set['begin'])
+        self._add(box, _('prognosis of cycle begin'),
+                  cycle.colour_set['prog begin'])
+        self._add(box, _('conception'), cycle.colour_set['conception'])
+        self._add(box, _('safe sex'), cycle.colour_set['safe sex'])
+        self._add(box, _('fertile'), cycle.colour_set['fertile'])
+        self._add(box, _('ovulation, birth'), cycle.colour_set['ovule'])
+        self._add(box, _('1-st tablet'), cycle.colour_set['1-st tablet'])
+        self._add(box, _('tablets no. 22-28 or pause'),
+                  cycle.colour_set['pause'])
+        self._add(box, _('next 1-st tablet'),
+                  cycle.colour_set['next 1-st tablet'])
+
+        i = wx.NewId()
+        box.Add(wx.Button(self, i, _('Ok')), 0, wx.ALIGN_CENTER | wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
+
+        self.SetAutoLayout(True)
         self.SetSizer(box)
-	box.Fit(self)
-	
-    def _add(self,box,txt,col,st=0):
-	b=wx.BoxSizer(wx.HORIZONTAL)
-        w=wx.Window(self,-1,size=wx.Size(15,15),style=st)
-	w.SetBackgroundColour(col)
-	b.Add(w, 0, wx.LEFT|wx.RIGHT,10)
-	b.Add(wx.StaticText(self, -1, txt), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 10)
-	box.Add(b, 0, wx.TOP, 10)
+        box.Fit(self)
 
+    def _add(self, box, txt, col, st=0):
+        b = wx.BoxSizer(wx.HORIZONTAL)
+        w = wx.Window(self, -1, size=wx.Size(15, 15), style=st)
+        w.SetBackgroundColour(col)
+        b.Add(w, 0, wx.LEFT | wx.RIGHT, 10)
+        b.Add(wx.StaticText(self, -1, txt), 0,
+              wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 10)
+        box.Add(b, 0, wx.TOP, 10)
 
     def OnOk(self, event):
-	self.EndModal(wx.ID_OK)
+        self.EndModal(wx.ID_OK)
+
+# ---------------------------------------------------------------------------
+
 
-#---------------------------------------------------------------------------
 class Note_Dlg(wx.Dialog):
-    def __init__(self, parent, title="",txt=""):
-	wx.Dialog.__init__(self,parent,-1, title)
-	self.CentreOnParent(wx.BOTH)
-
-	#======================
-	box = wx.BoxSizer(wx.VERTICAL)
-	self.txt=wx.TextCtrl(self, -1, txt,
-                       size=(-1, 100), style=wx.TE_MULTILINE)
-        box.Add( self.txt, 0,
-	    wx.EXPAND|wx.ALIGN_CENTER|wx.TOP|wx.LEFT|wx.RIGHT, 10)
-
-	b1=wx.BoxSizer(wx.HORIZONTAL)
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
-	
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
-	
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Remove')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnRemove, id=i)
-	box.Add(b1, 0, wx.ALIGN_CENTER)
-	
-	self.SetAutoLayout(True)
+    def __init__(self, parent, title="", txt=""):
+        wx.Dialog.__init__(self, parent, -1, title)
+        self.CentreOnParent(wx.BOTH)
+
+        # ======================
+        box = wx.BoxSizer(wx.VERTICAL)
+        self.txt = wx.TextCtrl(self, -1, txt,
+                               size=(-1, 100), style=wx.TE_MULTILINE)
+        box.Add(self.txt, 0,
+                wx.EXPAND | wx.ALIGN_CENTER | wx.TOP | wx.LEFT | wx.RIGHT, 10)
+
+        b1 = wx.BoxSizer(wx.HORIZONTAL)
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
+
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
+
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Remove')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnRemove, id=i)
+        box.Add(b1, 0, wx.ALIGN_CENTER)
+
+        self.SetAutoLayout(True)
         self.SetSizer(box)
-	box.Fit(self)
-	self.txt.SetFocus()
-	
+        box.Fit(self)
+        self.txt.SetFocus()
 
     def OnOk(self, event):
-	self.EndModal(wx.ID_OK)
+        self.EndModal(wx.ID_OK)
 
     def OnCancel(self, event):
-	self.EndModal(wx.ID_CANCEL)
+        self.EndModal(wx.ID_CANCEL)
 
     def OnRemove(self, event):
-	self.EndModal(False)
+        self.EndModal(False)
 
     def Get_Txt(self):
-	return self.txt.GetValue()
-    
-#---------------------------------------------------------------------------
+        return self.txt.GetValue()
+
+# ---------------------------------------------------------------------------
+
+
 class MyHtmlWindow(wx.html.HtmlWindow):
-    def __init__(self, parent, id, pos = wx.DefaultPosition, size=wx.DefaultSize):
-	wx.html.HtmlWindow.__init__(self, parent, id, pos, size)
-	if "gtk2" in wx.PlatformInfo:
-	    self.SetStandardFonts()
+    def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize):
+        wx.html.HtmlWindow.__init__(self, parent, id, pos, size)
+        if "gtk2" in wx.PlatformInfo:
+            self.SetStandardFonts()
 
     def OnLinkClicked(self, linkinfo):
-	pass
-	
-#---------------------------------------------------------------------------
+        pass
+
+# ---------------------------------------------------------------------------
+
+
 class Help_Dlg(wx.Dialog):
-    def __init__(self, parent, title="",txt=""):
-	wx.Dialog.__init__(self,parent,-1, title)
-	self.CentreOnParent(wx.BOTH)
-
-	#======================
-	box = wx.BoxSizer(wx.VERTICAL)
-	self.html=MyHtmlWindow(self, -1, size=(500, 350))
-	self.html.SetPage(txt)
-        box.Add( self.html, 0, wx.ALIGN_CENTER|wx.TOP|wx.LEFT|wx.RIGHT, 10)
-
-	i=wx.NewId()
-	box.Add(wx.Button(self, i, _('Ok')), 0, wx.ALIGN_CENTER|wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
-		
-	self.SetAutoLayout(True)
+    def __init__(self, parent, title="", txt=""):
+        wx.Dialog.__init__(self, parent, -1, title)
+        self.CentreOnParent(wx.BOTH)
+
+        # ======================
+        box = wx.BoxSizer(wx.VERTICAL)
+        self.html = MyHtmlWindow(self, -1, size=(500, 350))
+        self.html.SetPage(txt)
+        box.Add(self.html, 0, wx.ALIGN_CENTER |
+                wx.TOP | wx.LEFT | wx.RIGHT, 10)
+
+        i = wx.NewId()
+        box.Add(wx.Button(self, i, _('Ok')), 0, wx.ALIGN_CENTER | wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
+
+        self.SetAutoLayout(True)
         self.SetSizer(box)
-	box.Fit(self)
-	
+        box.Fit(self)
+
     def OnOk(self, event):
-	self.EndModal(wx.ID_OK)
+        self.EndModal(wx.ID_OK)
+
+# ---------------------------------------------------------------------------
+
 
-#---------------------------------------------------------------------------
 class Colours_Dlg(wx.Dialog):
     def __init__(self, parent):
-	wx.Dialog.__init__(self,parent,-1, _('Colours settings'))
-
-	self.col_set = cycle.colour_set.copy()
-	self.col_id = cycle.colour_set.keys()
-	self.data = wx.ColourData()
-	self.data.SetChooseFull(True)
-	self.buttons = {}
-	#======================
-	box = wx.BoxSizer(wx.VERTICAL)
-
-	self._add(box, _('begin of cycle'), 'begin')
-	self._add(box, _('prognosis of cycle begin'), 'prog begin')
-	self._add(box, _('conception'), 'conception')
-	self._add(box, _('safe sex'), 'safe sex')
-	self._add(box, _('fertile'), 'fertile')
-	self._add(box, _('ovule, birth'), 'ovule')
-	self._add(box, _('1-st tablet'), '1-st tablet')
-	self._add(box, _('tablets N 22-28 or pause'), 'pause')
-	self._add(box, _('next 1-st tablet'), 'next 1-st tablet')
-	
-	b1=wx.BoxSizer(wx.HORIZONTAL)
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
-
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('By default')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnDefault, id=i)
-
-	i=wx.NewId()
-	b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
-	self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
-	box.Add(b1, 0, wx.ALIGN_CENTER)
-	
-	self.SetAutoLayout(True)
+        wx.Dialog.__init__(self, parent, -1, _('Colours settings'))
+
+        self.col_set = cycle.colour_set.copy()
+        self.col_id = list(cycle.colour_set.keys())
+        self.data = wx.ColourData()
+        self.data.SetChooseFull(True)
+        self.buttons = {}
+        # ======================
+        box = wx.BoxSizer(wx.VERTICAL)
+
+        self._add(box, _('begin of cycle'), 'begin')
+        self._add(box, _('prognosis of cycle begin'), 'prog begin')
+        self._add(box, _('conception'), 'conception')
+        self._add(box, _('safe sex'), 'safe sex')
+        self._add(box, _('fertile'), 'fertile')
+        self._add(box, _('ovulation, birth'), 'ovule')
+        self._add(box, _('1-st tablet'), '1-st tablet')
+        self._add(box, _('tablets no. 22-28 or pause'), 'pause')
+        self._add(box, _('next 1-st tablet'), 'next 1-st tablet')
+
+        b1 = wx.BoxSizer(wx.HORIZONTAL)
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Ok')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
+
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('By default')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnDefault, id=i)
+
+        i = wx.NewId()
+        b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
+        box.Add(b1, 0, wx.ALIGN_CENTER)
+
+        self.SetAutoLayout(True)
         self.SetSizer(box)
-	box.Fit(self)
-	
+        box.Fit(self)
+
     def _add(self, box, txt, col):
-	b=wx.BoxSizer(wx.HORIZONTAL)
-	i=self.col_id.index(col)
-        bt=wx.Button(self, i, "", size=wx.Size(15,15))
-	self.Bind(wx.EVT_BUTTON, self.get_colour, id=i)
-	bt.SetBackgroundColour(self.col_set[col])
-	self.buttons.update({i:bt})
-	b.Add(bt, 0, wx.LEFT|wx.RIGHT,10)
-	b.Add(wx.StaticText(self, -1, txt), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 10)
-	box.Add(b, 0, wx.TOP, 10)
+        b = wx.BoxSizer(wx.HORIZONTAL)
+        i = self.col_id.index(col)
+        bt = wx.Button(self, i, "", size=wx.Size(15, 15))
+        self.Bind(wx.EVT_BUTTON, self.get_colour, id=i)
+        bt.SetBackgroundColour(self.col_set[col])
+        self.buttons.update({i: bt})
+        b.Add(bt, 0, wx.LEFT | wx.RIGHT, 10)
+        b.Add(wx.StaticText(self, -1, txt), 0,
+              wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 10)
+        box.Add(b, 0, wx.TOP, 10)
 
     def get_colour(self, event):
-	c = self.col_set[ self.col_id[event.GetId()] ]
-	self.data.SetColour(c)
+        c = self.col_set[self.col_id[event.GetId()]]
+        self.data.SetColour(c)
         dlg = wx.ColourDialog(self, self.data)
         if dlg.ShowModal() == wx.ID_OK:
-	    self.data = dlg.GetColourData()
-	    c = self.data.GetColour()
-	    self.buttons[event.GetId()].SetBackgroundColour(c)
-	    self.col_set[self.col_id[event.GetId()]] = c
+            self.data = dlg.GetColourData()
+            c = self.data.GetColour()
+            self.buttons[event.GetId()].SetBackgroundColour(c)
+            self.col_set[self.col_id[event.GetId()]] = c
 
     def OnOk(self, event):
-	cycle.colour_set = self.col_set.copy()
-	Val.Cal.Draw_Mark()
-	self.EndModal(wx.ID_OK)
+        cycle.colour_set = self.col_set.copy()
+        Val.Cal.Draw_Mark()
+        self.EndModal(wx.ID_OK)
 
     def OnDefault(self, event):
-	self.col_set = {'begin':wx.NamedColour('RED'),
-	    'prog begin':wx.NamedColour('PINK'),
-	    'conception':wx.NamedColour('MAGENTA'),
-	    'safe sex':wx.NamedColour('WHEAT'),
-	    'fertile':wx.NamedColour('GREEN YELLOW'),
-	    'ovule':wx.NamedColour('SPRING GREEN'),
-	    '1-st tablet':wx.NamedColour('GOLD'),
-	    'pause':wx.NamedColour('LIGHT BLUE'),
-	    'next 1-st tablet':wx.NamedColour('PINK')}
-	for item in self.col_id:
-	    self.buttons[self.col_id.index(item)].SetBackgroundColour(self.col_set[item])
+        self.col_set = {'begin': wx.NamedColour('RED'),
+                        'prog begin': wx.NamedColour('PINK'),
+                        'conception': wx.NamedColour('MAGENTA'),
+                        'safe sex': wx.NamedColour('WHEAT'),
+                        'fertile': wx.NamedColour('GREEN YELLOW'),
+                        'ovule': wx.NamedColour('SPRING GREEN'),
+                        '1-st tablet': wx.NamedColour('GOLD'),
+                        'pause': wx.NamedColour('LIGHT BLUE'),
+                        'next 1-st tablet': wx.NamedColour('PINK')}
+        for item in self.col_id:
+            self.buttons[self.col_id.index(item)].SetBackgroundColour(
+                self.col_set[item])
 
     def OnCancel(self, event):
         self.EndModal(wx.ID_CANCEL)
 
-#---------------------------------------------------------------------------
+# ---------------------------------------------------------------------------


=====================================
p_rotor.py
=====================================
@@ -46,6 +46,7 @@
    #####################################################################
 """
 
+
 class newrotor(object):
 
     def __init__(self, key, n_rotors=6):
@@ -77,14 +78,14 @@ class newrotor(object):
         size, nr, rotors, pos = self.get_rotors(do_decrypt)
         outbuf = []
         append = outbuf.append
-        for c in map(ord, buf):
+        for c in buf:
             if do_decrypt:
                 # Apply decrypt rotors and xor in reverse order
-                for i in xrange(nr-1,-1,-1):
+                for i in range(nr-1, -1, -1):
                     c = pos[i] ^ rotors[i][c]
             else:
                 # Apply xor and ecrypt rotors
-                for i in xrange(nr):
+                for i in range(nr):
                     c = rotors[i][c ^ pos[i]]
             append(c)
 
@@ -95,12 +96,12 @@ class newrotor(object):
             #        is lost if pos[i] == size-1 and pnew >= size.
             #        Masking with 0xff simulates this behavior.
             #
-            pnew = 0 # (pnew >= size) works as "carry bit"
-            for i in xrange(nr):
+            pnew = 0  # (pnew >= size) works as "carry bit"
+            for i in range(nr):
                 pnew = ((pos[i] + (pnew >= size)) & 0xff) + rotors[i][size]
                 pos[i] = pnew % size
 
-        return ''.join(map(chr, outbuf))
+        return bytes(outbuf)
 
     def get_rotors(self, do_decrypt):
         # Return a tuple (size, nr, rotors, positions) where
@@ -146,7 +147,7 @@ class newrotor(object):
                 # Generate identity permutation for 8-bit bytes plus an
                 # (unused) increment value
                 self.size = size = 256
-                id_rotor = range(size+1)
+                id_rotor = list(range(size+1))
 
                 # Generate nr "random" initial positions and "random"
                 # en/decrypt rotors from id_rotor.
@@ -155,12 +156,12 @@ class newrotor(object):
                 E = []
                 D = []
                 positions = []
-                for i in xrange(nr):
+                for i in range(nr):
                     i = size
                     positions.append(rand(i))
                     erotor = id_rotor[:]
                     drotor = id_rotor[:]
-                    drotor[i] = erotor[i] = 1 + 2*rand(i/2) # increment
+                    drotor[i] = erotor[i] = 1 + 2*rand(i//2)  # increment
                     while i > 1:
                         r = rand(i)
                         i -= 1
@@ -176,36 +177,43 @@ class newrotor(object):
             self.positions[do_decrypt] = positions
         return rotors[2], nr, rotors[do_decrypt], positions
 
+
 def random_func(key):
     # Generate a random number generator that is "seeded" from key.
     # This algorithm is copied from Python2.3 randommodule.c.
     #
     mask = 0xffff
-    x=995
-    y=576
-    z=767
-    for c in map(ord, key):
-        x = (((x<<3 | x>>13) + c) & mask)
-        y = (((y<<3 | y>>13) ^ c) & mask)
-        z = (((z<<3 | z>>13) - c) & mask)
+    x = 995
+    y = 576
+    z = 767
+    for c in key:
+        x = (((x << 3 | x >> 13) + c) & mask)
+        y = (((y << 3 | y >> 13) ^ c) & mask)
+        z = (((z << 3 | z >> 13) - c) & mask)
 
     # Emulate (unintended?) cast to short
     maxpos = mask >> 1
     mask += 1
-    if x > maxpos: x -= mask
-    if y > maxpos: y -= mask
-    if z > maxpos: z -= mask
+    if x > maxpos:
+        x -= mask
+    if y > maxpos:
+        y -= mask
+    if z > maxpos:
+        z -= mask
 
-    y |= 1 # avoid very bad seed, why not for x and z too?
+    y |= 1  # avoid very bad seed, why not for x and z too?
 
     # Oh, dear, for compatibility, we must evaluate the first seed transition
     # the hard way, later it becomes much simpler
-    x = 171 * (x % 177) - 2  * (x/177)
-    y = 172 * (y % 176) - 35 * (y/176)
-    z = 170 * (z % 178) - 63 * (z/178)
-    if x < 0: x += 30269
-    if y < 0: y += 30307
-    if z < 0: z += 30323
+    x = 171 * (x % 177) - 2 * (x//177)
+    y = 172 * (y % 176) - 35 * (y//176)
+    z = 170 * (z % 178) - 63 * (z//178)
+    if x < 0:
+        x += 30269
+    if y < 0:
+        y += 30307
+    if z < 0:
+        z += 30323
     # At least all values are > 0 by now but may be greater than expected ..
 
     def rand(n, seed=[(x, y, z)]):
@@ -224,4 +232,3 @@ def random_func(key):
         #    n = int(val*n) % n
 
     return rand
-


=====================================
save_load.py
=====================================
@@ -1,132 +1,138 @@
 # coding: koi8-r
-#====================================================
+# ====================================================
 #	Cycle - calendar for women
 #	Distributed under GNU Public License
 # Author: Oleg S. Gints (altgo at users.sourceforge.net)
 # Home page: http://cycle.sourceforge.net
-#===================================================    
+# ===================================================
+import hashlib
+import pickle
+import os.path
+import os
+import cal_year
+import wx
 import warnings
 # deprecated since release 2.3
 warnings.filterwarnings("ignore",
                         category=DeprecationWarning,
                         message='.*rotor module', module=__name__)
 
-import wx
-import os, os.path , cPickle, md5
-import cal_year
 try:
     import rotor
 except:
     import p_rotor as rotor
 
+
 def Save_Cycle(name='cycle', passwd='123', file='cycle'):
     """ Save the contents of our document to disk.
     """
-    objSave=[]
-    m=md5.new()
-    m.update(passwd)
-    rt=rotor.newrotor(m.digest())
+    objSave = []
+    m = hashlib.md5()
+    m.update(passwd.encode('utf-8'))
+    rt = rotor.newrotor(m.digest())
     objSave.append(['period', cal_year.cycle.period])
     objSave.append(['by_average', cal_year.cycle.by_average])
     objSave.append(['disp', cal_year.cycle.disp])
     objSave.append(['first_week_day', cal_year.cycle.first_week_day])
     objSave.append(['note', cal_year.cycle.note])
     for d in cal_year.cycle.begin:
-	objSave.append(['begin',[d.GetDay(), d.GetMonth(), d.GetYear()]])
-   
+        objSave.append(['begin', [d.GetDay(), d.GetMonth(), d.GetYear()]])
+
     for d in cal_year.cycle.last:
-	objSave.append(['last',[d.GetDay(), d.GetMonth(), d.GetYear()]])
-	
+        objSave.append(['last', [d.GetDay(), d.GetMonth(), d.GetYear()]])
+
     for d in cal_year.cycle.tablet:
-	objSave.append(['tablet',[d.GetDay(), d.GetMonth(), d.GetYear()]])
+        objSave.append(['tablet', [d.GetDay(), d.GetMonth(), d.GetYear()]])
 
-    for d in cal_year.cycle.colour_set.keys():
-	objSave.append(['colour', [d, cal_year.cycle.colour_set[d].Get()] ])
+    for d in list(cal_year.cycle.colour_set.keys()):
+        objSave.append(['colour', [d, cal_year.cycle.colour_set[d].Get()]])
 
-    tmp=rt.encrypt( 'Cycle'+cPickle.dumps(objSave) )
-    tmp="UserName="+cPickle.dumps(name)+"==="+tmp
-    p, f_name=get_f_name(file)
+    tmp = rt.encrypt(b'Cycle'+pickle.dumps(objSave))
+    tmp = b"UserName="+pickle.dumps(name)+b"==="+tmp
+    p, f_name = get_f_name(file)
 
     if not os.path.exists(p):
-	os.mkdir(p,0700)
-    f=open(f_name,"wb")
+        os.mkdir(p, 0o700)
+    f = open(f_name, "wb")
     f.write(tmp)
     f.close()
 #    print "All data saved to disk"
 
 
 def Load_Cycle(name='cycle', passwd='123', file='cycle'):
-    
-    p, f_name=get_f_name(file)
+
+    p, f_name = get_f_name(file)
     if os.path.isfile(f_name):
-	m=md5.new()
-	m.update(passwd)
-	rt=rotor.newrotor(m.digest())
-	f=open(f_name,"rb")
-	tmp=f.read()
-	if tmp[:len("UserName=")] == "UserName=":
-	    #new format
-	    n=tmp.find("===")+len("===")
-	    tmp=tmp[n:] #remove username
-	tmp=rt.decrypt(tmp)
-	f.close()
-	if tmp[0:5]!='Cycle':
-	    #	    print 'Password is invalid'
-	    return False
-	else:
-	    tmp=tmp[5:] #remove control word 'Cycle'
-	    objLoad=cPickle.loads(tmp)
-	    set_color_default()
-	    for type, d in objLoad:
-#		print "Load: ", type, d
-		if type=='period':
-		    cal_year.cycle.period=int(d)
-		elif type=='by_average':
-		    cal_year.cycle.by_average=int(d)
-		elif type=='disp':
-		    cal_year.cycle.disp=int(d)
-		elif type=='first_week_day':
-		    cal_year.cycle.first_week_day=int(d)
-		elif type=='begin':
-		    dt=wx.DateTimeFromDMY(d[0], d[1], d[2])
-		    cal_year.cycle.begin.append(dt)
-		elif type=='last':
-		    dt=wx.DateTimeFromDMY(d[0], d[1], d[2])
-		    cal_year.cycle.last.append(dt)
-		elif type=='tablet':
-		    dt=wx.DateTimeFromDMY(d[0], d[1], d[2])
-		    cal_year.cycle.tablet.append(dt)
-		elif type=='note':
-		    cal_year.cycle.note=d.copy()
-		elif type=='colour': # d=['item', (r,g,b)]
-		    c = wx.Colour(d[1][0], d[1][1], d[1][2])
-		    if cal_year.cycle.colour_set.has_key(d[0]):
-			cal_year.cycle.colour_set[d[0]] = c
-		    else:
-			cal_yaar.cycle.colour_set.update({d[0]:c})
+        m = hashlib.md5()
+        m.update(passwd.encode('utf-8'))
+        rt = rotor.newrotor(m.digest())
+        f = open(f_name, "rb")
+        tmp = f.read()
+        if tmp[:len(b"UserName=")] == b"UserName=":
+            # new format
+            n = tmp.find(b"===")+len(b"===")
+            tmp = tmp[n:]  # remove username
+        tmp = rt.decrypt(tmp)
+        f.close()
+        if tmp[0:5] != b'Cycle':
+            #	    print 'Password is invalid'
+            return False
+        else:
+            tmp = tmp[5:]  # remove control word 'Cycle'
+            objLoad = pickle.loads(tmp)
+            set_color_default()
+            for type, d in objLoad:
+                #		print "Load: ", type, d
+                if type == 'period':
+                    cal_year.cycle.period = int(d)
+                elif type == 'by_average':
+                    cal_year.cycle.by_average = int(d)
+                elif type == 'disp':
+                    cal_year.cycle.disp = int(d)
+                elif type == 'first_week_day':
+                    cal_year.cycle.first_week_day = int(d)
+                elif type == 'begin':
+                    dt = wx.DateTime.FromDMY(d[0], d[1], d[2])
+                    cal_year.cycle.begin.append(dt)
+                elif type == 'last':
+                    dt = wx.DateTime.FromDMY(d[0], d[1], d[2])
+                    cal_year.cycle.last.append(dt)
+                elif type == 'tablet':
+                    dt = wx.DateTime.FromDMY(d[0], d[1], d[2])
+                    cal_year.cycle.tablet.append(dt)
+                elif type == 'note':
+                    cal_year.cycle.note = d.copy()
+                elif type == 'colour':  # d=['item', (r,g,b)]
+                    c = wx.Colour(d[1][0], d[1][1], d[1][2])
+                    if d[0] in cal_year.cycle.colour_set:
+                        cal_year.cycle.colour_set[d[0]] = c
+                    else:
+                        cal_yaar.cycle.colour_set.update({d[0]: c})
 #	    print "Load OK"
-	    return True
+            return True
+
+# -------------------------------------------------------
+
 
-#-------------------------------------------------------
 def get_f_name(name=""):
     if '__WXMSW__' in wx.PlatformInfo:
-        p=os.path.join(os.getcwd(),"data")
+        p = os.path.join(os.getcwd(), "data")
     else:
-	p=os.path.expanduser("~/.cycle")
-    f_name=os.path.join(p,name)
+        p = os.path.expanduser("~/.cycle")
+    f_name = os.path.join(p, name)
 
     return p, f_name
 
-#-------------------------------------------------------
-def set_color_default():
-    cal_year.cycle.colour_set={'begin':wx.NamedColour('RED'),
-	'prog begin':wx.NamedColour('PINK'),
-        'conception':wx.NamedColour('MAGENTA'),
-	'safe sex':wx.NamedColour('WHEAT'),
-	'fertile':wx.NamedColour('GREEN YELLOW'),
-	'ovule':wx.NamedColour('SPRING GREEN'),
-	'1-st tablet':wx.NamedColour('GOLD'),
-	'pause':wx.NamedColour('LIGHT BLUE'),
-	'next 1-st tablet':wx.NamedColour('PINK')}
+# -------------------------------------------------------
 
 
+def set_color_default():
+    cal_year.cycle.colour_set = {'begin': wx.TheColourDatabase.Find('RED'),
+                                 'prog begin': wx.TheColourDatabase.Find('PINK'),
+                                 'conception': wx.TheColourDatabase.Find('MAGENTA'),
+                                 'safe sex': wx.TheColourDatabase.Find('WHEAT'),
+                                 'fertile': wx.TheColourDatabase.Find('GREEN YELLOW'),
+                                 'ovule': wx.TheColourDatabase.Find('SPRING GREEN'),
+                                 '1-st tablet': wx.TheColourDatabase.Find('GOLD'),
+                                 'pause': wx.TheColourDatabase.Find('LIGHT BLUE'),
+                                 'next 1-st tablet': wx.TheColourDatabase.Find('PINK')}


=====================================
setup.py
=====================================
@@ -2,12 +2,11 @@
 
 from distutils.core import setup
 
-setup (name = "cycle",
-       version = "0.3.1",
-       description = "Calendar for women",
-       author = "Oleg Gints",
-       author_email = "altgo at users.sourceforge.net",
-       url = "http://cycle.sourceforge.net",
-       py_modules = ['cycle'],
+setup(name="cycle",
+      version="0.3.1",
+      description="Calendar for women",
+      author="Oleg Gints",
+      author_email="altgo at users.sourceforge.net",
+      url="http://cycle.sourceforge.net",
+      py_modules=['cycle'],
       )
-



View it on GitLab: https://salsa.debian.org/med-team/cycle/-/commit/a60ea424227a4e2477c508cb9c26457540761dbd

-- 
View it on GitLab: https://salsa.debian.org/med-team/cycle/-/commit/a60ea424227a4e2477c508cb9c26457540761dbd
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20221014/cde8dac8/attachment-0001.htm>


More information about the debian-med-commit mailing list