aboutsummaryrefslogtreecommitdiffstats
path: root/deskutils/cycle
diff options
context:
space:
mode:
authordanfe <danfe@FreeBSD.org>2005-06-30 22:05:05 +0800
committerdanfe <danfe@FreeBSD.org>2005-06-30 22:05:05 +0800
commit3967ff746d4418593387d790f7724ed64d668b45 (patch)
tree45b3e9eec00631450836b1dbcd1307e32e184a7e /deskutils/cycle
parentea2301c6829e134d76593b9b2874545277ca4676 (diff)
downloadfreebsd-ports-gnome-3967ff746d4418593387d790f7724ed64d668b45.tar.gz
freebsd-ports-gnome-3967ff746d4418593387d790f7724ed64d668b45.tar.zst
freebsd-ports-gnome-3967ff746d4418593387d790f7724ed64d668b45.zip
Add cycle 0.3.0, a calendar for women.
Idea from: LG G1800 Obtained from: Debian (patches and manpage)
Diffstat (limited to 'deskutils/cycle')
-rw-r--r--deskutils/cycle/Makefile55
-rw-r--r--deskutils/cycle/distinfo2
-rw-r--r--deskutils/cycle/files/cycle.185
-rw-r--r--deskutils/cycle/files/p_rotor.py227
-rw-r--r--deskutils/cycle/files/patch-cal_year.py237
-rw-r--r--deskutils/cycle/files/patch-cycle.py140
-rw-r--r--deskutils/cycle/files/patch-dialogs.py284
-rw-r--r--deskutils/cycle/files/patch-save_load.py48
-rw-r--r--deskutils/cycle/pkg-descr21
-rw-r--r--deskutils/cycle/pkg-plist35
10 files changed, 1134 insertions, 0 deletions
diff --git a/deskutils/cycle/Makefile b/deskutils/cycle/Makefile
new file mode 100644
index 000000000000..6e548c1cb226
--- /dev/null
+++ b/deskutils/cycle/Makefile
@@ -0,0 +1,55 @@
+# New ports collection makefile for: Cycle
+# Date created: 30 Jun 2005
+# Whom: Alexey Dokuchaev <danfe@FreeBSD.org>
+#
+# $FreeBSD$
+#
+
+PORTNAME= cycle
+PORTVERSION= 0.3.0
+CATEGORIES= deskutils biology python
+MASTER_SITES= ${MASTER_SITE_SOURCEFORGE}
+MASTER_SITE_SUBDIR= ${PORTNAME}
+
+MAINTAINER= danfe@FreeBSD.org
+COMMENT= A calendar program for women
+
+RUN_DEPENDS= ${PYTHON_SITELIBDIR}/wx-2.6-gtk2-ansi/wxPython/__init__.py:${PORTSDIR}/x11-toolkits/py-wxPython26
+
+USE_BZIP2= yes
+USE_PYTHON= yes
+USE_REINPLACE= yes
+NO_BUILD= yes
+
+MAN1= ${PORTNAME}.1
+
+post-patch:
+ @${REINPLACE_CMD} -e 's,"msg","${PREFIX}/share/locale",' \
+ -e 's,"","${DOCSDIR}", ; s,"icons","${DATADIR}/icons",' \
+ -e '$$s,^$$,bitmaps_dir="${DATADIR}/bitmaps",' \
+ ${WRKSRC}/set_dir.py
+
+do-install:
+ ${INSTALL_SCRIPT} ${WRKSRC}/${PORTNAME}.py ${PREFIX}/bin/${PORTNAME}
+ @${MKDIR} ${PREFIX}/lib/${PORTNAME}
+ ${INSTALL_DATA} ${WRKSRC}/cal_year.py ${WRKSRC}/dialogs.py \
+ ${FILESDIR}/p_rotor.py ${WRKSRC}/save_load.py \
+ ${WRKSRC}/set_dir.py ${WRKSRC}/setup.py ${PREFIX}/lib/${PORTNAME}
+ @${MKDIR} ${DATADIR}/bitmaps ${DATADIR}/icons/mini ${DATADIR}/icons/large
+ ${INSTALL_DATA} ${WRKSRC}/bitmaps/*.[pb]* ${DATADIR}/bitmaps
+ ${INSTALL_DATA} ${WRKSRC}/icons/*.xpm ${DATADIR}/icons
+ ${INSTALL_DATA} ${WRKSRC}/icons/mini/*.xpm ${DATADIR}/icons/mini
+ ${INSTALL_DATA} ${WRKSRC}/icons/large/*.xpm ${DATADIR}/icons/large
+ # These two (cs, sk) are not in mtree yet
+ @${MKDIR} ${PREFIX}/share/locale/cs/LC_MESSAGES \
+ ${PREFIX}/share/locale/sk/LC_MESSAGES
+.for l in cs de ru sk
+ ${INSTALL_DATA} ${WRKSRC}/msg/${l}/LC_MESSAGES/${PORTNAME}.mo \
+ ${PREFIX}/share/locale/${l}/LC_MESSAGES
+.endfor
+ # Docs are kinda mandatory here since being used as internal help
+ @${MKDIR} ${DOCSDIR}
+ ${INSTALL_DATA} ${WRKSRC}/README*.html ${DOCSDIR}
+ ${INSTALL_MAN} ${FILESDIR}/${MAN1} ${MANPREFIX}/man/man1
+
+.include <bsd.port.mk>
diff --git a/deskutils/cycle/distinfo b/deskutils/cycle/distinfo
new file mode 100644
index 000000000000..bcc5c55a1126
--- /dev/null
+++ b/deskutils/cycle/distinfo
@@ -0,0 +1,2 @@
+MD5 (cycle-0.3.0.tar.bz2) = c0d5f27c0dd2a0345e6ecf4b013714f4
+SIZE (cycle-0.3.0.tar.bz2) = 40520
diff --git a/deskutils/cycle/files/cycle.1 b/deskutils/cycle/files/cycle.1
new file mode 100644
index 000000000000..15394c662af9
--- /dev/null
+++ b/deskutils/cycle/files/cycle.1
@@ -0,0 +1,85 @@
+.\" .ig
+.\" cycle manual page.
+.\"
+.\" Miriam Ruiz <little_miry@yahoo.es>, 2005.
+.\"
+.\" This next line loads the www macro package so that the .URL macro can be used.
+.\" ..
+.\" .mso www.tmac
+.TH "cycle" "1" "6 April 2005" "Miriam Ruiz" "Utils"
+.SH "NAME"
+.
+cycle \- a calendar for women
+.
+.SH "SYNOPSIS"
+.
+.B cycle
+.
+.SH "DESCRIPTION"
+.
+Cycle is a calendar program for women. Given a cycle length or statistics for several periods, it can calculate the days until menstruation, the days of "safe" sex, the fertile period, and the days to ovulations, and define the d.o.b. (date of birth) of a child. It allows the user to write notes and helps to supervise the reception of hormonal contraceptive tablets.
+.
+.SH "FEATURES"
+The program is capable of:
+.P
+ \- Calculate of the days of menstruation, based on length of the cycle or on statistics of a period.
+ \- Calculate the "safe" sex days, fertile period and day to ovulations
+ \- Definition of D.O.B . (Date Of Birth) of a child
+ \- Allows to write notes
+ \- Helps to supervise reception of hormonal contraceptive tablets
+.P
+.SH "HOW DOES IT WORK"
+It uses the calendar method for the definition of fertile days. For this is necessary to determine duration, at least, of last six cycles. For determine the fertile days it uses this algoritm:
+.P
+ \- First day: duration of shortest cycle minus 18
+ \- Last day: duration of longest cycle minus 11
+ \- Ovulation: is considered in the middle of fertile period (Determine the exact day isn't possible with the calendar method)
+.P
+
+Date of a birth of the child is counted from the beginning of last menstruation (in obstetrics are accepted 40 weeks). This date is corrected with the duration of a cycle (are subtracted or added same number of days that a cycle differs from 28 days). Is possible check the results at: http://cir.msk.ru/sroki.shtml (in Russian)
+.SH "USAGE"
+.
+It is necessary to mark the beginning of menstruation. This is possible clicking with the right button on the date and chosing "The beginning of a cycle". Similarly the mark can be removed. Using duration of last six cycles, the program will calculate
+
+.P
+ \- Fertile period \- green cells
+ \- Ovulation day (the middle fertile period) \- brightly green cell
+ \- Beginning of following menstruation \- pink cells
+.P
+
+Cycle duration is set in options or is calculated an average of last six periods.
+
+To determine prospective date of a birth of the child, it is necessary first day of last cycle to mark in addition as "Pregnancy".
+
+Depending on your purposes, you can display only "Safe" sex days or only fertile days. Information about interesting day can be received clicking with left button.
+
+Is possible adding a note to any date using corresponding item of the menu. Day with a note are underlined.
+
+It is necessary to note that factor of failures of calendar contraception method is about 10 percent. This method is suitable only for women with enough regular cycle.
+
+If your doctor has recommended hormonal contraceptive this program will help to supervise their reception. Closely familiarize with the instruction applied to the chosen preparation. Packing can contain 21 tablet (the circuit of reception 21 day on one tablet, then 7 days pause) or 28 tablets in this case all tablets are accepted without interruption every day of 28. In the program, is marked only day of reception of each first tablet of packing.
+
+NOTE: This program is not a reliable contraceptive method. It does neither help to prevent sexual transmision diseases like AIDS. It is just an electronic means of keeping track of some of your medical data and extract some statistical conclusions from them. You cannot consider this program as a substitute for your gynecologist in any way.
+.
+.SH "FILES"
+.
+.TP
+.I ~/.cycle
+This is the directory where cycle stores the data.
+.
+.SH "AUTHOR"
+.
+cycle was written by Oleg S. Gints.
+.P
+This manual page was written for Debian by Miriam Ruiz <little_miry@yahoo.es>.
+.
+.SH "SEE ALSO"
+.
+You can find cycle's home page at:
+.URL http://cycle.sourceforge.net/
+http://cycle.sourceforge.net/
+.P
+More information about calendar method are available at:
+.URL http://www.mama.ru/gynecolog/STA/st18.htm
+http://www.mama.ru/gynecolog/STA/st18.htm (in Russian)
+.
diff --git a/deskutils/cycle/files/p_rotor.py b/deskutils/cycle/files/p_rotor.py
new file mode 100644
index 000000000000..ed0467761cfa
--- /dev/null
+++ b/deskutils/cycle/files/p_rotor.py
@@ -0,0 +1,227 @@
+"""This module was written by Gerd Woetzel:
+ http://mail.python.org/pipermail/python-list/2005-January/261304.html
+
+
+ This module is derived from Modules/rotormodule.c and translated
+ into Python. I have appended the Copyright by Lance Ellinghouse
+ below. The rotor module has been removed from the Python 2.4
+ distribution because
+
+ the rotor module uses an insecure algorithm and is deprecated.
+ ==============================================================
+
+ Of course, this does still hold. However, I think this module might
+ be used and adapted for demonstration purposes and might help some
+ poor users who have encrypted (or obfuscated) some old stuff with
+ the rotor module and have no access to older Python versions any
+ more.
+
+ Documentation can be found in
+
+ Python Library Reference, Guido van Rossum, Fred L. Drake, Jr., editor,
+ PythonLabs, Release 2.3.4 May 20, 2004
+ <http://www.python.org/doc/2.3.4/lib/module-rotor.html>
+
+ #####################################################################
+ Copyright 1994 by Lance Ellinghouse,
+ Cathedral City, California Republic, United States of America.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation, and that the name of Lance Ellinghouse
+ not be used in advertising or publicity pertaining to distribution
+ of the software without specific, written prior permission.
+
+ LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #####################################################################
+"""
+
+class newrotor(object):
+
+ def __init__(self, key, n_rotors=6):
+ self.n_rotors = n_rotors
+ self.setkey(key)
+
+ def setkey(self, key):
+ self.key = key
+ self.rotors = None
+ self.positions = [None, None]
+
+ def encrypt(self, buf):
+ # Reset (encrypt) positions and encryptmore
+ self.positions[0] = None
+ return self.cryptmore(buf, 0)
+
+ def encryptmore(self, buf):
+ return self.cryptmore(buf, 0)
+
+ def decrypt(self, buf):
+ # Reset decrypt positions and decryptmore
+ self.positions[1] = None
+ return self.cryptmore(buf, 1)
+
+ def decryptmore(self, buf):
+ return self.cryptmore(buf, 1)
+
+ def cryptmore(self, buf, do_decrypt):
+ size, nr, rotors, pos = self.get_rotors(do_decrypt)
+ outbuf = []
+ append = outbuf.append
+ for c in map(ord, buf):
+ if do_decrypt:
+ # Apply decrypt rotors and xor in reverse order
+ for i in xrange(nr-1,-1,-1):
+ c = pos[i] ^ rotors[i][c]
+ else:
+ # Apply xor and ecrypt rotors
+ for i in xrange(nr):
+ c = rotors[i][c ^ pos[i]]
+ append(c)
+
+ # Advance rotors, i.e. add the (fixed) rotor increments to the
+ # variable rotor positions with carry.
+ # Note: In the C-implementation, the result of the carry addition
+ # was stored to an "unsigned char". Hence the next carry
+ # 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 = ((pos[i] + (pnew >= size)) & 0xff) + rotors[i][size]
+ pos[i] = pnew % size
+
+ return ''.join(map(chr, outbuf))
+
+ def get_rotors(self, do_decrypt):
+ # Return a tuple (size, nr, rotors, positions) where
+ # - size is the rotor size (== 256, because of 8-bit bytes)
+ # - nr is the number of rotors.
+ # - rotors is a tuple of nr encrypt or nr decrypt rotors
+ # for do_decrypt == 0 or do_decrypt == 1 respectively.
+ # - postions is a list of nr "rotor positions".
+ #
+ # The rotors represent the static aspect of the rotor machine which
+ # is initially computed from key and fixed during en/decryption.
+ # A rotor is a random permutation of range(size) extended
+ # by an "increment value" in range(size).
+ #
+ # The followng statements hold for a tuple of encrypt rotors E and
+ # and the corresponding tuple of decrypt rotors D.
+ #
+ # D[i][E[i][j]] == j for i in range(nr) for j in range(size)
+ #
+ # E[i][D[i][j]] == j for i in range(nr) for j in range(size)
+ #
+ # This means that the corresponding rotors E[i] and D[i] are
+ # inverse permutations.
+ # The increments are equal for the corresponding encrypt and
+ # decrypt rotors and have an odd value:
+ #
+ # D[i][size] == E[i][size] and E[i][size] == 1 mod 2 and
+ # 0 < E[i][size] < size for i in range(nr)
+ #
+ # The position vector represents the dynamic aspect.
+ # It changes after each en/decrypted character (the rotors
+ # are "advanced"). The initial position vector is also computed
+ # from the key
+ #
+ nr = self.n_rotors
+ rotors = self.rotors
+ positions = self.positions[do_decrypt]
+
+ if positions is None:
+ if rotors:
+ positions = list(rotors[3])
+ else:
+ # Generate identity permutation for 8-bit bytes plus an
+ # (unused) increment value
+ self.size = size = 256
+ id_rotor = range(size+1)
+
+ # Generate nr "random" initial positions and "random"
+ # en/decrypt rotors from id_rotor.
+ #
+ rand = random_func(self.key)
+ E = []
+ D = []
+ positions = []
+ for i in xrange(nr):
+ i = size
+ positions.append(rand(i))
+ erotor = id_rotor[:]
+ drotor = id_rotor[:]
+ drotor[i] = erotor[i] = 1 + 2*rand(i/2) # increment
+ while i > 1:
+ r = rand(i)
+ i -= 1
+ er = erotor[r]
+ erotor[r] = erotor[i]
+ erotor[i] = er
+ drotor[er] = i
+ drotor[erotor[0]] = 0
+ E.append(tuple(erotor))
+ D.append(tuple(drotor))
+ self.rotors = rotors = (
+ tuple(E), tuple(D), size, tuple(positions))
+ 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)
+
+ # 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
+
+ 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
+ # At least all values are > 0 by now but may be greater than expected ..
+
+ def rand(n, seed=[(x, y, z)]):
+ # Return a random number 0 <= r < n
+ #
+ x, y, z = seed[0]
+ seed[0] = ((171*x) % 30269, (172*y) % 30307, (170*z) % 30323)
+ return int((x/30269.0 + y/30307.0 + z/30323.0) * n) % n
+
+ # Original code was like this:
+ # from math import floor
+ # val = x/30269.0 + y/30307.0 + z/30323.0
+ # val = val - floor(val)
+ # if val >= 1.0:
+ # val = 0.0
+ # n = int(val*n) % n
+
+ return rand
+
diff --git a/deskutils/cycle/files/patch-cal_year.py b/deskutils/cycle/files/patch-cal_year.py
new file mode 100644
index 000000000000..b3e44a8794ea
--- /dev/null
+++ b/deskutils/cycle/files/patch-cal_year.py
@@ -0,0 +1,237 @@
+--- cal_year.py.orig
++++ cal_year.py
+@@ -45,15 +45,20 @@
+ 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:
++ #if '__WXMSW__' in wx.PlatformInfo:
++ if False:
+ 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.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
++ wx.EVT_RIGHT_DOWN(self, self.OnRightDown)
++ #self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
++ wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
++ #self.Bind(wx.EVT_KEY_UP, self.OnKey)
++ wx.EVT_KEY_UP(self, self.OnKey)
++ #self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
++ wx.EVT_KEY_DOWN(self, self.OnKey)
+ self.d_click=wx.DateTime()#FromDMY(1, 0,2002)
+
+ def OnLeftDown(self, event):
+@@ -80,10 +85,14 @@
+ 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.Bind(wx.EVT_MENU, self.OnBegin, id=2)
++ wx.EVT_MENU(self, 2, self.OnBegin)
++ #self.Bind(wx.EVT_MENU, self.OnLast, id=3)
++ wx.EVT_MENU(self, 3, self.OnLast)
++ #self.Bind(wx.EVT_MENU, self.OnNote, id=4)
++ wx.EVT_MENU(self, 4, self.OnNote)
++ #self.Bind(wx.EVT_MENU, self.OnTablet, id=5)
++ wx.EVT_MENU(self, 5, self.OnTablet)
+ self.PopupMenu(menu, event.GetPosition())
+ menu.Destroy()
+
+@@ -139,8 +148,8 @@
+
+ def OnKey(self, event):
+ k=event.GetKeyCode()
+- if k==WXK_LEFT or k==WXK_RIGHT or \
+- k==WXK_UP or k==WXK_DOWN:
++ if k==wx.WXK_LEFT or k==wx.WXK_RIGHT or \
++ k==wx.WXK_UP or k==wx.WXK_DOWN:
+ pass
+ else:
+ event.Skip()
+@@ -337,7 +346,8 @@
+
+ last_6=[]
+ for k in range(i,0,-1):
+- span=(cycle.begin[k]-cycle.begin[k-1]+wx.TimeSpan.Hours(1)).GetDays()
++ #span=(cycle.begin[k]-cycle.begin[k-1]+wx.TimeSpan.Hours(1)).GetDays()
++ 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)
+@@ -367,27 +377,34 @@
+ 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:
++ #if (cycle.begin[i+1]-cycle.begin[i]+wx.TimeSpan.Hours(1)).GetDays()<21:
++ 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
++ #begin = d+wx.DateSpan.Days( min-18 ) # begin fertile
++ begin = d+wx.DateSpan_Days( min-18 ) # begin fertile
++ #end = d+wx.DateSpan.Days( max-11 ) # end fertile
++ end = d+wx.DateSpan_Days( max-11 ) # end fertile
++ #ovul=end-wx.DateSpan.Days(((max-11)-(min-18))/2) #day of ovul
++ 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()
++ #last_cycle=(cycle.begin[i+1]-cycle.begin[i]+wx.TimeSpan.Hours(1)).GetDays()
++ last_cycle=(cycle.begin[i+1]-cycle.begin[i]+wx.TimeSpan_Hours(1)).GetDays()
+ if last_cycle>35:
+- stop=d+wx.DateSpan.Days( 35 )
++ #stop=d+wx.DateSpan.Days( 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 )
++ #stop=d+wx.DateSpan.Days( cycle.period-1 )
++ stop=d+wx.DateSpan_Days( cycle.period-1 )
+
+ if (stop<year_b or start>year_e) and (d not in cycle.last):
+ continue
+@@ -400,7 +417,8 @@
+ f=f+wx.DateSpan_Day()
+
+ if d in cycle.last: # calc birthday
+- birth = d+wx.DateSpan.Days(280+cycle.period-28)
++ #birth = d+wx.DateSpan.Days(280+cycle.period-28)
++ 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)
+@@ -410,7 +428,8 @@
+
+ # prognosis to future cycles
+ cycle.prog_begin=[]
+- d=d+wx.DateSpan.Days( cycle.period )
++ #d=d+wx.DateSpan.Days( cycle.period )
++ 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
+@@ -418,15 +437,21 @@
+ # 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
++ #begin = d+wx.DateSpan.Days( min-18 ) #начало периода
++ begin = d+wx.DateSpan_Days( min-18 ) #начало периода
++ #end = d+wx.DateSpan.Days( max-11 ) #конец периода
++ end = d+wx.DateSpan_Days( max-11 ) #конец периода
++ #ovul=end-wx.DateSpan.Days(((max-11)-(min-18))/2) #day of ovul
++ 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 )
++ #start=d+wx.DateSpan.Day()
++ start=d+wx.DateSpan_Day()
++ #stop=d+wx.DateSpan.Days( cycle.period-1 )
++ stop=d+wx.DateSpan_Days( cycle.period-1 )
++ #d=d+wx.DateSpan.Days( cycle.period )
++ d=d+wx.DateSpan_Days( cycle.period )
+
+ if stop<year_b or start>year_e : continue
+
+@@ -448,15 +473,19 @@
+ 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:
++ #if (cycle.tablet[i+1]-cycle.tablet[i]+wx.TimeSpan.Hours(1)).GetDays()<28:
++ 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 |
++ #remove_mark(d+wx.DateSpan.Days(k), MARK_PROG | MARK_FERT |
++ 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)
++ #add_mark(d+wx.DateSpan.Days(k), MARK_T22_28, year)
++ add_mark(d+wx.DateSpan_Days(k), MARK_T22_28, year)
++ #add_mark(d+wx.DateSpan.Days(28), MARK_NEXT_TABLET, year)
++ add_mark(d+wx.DateSpan_Days(28), MARK_NEXT_TABLET, year)
+
+
+
+@@ -502,8 +531,10 @@
+ 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
++ #if day.IsBetween(d, d+wx.DateSpan.Days(28)):
++ if day.IsBetween(d, d+wx.DateSpan_Days(28)):
++ #t=(day-d+wx.TimeSpan.Hours(1)).GetDays()+1
++ t=(day-d+wx.TimeSpan_Hours(1)).GetDays()+1
+ s+=" - "
+ if t<=28:
+ s+=_('tablet N ')+str(t)
+@@ -532,7 +563,8 @@
+ 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)
++ #d=d+wx.DateSpan.Days(cycle.period)
++ d=d+wx.DateSpan_Days(cycle.period)
+ find=2
+
+
+@@ -543,10 +575,12 @@
+ if d2 in cycle.last:
+ gestation=1
+ elif find==2:
+- d2=d-wx.DateSpan.Days(cycle.period)
++ #d2=d-wx.DateSpan.Days(cycle.period)
++ d2=d-wx.DateSpan_Days(cycle.period)
+
+ if gestation:
+- k=(day-d2+wx.TimeSpan.Hours(1)).GetDays()+1
++ #k=(day-d2+wx.TimeSpan.Hours(1)).GetDays()+1
++ 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')
+@@ -555,10 +589,13 @@
+ if (k-w*7) == 1: s+=_(' 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()
++ p=(d-d2+wx.TimeSpan_Hours(1)).GetDays()
++ #k=(day-d2+wx.TimeSpan.Hours(1)).GetDays()+1
++ k=(day-d2+wx.TimeSpan_Hours(1)).GetDays()+1
+
+- d=d-wx.DateSpan.Day()
++ #d=d-wx.DateSpan.Day()
++ 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')
+ return s
diff --git a/deskutils/cycle/files/patch-cycle.py b/deskutils/cycle/files/patch-cycle.py
new file mode 100644
index 000000000000..70ab91234e9a
--- /dev/null
+++ b/deskutils/cycle/files/patch-cycle.py
@@ -0,0 +1,140 @@
+--- cycle.py.orig
++++ cycle.py
+@@ -8,8 +8,16 @@
+ #===================================================
+ import os, sys, gettext
+ import locale
++
++prefix = os.path.split(os.path.dirname(sys.argv[0]))[0]
++sys.path.append(os.path.join(prefix, 'lib', 'cycle'))
++
++#import wxversion
++#wxversion.select("2.4")
++#wxversion.ensureMinimal('2.5.3')
+ import wx
+ import wx.html
++import wx.lib.colourdb
+
+ from cal_year import *
+ from save_load import *
+@@ -19,36 +27,49 @@
+
+ import gettext
+ import __builtin__
+-lang_find=0
+-if os.environ.has_key('LANGUAGE'):
+- env_language=os.environ['LANGUAGE']
+- for s_lang in env_language.split(':'): # if set more languages
+- os.environ['LANGUAGE']=s_lang
+- try:
+- dl=locale.getdefaultlocale()
+- lang=[ dl[0][0:2] ]
+- l=gettext.translation('cycle', msg_dir, lang)
+- __builtin__.__dict__['_'] = lambda s: l.ugettext(s).encode(dl[1])
+- _('try decode this string')
+- lang_find=1
+- break #language is finded
+- except:
+- pass
+-else: #for Windows
++lang_find=False
++#if not '__WXMSW__' in wx.PlatformInfo:
++if True:
++ 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
++ #print "Using language \"%s\"." % (lang)
++ except:
++ pass
++else: #for MS Windows
+ try:
+ dl=locale.getdefaultlocale()
+ lang=[ dl[0][0:2] ]
+ l=gettext.translation('cycle', msg_dir, lang)
+- __builtin__.__dict__['_'] = lambda s: l.ugettext(s).encode(dl[1])
++ 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=1
++ lang_find=True
++ #print "Using language \"%s\"." % (lang)
+ except:
+ pass
+
+ if not lang_find:
+ __builtin__.__dict__['_'] = lambda s: s
+ lang=[""]
+-
++ #print "Language NOT found."
+
+ class MyFrame(wx.Frame):
+ def __init__(self, parent, ID, title):
+@@ -79,35 +100,33 @@
+ tb = self.CreateToolBar(wx.TB_HORIZONTAL|wx.NO_BORDER)
+ tb.SetToolBitmapSize( wx.Size(24,24) )
+
+- bmp_path = 'bitmaps/'
+-
+- SetToolPath(self, tb, 10, bmp_path + 'dec.png', _('Dec Year'))
++ SetToolPath(self, tb, 10, os.path.join(bitmaps_dir,'dec.png'), _('Dec Year'))
+ wx.EVT_TOOL(self, 10, self.OnDecYear)
+
+- SetToolPath(self, tb, 20, bmp_path + 'curr.png', _('Current Year'))
++ SetToolPath(self, tb, 20, os.path.join(bitmaps_dir,'curr.png'), _('Current Year'))
+ wx.EVT_TOOL(self, 20, self.OnCurrent)
+
+- SetToolPath(self, tb, 30, bmp_path + 'inc.png', _('Inc Year'))
++ 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, bmp_path + 'legend.png', _('Legend'))
++ SetToolPath(self, tb, 40, os.path.join(bitmaps_dir,'legend.png'), _('Legend'))
+ wx.EVT_TOOL(self, 40, self.Legend)
+
+- SetToolPath(self, tb, 50, bmp_path + 'set.png', _('Settings'))
++ SetToolPath(self, tb, 50, os.path.join(bitmaps_dir,'set.png'), _('Settings'))
+ wx.EVT_TOOL(self, 50, self.Settings)
+
+- SetToolPath(self, tb, 55, bmp_path + 'help.png', _('Help'))
++ SetToolPath(self, tb, 55, os.path.join(bitmaps_dir,'help.png'), _('Help'))
+ wx.EVT_TOOL(self, 55, self.Info)
+
+-# SetToolPath(self, tb, 57, bmp_path + 'help.png', _('Print'))
++# SetToolPath(self, tb, 57, os.path.join(bitmaps_dir,'help.png'), _('Print'))
+ # wx.EVT_TOOL(self, 57, self.test)
+
+ tb.AddSeparator()
+
+- SetToolPath(self, tb, 60, bmp_path + 'exit.png', _('Exit'))
++ SetToolPath(self, tb, 60, os.path.join(bitmaps_dir,'exit.png'), _('Exit'))
+ wx.EVT_TOOL(self, 60, self.TimeToQuit)
+
+ tb.Realize()
+@@ -163,6 +182,7 @@
+
+ class MyApp(wx.App):
+ def OnInit(self):
++ wx.lib.colourdb.updateColourDB()
+ ret=first_login()
+ if ret=='bad_login':
+ return True
diff --git a/deskutils/cycle/files/patch-dialogs.py b/deskutils/cycle/files/patch-dialogs.py
new file mode 100644
index 000000000000..f59743705437
--- /dev/null
+++ b/deskutils/cycle/files/patch-dialogs.py
@@ -0,0 +1,284 @@
+--- dialogs.py.orig
++++ dialogs.py
+@@ -9,8 +9,8 @@
+ import wx
+ import wx.html
+ from cal_year import cycle , Val
+-from save_load import Load_Cycle, get_f_name
+-
++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):
+@@ -23,7 +23,8 @@
+ 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.Bind(wx.EVT_CHECKBOX, self.By_Average, id=i)
++ wx.EVT_CHECKBOX(self, i, self.By_Average)
+ self.cb1.SetValue(cycle.by_average)
+
+ b2 = wx.BoxSizer(wx.HORIZONTAL)
+@@ -58,21 +59,25 @@
+ 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)
++ #self.Bind(wx.EVT_BUTTON, self.OnColours, id=i)
++ wx.EVT_BUTTON(self, i, self.OnColours)
+ #======================
+ 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)
++ #self.Bind(wx.EVT_BUTTON, self.OnChangePasswd, id=i)
++ wx.EVT_BUTTON(self, i, self.OnChangePasswd)
+
+ #======================
+ 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)
++ #self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
++ wx.EVT_BUTTON(self, i, self.OnOk)
+
+ i=wx.NewId()
+ but_box.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+- self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ #self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ wx.EVT_BUTTON(self, i, self.OnCancel)
+
+ box.Add(but_box, 0, wx.ALIGN_CENTER)
+
+@@ -135,11 +140,13 @@
+ 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)
++ #self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
++ wx.EVT_BUTTON(self, i, self.OnOk)
+
+ i=wx.NewId()
+ b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+- self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ #self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ wx.EVT_BUTTON(self, i, self.OnCancel)
+ self.pass1.SetFocus()
+ box.Add(b1, 0, wx.ALIGN_CENTER)
+
+@@ -185,7 +192,7 @@
+ #======== List users ==============
+ i = wx.NewId()
+ self.il = wx.ImageList(16, 16,True)
+- bmp=wx.Bitmap('bitmaps/smiles.bmp', wx.BITMAP_TYPE_BMP)
++ bmp=wx.Bitmap(os.path.join(bitmaps_dir, 'smiles.bmp'), wx.BITMAP_TYPE_BMP)
+ mask = wx.Mask(bmp, wx.WHITE)
+ bmp.SetMask(mask)
+
+@@ -201,25 +208,30 @@
+ self.list.SetItemState(0, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
+ self.name=users[0]
+
+- self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list)
+- self.list.Bind(wx.EVT_LIST_KEY_DOWN, self.OnKeyDown, self.list)
++ #self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list)
++ wx.EVT_LIST_ITEM_SELECTED(self, i, self.OnItemSelected)
++ #self.list.Bind(wx.EVT_LIST_KEY_DOWN, self.OnKeyDown, self.list)
++ wx.EVT_KEY_DOWN(self.list, self.OnKeyDown)
+
+ 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)
++ #self.Bind(wx.EVT_BUTTON, self.OnAdd, id=i)
++ wx.EVT_BUTTON(self, i, self.OnAdd)
+
+ #========= 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)
++ #self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
++ wx.EVT_BUTTON(self, i, self.OnOk)
+
+ i=wx.NewId()
+ b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+- self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ #self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ wx.EVT_BUTTON(self, i, self.OnCancel)
+ box.Add(b1, 0, wx.ALIGN_CENTER)
+
+ self.SetAutoLayout(True)
+@@ -267,34 +279,56 @@
+ if os.path.exists(p):
+ users=os.listdir(p)
+ if users != []:
+- return 'not_first' #user(s) already exist
++ return 'not_first' #user(s) already exists
+ if ask_name():
+ return 'first'
+ else:
+ return 'bad_login'
+
+ #-------------------------------------------------------
++def check_validname(str):
++ i=0
++ while i<len(str):
++ if ord(str[i])<0x20 or ord(str[i])>0x7f:
++ return False
++ i=i+1
++ return str.isalnum();
++
++#-------------------------------------------------------
+ def ask_name(parent=None):
+ # nobody, it is first login
++ wx.MessageBox(
++ _("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 you name:'),_('New user'),'',
+ style=wx.OK | wx.CANCEL)
+ while dlg.ShowModal()==wx.ID_OK:
+ name=dlg.GetValue()
++ name=name.strip()
+ if name != "":
+- p, f_name=get_f_name(name)
+- if not os.path.isfile(f_name):
+- d=Ask_Passwd_Dlg(parent)
+- if d.ShowModal()==wx.ID_OK:
+- cycle.name=name
+- d.Destroy()
+- dlg.Destroy()
+- #self.EndModal(wx.ID_OK)
+- return True
+- else:
+- d.Destroy()
+- continue
++ if check_validname(name):
++ #name=name.encode("ascii")
++ p, f_name=get_f_name(name)
++ if not os.path.isfile(f_name):
++ d=Ask_Passwd_Dlg(parent)
++ if d.ShowModal()==wx.ID_OK:
++ 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+_(' - already is exist!')
++ err=name+_(' - has invalid characters!')
+ else:
+ err=_('Name must be not EMPTY')
+ d2 = wx.MessageDialog(dlg, err, _('Error!'), wx.OK |wx.ICON_ERROR )
+@@ -326,7 +360,8 @@
+
+ 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.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
++ wx.EVT_BUTTON(self, i, self.OnOk)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(box)
+@@ -360,15 +395,18 @@
+ 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)
++ #self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
++ wx.EVT_BUTTON(self, i, self.OnOk)
+
+ i=wx.NewId()
+ b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+- self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ #self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ wx.EVT_BUTTON(self, i, self.OnCancel)
+
+ i=wx.NewId()
+ b1.Add(wx.Button(self, i, _('Remove')), 0, wx.ALL, 10)
+- self.Bind(wx.EVT_BUTTON, self.OnRemove, id=i)
++ #self.Bind(wx.EVT_BUTTON, self.OnRemove, id=i)
++ wx.EVT_BUTTON(self, i, self.OnRemove)
+ box.Add(b1, 0, wx.ALIGN_CENTER)
+
+ self.SetAutoLayout(True)
+@@ -413,7 +452,8 @@
+
+ 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.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
++ wx.EVT_BUTTON(self, i, self.OnOk)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(box)
+@@ -448,15 +488,18 @@
+ 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)
++ #self.Bind(wx.EVT_BUTTON, self.OnOk, id=i)
++ wx.EVT_BUTTON(self, i, self.OnOk)
+
+ i=wx.NewId()
+ b1.Add(wx.Button(self, i, _('By default')), 0, wx.ALL, 10)
+- self.Bind(wx.EVT_BUTTON, self.OnDefault, id=i)
++ #self.Bind(wx.EVT_BUTTON, self.OnDefault, id=i)
++ wx.EVT_BUTTON(self, i, self.OnDefault)
+
+ i=wx.NewId()
+ b1.Add(wx.Button(self, i, _('Cancel')), 0, wx.ALL, 10)
+- self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ #self.Bind(wx.EVT_BUTTON, self.OnCancel, id=i)
++ wx.EVT_BUTTON(self, i, self.OnCancel)
+ box.Add(b1, 0, wx.ALIGN_CENTER)
+
+ self.SetAutoLayout(True)
+@@ -466,8 +509,9 @@
+ 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=wx.Button(self, i, "", size=wx.Size(15,15))
++ #self.Bind(wx.EVT_BUTTON, self.get_colour, id=i)
++ wx.EVT_BUTTON(self, i, self.get_colour)
+ bt.SetBackgroundColour(self.col_set[col])
+ self.buttons.update({i:bt})
+ b.Add(bt, 0, wx.LEFT|wx.RIGHT,10)
+@@ -490,15 +534,15 @@
+ self.EndModal(wx.ID_OK)
+
+ def OnDefault(self, event):
+- self.col_set = {'begin':wx.NamedColour('red'),
+- 'prog begin':wx.NamedColour('pink'),
++ 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'),
++ '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')}
++ '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])
+
diff --git a/deskutils/cycle/files/patch-save_load.py b/deskutils/cycle/files/patch-save_load.py
new file mode 100644
index 000000000000..6c440caf3357
--- /dev/null
+++ b/deskutils/cycle/files/patch-save_load.py
@@ -0,0 +1,48 @@
+--- save_load.py.orig
++++ save_load.py
+@@ -12,8 +12,12 @@
+ message='.*rotor module', module=__name__)
+
+ import wx
+-import os, os.path , cPickle, rotor, md5
++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'):
+ """ Save the contents of our document to disk.
+@@ -99,7 +103,8 @@
+
+ #-------------------------------------------------------
+ def get_f_name(name=""):
+- if '__WXMSW__' in wx.PlatformInfo:
++ #if '__WXMSW__' in wx.PlatformInfo:
++ if False:
+ p=os.getcwd()+"\\data"
+ f_name=p+"\\"+name
+ else:
+@@ -110,14 +115,14 @@
+
+ #-------------------------------------------------------
+ def set_color_default():
+- cal_year.cycle.colour_set={'begin':wx.NamedColour('red'),
+- 'prog begin':wx.NamedColour('pink'),
++ 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'),
++ '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')}
++ '1-st tablet':wx.NamedColour('GOLD'),
++ 'pause':wx.NamedColour('LIGHT BLUE'),
++ 'next 1-st tablet':wx.NamedColour('PINK')}
+
+
diff --git a/deskutils/cycle/pkg-descr b/deskutils/cycle/pkg-descr
new file mode 100644
index 000000000000..e43323029dbd
--- /dev/null
+++ b/deskutils/cycle/pkg-descr
@@ -0,0 +1,21 @@
+Cycle is a calendar for women. Given a cycle length or statistics for
+several periods, it can calculate the days until menstruation, the days of
+"safe" sex, the fertile period, the days to ovulation, and define the date
+of date of birth of a child. It allows the user to write notes and helps to
+supervise the reception of hormonal contraceptive tablets. Main features:
+
+ - Calculate days of menstruation, based on the length of the cycle or on
+ statistics of previous periods
+ - Calculate days of "safe" sex, fertile period and day to ovulation
+ - Definition of D.o.B. (Date of Birth) of a child
+ - Allows to write notes
+ - Helps to supervise reception of hormonal contraceptive tablets
+ - Multiple users allowed, data is protected by a password for every user
+
+NOTE: This program is not a reliable contraceptive method. It neither does
+help to prevent sexual transmission diseases like AIDS. It is just a nice
+tool for 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. You have been warned!
+
+WWW: http://cycle.sourceforge.net/
diff --git a/deskutils/cycle/pkg-plist b/deskutils/cycle/pkg-plist
new file mode 100644
index 000000000000..ce5596ffacfe
--- /dev/null
+++ b/deskutils/cycle/pkg-plist
@@ -0,0 +1,35 @@
+bin/cycle
+lib/cycle/cal_year.py
+lib/cycle/dialogs.py
+lib/cycle/p_rotor.py
+lib/cycle/save_load.py
+lib/cycle/set_dir.py
+lib/cycle/setup.py
+@dirrm lib/cycle
+%%DATADIR%%/bitmaps/curr.png
+%%DATADIR%%/bitmaps/dec.png
+%%DATADIR%%/bitmaps/exit.png
+%%DATADIR%%/bitmaps/help.png
+%%DATADIR%%/bitmaps/inc.png
+%%DATADIR%%/bitmaps/legend.png
+%%DATADIR%%/bitmaps/set.png
+%%DATADIR%%/bitmaps/smiles.bmp
+@dirrm %%DATADIR%%/bitmaps
+%%DATADIR%%/icons/mini/cycle.xpm
+@dirrm %%DATADIR%%/icons/mini
+%%DATADIR%%/icons/large/cycle.xpm
+@dirrm %%DATADIR%%/icons/large
+%%DATADIR%%/icons/cycle.xpm
+@dirrm %%DATADIR%%/icons
+share/locale/cs/LC_MESSAGES/cycle.mo
+share/locale/de/LC_MESSAGES/cycle.mo
+share/locale/ru/LC_MESSAGES/cycle.mo
+share/locale/sk/LC_MESSAGES/cycle.mo
+@unexec rmdir %D/share/locale/cs/LC_MESSAGES 2>/dev/null || true
+@unexec rmdir %D/share/locale/cs 2>/dev/null || true
+@unexec rmdir %D/share/locale/sk/LC_MESSAGES 2>/dev/null || true
+@unexec rmdir %D/share/locale/sk 2>/dev/null || true
+%%DOCSDIR%%/README.html
+%%DOCSDIR%%/README_de.html
+%%DOCSDIR%%/README_ru.html
+@dirrm %%DOCSDIR%%