[Debian-islamic-commits] [othman] 02/07: Imported Upstream version 0.3.0

أحمد المحمودي (Ahmed El-Mahmoudy) aelmahmoudy at sabily.org
Mon Mar 31 15:28:31 UTC 2014


This is an automated email from the git hooks/post-receive script.

aelmahmoudy-guest pushed a commit to branch master
in repository othman.

commit c089f8ed4c7a77fce845eee62629bd6aae3d4320
Author: أحمد المحمودي (Ahmed El-Mahmoudy) <aelmahmoudy at sabily.org>
Date:   Mon Mar 31 14:14:46 2014 +0200

    Imported Upstream version 0.3.0
---
 LICENSE-ar.txt        | 138 ---------
 LICENSE-en            | 222 --------------
 TODO                  |   4 +
 exe-setup.py          |  51 ++--
 gen-index.py          |  12 +-
 othman.spec           |  56 ++--
 othman/core.py        | 397 +++++++++++++------------
 othman/gtkUi.py       | 779 ++++++++++++++++++++++++++------------------------
 othman/univaruints.py | 302 +++++++++++++++++++
 othman/varuints.py    | 170 -----------
 po/ar.po              |  34 ++-
 po/de.po              |  37 ++-
 po/othman.pot         |  33 ++-
 waqf2-ar.pdf          | Bin 0 -> 69252 bytes
 14 files changed, 1057 insertions(+), 1178 deletions(-)

diff --git a/LICENSE-ar.txt b/LICENSE-ar.txt
deleted file mode 100644
index 8f8ce80..0000000
--- a/LICENSE-ar.txt
+++ /dev/null
@@ -1,138 +0,0 @@
-   بسم الله الرحمن الرحيم
-
-                                         رخصة "وقف" العامة
-
-                                               مقدمة
-
-   إن نشر أي عمل فكري (برنامج حاسوبي أو كتاب على سبيل المثال لا الحصر) لا يكون بالبيع وإن بدا
-   كذلك بل يكون باتفاقية ضمنية لا قيمة لها لولا مفهوم الملكية الفكرية الذي رسخته القوانين الوضعة
-   التي يفترض أنها وضعت لحفز نشر الأعمال الفكرية النافعة. ترتكز الملكية الفكرية على أن أول مودع
-   العمل (يسمى المالك Owner أو copyright holder وسنشير له في هذه الوثيقة باسم صاحب العمل) يملك
-   الحق في العمل بصورته المعنوية على أي وسيط مادي كان وله حق التصرف في ملكه المزعوم. إن أي
-   استعمال للعمل الفكري دون الإذن المسبق الصريح من مالك العمل يعد مكافئا أخلاقيا لسرقة السفن أو
-   “قرصنة” بنظرهم. هذا الإذن يسمى “رخصة License” وتهدف تلك الرخص غالبا لإعطاء المالك (غالبا
-   الناشر) أفضلية في السوق أمام الناشرين الآخرين من خلال احتكار العمل وذلك بفرض قيود على
-   المستخدمين لا الناشرين. تسمى مثل تلك الأعمال بالأعمال “المملوكة Proprietary”.
-
-   إننا نرى أن هذه الاتفاقيات (الرخص المملوكة) مجحفة جدا لكننا ندرك إن قبول اتفاقية معينة (مثل
-   رخص البرامج المملوكة) وأنت تضمر مسبقا خرقها أمر غير أخلاقي ^1). لهذا فنحن لا نحل المشكلة
-   بمشكلة أخرى بل إننا نقدم البديل.
-
-   نحن لدينا رؤية مختلفة فنحن نقدم أعمالنا الفكرية من برامج حاسوبية وغيرها ابتغاء وجه الله، والتي
-   هي الركيزة الأساسية لهذه الرخصة التي تميزها عن الرخص المملوكة وعلى أي غاية آخرى (مثل نشر العلم
-   النافع أو جني الأرباح) أن تتحقق بوسيلة لا تخالف هذا الهدف الأسمى.
-
-   في قناعتنا - التي لا نلزم أحدا بها والتي لا يضيرك أن لا تشترك معنا فيها - أن الاسلام يحرم
-   وبشكل قطعي حكر العلم والمعرفة والانتاج الفكري على وجه العموم، وهذا التحريم يأتي من عدة أوجه :
-
-     * الحديث النبوي الشريف : “من كتم علما ألجمه الله يوم القيامة بلجام من نار” ^2) وقد جاءت
-       كلمة العلم نكرة عامة فهي تنطبق على كل علم ينتفع الناس به سواء علم ديني أو دنيوي.
-     * أن الإسلام حدد ما يصح أن يكون مملوكا وذلك لا ينطبق على العمل الفكري لأنه ليس عينا محصورا
-       وأغلب شروط البرمجيات المملوكة تقع في بيع الغرر (ذاك أن ما لا يجوز بيعه لا يجوز تملكه) دل
-       عليه ما ورد من النهي عن بيع الغرر في صحيح مسلم (ويدخل فيه مسائل كثيرة غير منحصرة كبيع
-       المعدوم والمجهول وما لا يقدر على تسليمه وما لم يتم ملك البائع عليه) وما ورد عن الأئمة
-       الأربعة من فهمهم لهذا.
-     * لسنا بحاجة لابتداع شيء لنشر العلم لأن الأعمال الفكرية ليست محدثة وأن قرون الخير الأولى
-       نشرت العلم دون تملكها.
-     * حبس المعرفة والعلم عمن يحتاجه هو إضرار بالناس لصالح قلة منهم، وهذا مما نهى عنه الشارع ولا
-       يبرر هكذا فعل إلا من يؤمن بالرأسمالية الذاتية التي تطرفت في تعظيم مصلحة الفرد.
-     * انتفاء مبرر المصلحة إذا وجدت طرق لنشر الأعمال الفكرية والتربح منها دون كتمها.
-     * إن المتمعن في قوانين الملكية الفكرية المختلفة يجد في أنها تتلخص بإعطاء “المالك” المزعوم
-       الحق في تحريم ما أحله الله ليكون ذلك مدخلا له في كسب مادي ولا علاقة لها بتقديم خدمة أو
-       منتج معين.
-     * الغموض الذي يحيط بماهية الشيء المزعوم ملكه تفتح الباب أمام جبات “الأتاوات” حيث تتكسب بعض
-       الشركات من التهديد بخطر المقاضاة حتى على أشياء لا تملكها والقضاء الأمريكي يغص بمثل هذه
-       القضايا.
-
-   فإن كانت الغاية قد بررت الوسيلة لواضعي الدستور الأمريكي حين أقروا مفهوم ”الملكية الفكرية”
-   كحق مكتسب (غير فطري باعترافهم) يخدم ما تؤمن به ثقافتهم من تعظيم المصلحة الذاتية وتقديمها على
-   كل شيء؛ ذاك لا يعنينا في شيء ونحن نؤمن بعدم صلاحية ذلك لعموم البشر، لهذا جاءت رخصة “وقف”
-   العامة (كما غيرها الكثير من رخص التوزيع المضادة لحكر التوزيع)، فهي وضعت لكي تؤكد لمستهلك العمل
-   الفكري أن لا قيد يفرضه صاحب العمل على استخدم منتجه والإفادة منه أو إعادة انتاجه وتوزيعه. أي أن
-   تجعل حقوق الطبع والتوزيع “ممنوحة” أو مرفوعة وليس “محفوظة” (وبالإنجليزية يشار لها باسم copyleft
-   او copy-wrong تهكما على copyright)
-
-   فمعادلة وتفاصيل تركيب الدواء هي عمل فكري، وبرمجية الحاسوب هي عمل فكري وقصيدة الشعر هي عمل
-   فكري. وهي بشكل عام كل فكرة تنفع الناس تصلهم على شكل منتج. وعندما نتكلم عن العمل الفكري فإننا
-   نحدد التعريف بالفكر الذي ينفع الناس نشره ولا نقصد به عموم الفكر فلكل منا خصوصيته وأسراره التي
-   لايشارك بها الاخرين. فأسماء الزبائن وأرقام المناقصات وسياسة الدولة العسكرية أو السياسية ليست
-   أعمالا فكرية.
-
-   وهنا يجدر الوقوف عند مسألتين :
-
-     * الأولى، أن الحق الأدبي للصاحب العمل يبقى للمبتكر الأصلي على كل الأحوال. فلا يجوز لأحد أن
-       يأخذ هذا العمل وينتحله ويدعيه لنفسه.
-     * والثانية، أن لصحاب العمل ولغيره (ممن عندهم الكفاية) الإفادة المادية من العمل كأن يطلب
-       أتعابا أو يتقاضى أجرا عن تحسينه أوتطويره أو أجرا عن تدريسه وهكذا. ولكن ما وراء ذلك فلا يحق
-       له إدعاء ملكيته للفكرة أو العمل في صورته المعنوية ولا يحق له منع الآخرين من اعادة نشرها
-       والاستفادة منها. وهذا لا تناقض مع كون العمل موقوفا لأن الموقوف هو أصل العمل الفكري بصورته
-       المعنوية وليس الوسيط أو الخدمة ^3)
-
-                                              تعريفات
-
-   تكون التعريفات هنا هي المقصودة عند استخدامها في الرخصة :
-
-     * العمل الفكري (أو اختصارا العمل): هو أي عمل فكري نافع غير مادي ولا ملموس ويمكن لمن يتلقاه
-       عمل نسخ منه ونقله إلى آخرين دون أي عبء على من قام بإيصال النسخة اليه.
-     * صاحب العمل : هو الشخص المُبتكِر أو الجهة التي قامت بتطوير وتوفير العمل الفكري (والتي تملك
-       حقوق النسخ عند الجهات الرسمية إن لزم الأمر).
-     * المُنتًفع (المستخدِم): هو الشخص أو الجهة التي ترغب بالانتفاع من العمل الفكري.
-     * رخصة الاستخدام (أو اختصارا الرخصة): هي هذا العقد الذي بين يديك وهو عقد بين صاحب العمل
-       والمنتفع يحق للمنتفع بموجبه وضمن شروطه الاستفادة والانتفاع من العمل. ونظرا لتوفر العمل
-       بشكل مفتوح للجميع فإن قيام المنتفع بالاستفادة من العمل الفكري يعني بالضرورة إقراره
-       وموافقته على كافة شروط الرخصة. فإذا لم يكن المنتفع موافقا على الرخصة تنتفي عنه حقوق الحقوق
-       الممنوحة بموجبها ويصبح أي انتفاع بالعمل غير مشروع ويعرض نفسه للمقاضاة.
-
-                                            بنود الرخصة
-
-   رخصة وقف العامة، يرمز لها اختصارا بـ “وقف”، هي رخصة لتوزيع العمل الفكري (من برمجيات أو مؤلفات
-   مكتوبة أو إنتاج فني على سبيل المثال لا الحصر). تتشابه هذه الرخصه في اهدافها مع رخص البرمجيات
-   الحرة والتوثيق الحر و رخصة الانتاج المشترك. ولكنها تزيد عليها ببعض الجوانب المتعلقة بالهدف من
-   وراء الانتاج و حدود الاستخدام.
-
-   رخصة وقف وكما يقترح الاسم هي إقرار من صاحب العمل بأن هذا العمل هو وقف لله تعالى ويتقصد به نوال
-   رضاه من خلال انتفاع الناس به، أي أن هذا العمل هو صدقة جارية لوجه الله تعالى. وبذلك فإن رخصة
-   وقف تقر بأن للمنتفع -أيا كان جنسه أو لونه أو عقيدته- الحق في الإفادة من العمل وإعادة توزيعه
-   وحتى تطويره ضمن الشروط التالية:
-
-     * أولا - أوجه الاستخدام :
-
-   يحق للمنتفع استخدام العمل ضمن أي غرض فيه منفعة ولايجوز استخدامه فيما يسئ للأخرين أو يخالف
-   مبادئ الإسلام السمحة. مع ملاحظة أن الأعمال التي يغلب الظن أنها الضارة لا يجوز أن توضع تحت هذه
-   الرخصة أصلا.
-
-     * ثانيا - حق التوزيع :
-
-   يحق للمنتفع إعادة توزيع العمل بصورته الأصلية ودون تعديل وتحت شروط رخصة وقف، بالكم الذي يريد مع
-   صون ذكر الحق الأدبي لصاحب العمل.
-
-     * ثالثا - حق التعديل :
-
-   يحق للمنتفع الحصول على النسخة المصدرية للعمل كما ويحق له التعديل عليها بما يناسب احتياجاته
-   وضمن الحدود الموضحة في بند أولا.
-
-     * رابعا - حق توزيع النسخة المُعدّلة :
-
-   يحق للمنتفع إعادة توزيع العمل المعدّل فقط تحت رخصة وقف العامة وعلى أن يذكر أصل العمل المعدل
-   وطبيعة التعديل وأن يكون واضحا بما لايدع مجالا للبس أن هذه النسخة معدلة وليست هي النسخة الأصلية
-   التي انتجها صاحب العمل الأول.
-
-     * خامسا - عدم المسؤلية :
-
-   لا يتحمل صاحب العمل أية مسؤوليه لا قانونية ولا أخلاقية عن حسن أو إساءة استخدام العمل أو
-   الأضرار المباشرة أو غير المباشرة الناتجة عنه إلى أقصى حد يسمح به القانون. وصاحب العمل بهذا لا
-   يقدم أية ضمانة لا ضمنا ولا تصريحا بقدرة المنتج على تحقيق أي غرض.
-
-   المسؤولية الكاملة تقع على عاتق المنتفع والضمانة الوحيدة المقدمة له هي مصدر العمل.
-
-                                              الخلاصة
-
-   استخدام رخصة وقف العامة يساعد في نشر الوعي على خطر مفاهيم الملكية الفكرية. كما ويقدم البديل
-   القانوني وإن كنّا لانؤمن بقانونية تلك الملكيات.
-
-   ^1) انظر http://www.islam-qa.com/ar/ref/454
-   ^2) الحديث صحيح رواه أحمد وأبو داود والترمذي وابن ماجه انظر “رفع المنار بطرق حديث من
-   كتم علماً ألجمه الله بلجام من نار”
-   ^3) مثلا يجوز أخذ أجل على نقل ثمار أرض موقوفة أو عصرها
-
-
diff --git a/LICENSE-en b/LICENSE-en
deleted file mode 100644
index c389e77..0000000
--- a/LICENSE-en
+++ /dev/null
@@ -1,222 +0,0 @@
-   بسم الله الرحمن الرحيم
-
-   In the name of Allah, Most Gracious, Most Merciful
-
-                         "Waqf" General Public License
-
-   This is the informal English translation of Waqf General Public License.
-   Anything but the Arabic version of the license has no value except for
-   convenience of our English speaking users. When we talk about the License
-   we refer to the Arabic version, which is the only one we officially
-   offer, we will try our best to make other translation as accurate as
-   possible but because of the nature of human languages we use one single
-   reference language.
-
-                                    Preamble
-
-   Publishing any intellectual work (including but not limited to books and
-   Computer Software) is not done by selling even if it appeared to be so,
-   but it's about getting an implied license that has no enforcement without
-   the concept of intellectual property granted by man-made laws which was
-   acquired as they claim to promote the publication of science and the
-   useful arts. The concept of the so called “intellectual property” is
-   centered around giving ownership to the first one who register the work
-   (called owner or copyright holder and we will refer to him/her/it as
-   holder) then the holder practice his rights on the work in it's intangible
-   form on any media it's carried, and thus using the intellectual work
-   without explicit prior permission is according to them ethically
-   equivalent to hijacking ships or “piracy” as they call it. This permission
-   is called License and it's aimed to give the holder (usually the
-   publisher) an advantage in the market against other publishers through
-   monopoly on providing that work by imposing restrictions on the users not
-   the publishers. Such works are called “Proprietary”.
-
-   We see that such agreements (proprietary licenses) are evil, but we also
-   acknowledge that making an agreement with a prior intention to violate it
-   is another immoral evil ^1). We don't solve problems with problems, we
-   offer an alternative.
-
-   We have a different vision, we offer our work (like computer software) to
-   please Allah, and this is the pillar of this license which distinguish it
-   from proprietary licenses. Any other intention (like spreading knowledge
-   or getting profits) should be accomplished in ways that does not go
-   against our primary moral aim.
-
-   According to our believes (which we don't enforce on any one, and you may
-   or may not share it with us) that Islam certainly forbids monopoly and
-   concealing knowledge in general, and this comes from:
-
-     * The sound Hadith (saying of prophet Muhammad PBUH): “Who conceal any
-       type of knowledge will be bridle with a bridle of fire on the Day of
-       Resurrection.” ^2)
-     * Islamic Jurisprudence has specified what can be owned, and the rules
-       does not apply to ideas as it's not a bounded tangible object and
-       almost all the terms of proprietary agreements fall in ruling of
-       forbidden Gharar^3) (a kind of fraud that use uncertainty to
-       fool the customers) as we see in Imam Muslim Sahih description of that
-       term {and below that term we classify so many actions like selling
-       negligible objects or unknowns or what can't be delivered or things
-       that are not full owned by the seller} and such view is also shared by
-       the four major scholars.
-     * The laws of Fiqh (Islamic Jurisprudence) have been perfected in the
-       good centuries and no new rulings are allowed to be brought except for
-       newly discovered things and this does not apply ideas as they did
-       exist in the past centuries and Muslims massively spread them without
-       owning them. FYI: Almost all the Islamic literature is freely
-       available on the internet.
-     * Concealing useful knowledge from those who need it impose damage to
-       people for temporal gains to few individuals. This can not be
-       justified by Shari'a (Islamic Law), it's only justified by
-       individualist capitalism ^4)
-     * Even bringing interests to software publishers is not a valid excuse
-       because there are some companies produce and publish software without
-       owning them (proprietary software) and yet they gain profits.
-     * the so call “Intellectual Proprietary” is all about giving owners the
-       right to forbid what Allah had made lawful to gain money, not by
-       providing service nor goods.
-     * The uncertainty and untangable nature of the claimed owned product is
-       the source of “protection money collecting” where some company
-       threaten some smaller company by copyright infringement lawsuit on
-       some purposely ambiguous product which the later can't afford so they
-       go safe and pay.
-
-   If the good intentions made excuses to introduce “intellectual
-   proprietary” by the Machiavellists who wrote the American constitution
-   as an acquired right (at least they admit it's not a natural right), they
-   serve their own way of life which is not international. We don't take
-   that. We have our own high moral standards. We introduce Waqf General
-   Public License to place it among the anti-copyright licenses. This license
-   is designed to grant rights to users not to restrict them, it's uses the
-   concept of copyleft/copy-wrong as opposed to the concept of copyright.
-
-   Computer software, Medicine formula or even poems are considered to be
-   intellectual works and thus can be covered by “Waqf”. An intellectual work
-   is any useful idea that can be delivered or utilized by people. “Waqf” is
-   not meant for ideas in general, but for intellectual work which is
-   beneficial to people if published. As we support protecting privacy for
-   example one shouldn't publish names of his customers, bid prices,
-   government military or political secrets because those are not
-   intellectual works.
-
-   We should clarify two things:
-
-     * First: The favor and ethical rights of the holder are preserved and
-       acknowledged
-     * Second: original author and any other party (if they have the
-       intention and the ability) have the right to get fees on enhancing the
-       work or developing it or to provide paid services or paid courses
-       …etc. but not the work in its intangible form. There is not
-       contradiction between getting fees on services because what is covered
-       by “Waqf” is the source form of the work not the media nor the service
-       (the same way one can take fees on shipping fruits for a charitable
-       Waqf fruit field or make juice)
-
-                                  Definitions
-
-   The following terms would have the corresponding meanings in this license
-
-     * The intellectual work (or The work for short): is any useful
-       intangible intellectual product that can be passed on to others or
-       replicated withno cost imposed on the original author or the one who
-       pass it on before.
-     * The holder: is the creative author or the party which carried the
-       process of developing the work and make it available (and the one who
-       holds the copyrights on the product before the governmental offices).
-     * the licensee or the user: any one or party who uses the work (runs,
-       copies, modifies or otherwise takes benefits provided by the work).
-     * The license: this agreement (the Arabic version of “Waqf”) between the
-       two parties (the holder and the user) covering the usage of the second
-       party on the work provided by the first party. The usage of the
-       product is with accordance to the terms of this license. And because
-       of the intangible nature of the work, this agreement applies by using
-       the product (in any way) without signing the agreement. One do not
-       accept the terms looses the rights given by this license and his/her
-       usage of the work is considered illegal and will be sued.
-
-                                   The Terms
-
-   Waqf General Public license (or “Waqf” for short) covers intellectual
-   works (including but not limited to Software and paper publications,
-   scientific theses, art works) and have many common features with FLOSS
-   licenses. Waf is distinguished with its moral intentions behind the work
-   and usage limits.
-
-   As the name suggests, with “Waqf” ^5) the holder announce his/her work
-   was produced and made available to the public for the sake of Allah aimed
-   to please Allah by providing people with useful works. It's a form of
-   “Sadaqa Jariah” ^6).
-
-   “Waqf” gives users (regardless of their nationality, color, race,
-   religion) the right to benefit from the work with running, copying,
-   redistribution, or even develop and only with according to the following
-
-     * First - Usage :
-
-   The user may use the work for any good purpose and he may not use it to
-   harm others or violate the permissive principles of Islam ^7). Notice
-   that any work that is most likely harmful can't be put under Waqf in the
-   first place.
-
-     * Second - Redistribution :
-
-   The user have the right to redistribute the unmodified work in any
-   quantity to any third party under the terms of this license, acknowledging
-   the favor and ethical rights of the holder to the third party.
-
-     * Third - Modifications :
-
-   The user has the right to get the source form of the work and make
-   modifications enhancing or adopting to the user's needs to the limits
-   given by this license.
-
-     * Fourth - Redistribute modifications:
-
-   The user can redistribute modifications only under this license provided
-   that he points to previous original work (the unmodified work) and its
-   author and the nature of modification clearly to the third party to whom
-   the modified work is presented in a way that no one may reasonably get
-   confused between it and the original unmodified work of the previous
-   author.
-
-     * Fourth - Disclaimer of responsibility :
-
-   The holder does not take any legal nor moral direct or indirect
-   responsibility nor liability on the good or bad usage or damages caused by
-   the work to the farthest level allowed by the law. THIS SOFTWARE IS
-   PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-   PARTICULAR PURPOSE ARE DISCLAIMED BY THE HOLDER.
-
-   The entire responsibility is on the user and the only warranty given to
-   him is the source of the work.
-
-                                   Conclusion
-
-   Applying Waqf public license help to spread the awareness of dangers
-   caused by intellectual property. And provide people with a legal
-   alternative even though we don't believe on the validity of such man made
-   laws.
-
-   ^1) http://www.islam-qa.com/ar/ref/454
-   ^2) This is an authentic sound/Sahih as it's narrated by Imam
-   Ahmad, Abu Dawood, AlTirmithi and Ibn Majah. Refer to “Hoisting the
-   Lighthouse : A synopsis of the Various narrations of the Hadith: Whoever
-   conceals knowledge, Allah will bridle him with a bridle of fire” or in
-   Arabic “رفع المنار بطرق حديث من كتم علماً ألجمه الله بلجام من نار”.
-   ^3) Some information about Ghrar is available at
-   http://www.investopedia.com/terms/g/gharar.asp
-   ^4) Although Islamic economy is a kind of liberal capitalism economy
-   but it's regulated with so many moral rulings that guarantee social
-   justice
-   ^5) The name Waqf means to prevent the source or assets from being
-   consumed while giving away for charity the proceeds.
-   ^6) Sadaqa Jariah means sustainable charity which is a kind of charity
-   that continue to be beneficial to people even after the death of the one
-   who give it like giving the fruits of a field but not the field, more over
-   prophet Muhammad PBUH specifically named useful knowledge as a form of
-   that kind of charity.
-   ^7) Some scholars use the term Maqasid Alsharia and summarize them by
-   saying that it aims to protect people rights in religion, lives, sanity,
-   breed, and properties.
-
-
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..ce54358
--- /dev/null
+++ b/TODO
@@ -0,0 +1,4 @@
+بسم الله الرحمن الرحيم
+- copy multiple aya to clipboard
+- add 100% zoom button
+- add accels
diff --git a/exe-setup.py b/exe-setup.py
index 8016c5c..9d91139 100644
--- a/exe-setup.py
+++ b/exe-setup.py
@@ -11,38 +11,41 @@ import py2exe
 # NOTE: before you use this tool you should run make to generate index and locale files
 
 
-locales=map(lambda i: ('locale/'+i,[''+i+'/othman.mo',]),glob('locale/*/LC_MESSAGES'))
-data_files=[('othman-data',glob('othman-data/*')), ('.', ['COPYING']+glob('LICENSE*')+glob('README*'))]
+locales=map(lambda i: ('locale/' + i, ['' + i + '/othman.mo',]), glob('locale/*/LC_MESSAGES'))
+data_files=[('othman-data',
+             glob('othman-data/*')),
+             ('.',
+              ['COPYING'] + glob('LICENSE*') + glob('README*'))]
 data_files.extend(locales)
 
 setup (name='Othman', version='0.2.0',
-      description='Othman Quran Browser',
-      author='Muayyad Saleh Alsadi',
-      author_email='alsadi at ojuba.org',
-      url='http://othman.ojuba.org/',
-      license='Waqf',
-      packages=['othman'],
-      classifiers=[
-          'Development Status :: 4 - Beta',
-          'Intended Audience :: End Users/Desktop',
-          'Operating System :: POSIX',
-          'Programming Language :: Python',
-          ],
+    description='Othman Quran Browser',
+    author='Muayyad Saleh Alsadi',
+    author_email='alsadi at ojuba.org',
+    url='http://othman.ojuba.org/',
+    license='Waqf',
+    packages=['othman'],
+    classifiers=[
+        'Development Status :: 4 - Beta',
+        'Intended Audience :: End Users/Desktop',
+        'Operating System :: POSIX',
+        'Programming Language :: Python',
+        ],
 
     windows = [
-                  {
+                {
                       'script': 'othman-browser',
                       'icon_resources': [(1, "othman.ico")],
-                  }
-              ],
+                }
+            ],
 
     options = {
-                  'py2exe': {
-                      'packages':'encodings',
-                      'includes': 'cairo, pango, pangocairo, atk, gobject, gio',
-                  }
-              },
-      data_files=data_files
-)
+              'py2exe': {
+                  'packages':'encodings',
+                  'includes': 'cairo, pango, pangocairo, atk, gobject, gio',
+              }
+          },
+    data_files=data_files
+    )
 
 
diff --git a/gen-index.py b/gen-index.py
index a2e2c9d..761105a 100755
--- a/gen-index.py
+++ b/gen-index.py
@@ -4,12 +4,14 @@
 import sys, os, os.path, time
 from othman.core import othmanCore, searchIndexer
 
-q=othmanCore(False)
-ix=searchIndexer(True)
-wc=0
+q = othmanCore(False)
+ix = searchIndexer(True)
+wc = 0
 for n,(o,i) in enumerate(q.getAyatIter(1, 6236)):
-  for w in i.split(): ix.addWord(w,n+1); wc+=1
-d=os.path.dirname(sys.argv[0])
+    for w in i.split():
+        ix.addWord(w,n+1)
+        wc += 1
+d = os.path.dirname(sys.argv[0])
 ix.save()
 print "got %d words, %d terms (max term length=%d character, term vectors size=%d bytes)." % (wc, ix.terms_count, ix.maxWordLen, ix.term_vectors_size)
 
diff --git a/othman.spec b/othman.spec
index 889304e..8b3079e 100644
--- a/othman.spec
+++ b/othman.spec
@@ -1,19 +1,22 @@
+%global owner ojuba-org
+%global commit #Write commit number here
+
 Name:		othman
-Version:	0.2.7
+Version:	0.3
 Release:	1%{?dist}
 Summary:	Othman Electronic Quran Browser
-# sitelib for noarch packages, sitearch for others (remove the unneeded one)
-%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
-
 Group:		Applications/Productivity
-License:	Waqf
-URL:		http://othman.ojuba.org
-Source:		http://git.ojuba.org/cgit/%{name}/snapshot/%{name}-%{version}.tar.bz2
-BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+License:	WAQFv2
+URL:		http://ojuba.org
+Source:		https://github.com/%{owner}/%{name}/archive/%{commit}/%{name}-%{commit}.tar.gz
 BuildArch:	noarch
 BuildRequires:	python
-Requires:	pygtk2, islamic-menus, arabeyes-core-fonts
+BuildRequires:	python2-devel
+Requires:	islamic-menus
+Requires:	arabeyes-core-fonts
+Requires:	pygobject3 >= 3.0.2
 Requires:	python-othman
+
 %description
 Othman Electronic Quran Browser displays Quranic text in Othmani script style
 as written under authority of Othman ibn Affan the companion of prophet Muhammad PBUH
@@ -21,13 +24,12 @@ as written under authority of Othman ibn Affan the companion of prophet Muhammad
 Othman project features fast search, autoscrolling, copy Quranic text to clipboard.
 
 %prep
-%setup -q
+%setup -q -n %{name}-%{commit}
 
 %build
 make %{?_smp_mflags}
 
 %install
-rm -rf $RPM_BUILD_ROOT
 %makeinstall DESTDIR=$RPM_BUILD_ROOT
 
 %post
@@ -42,42 +44,48 @@ if [ -x %{_bindir}/gtk-update-icon-cache ] ; then
 %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
 fi
 
-%clean
-rm -rf $RPM_BUILD_ROOT
-
 %package -n python-othman
 Group:		System Environment/Base
 Summary:	python package providing access to Quranic text
-License:	Waqf
+License:	WAQFv2
 BuildArch:	noarch
 Requires:	python
+
 %description -n python-othman
 a python package that provides access to Quranic text with a fast search index
 
 %files
 %defattr(-,root,root,-)
-%doc LICENSE-en LICENSE-ar.txt README README-ar.txt COPYING
+%doc README README-ar.txt COPYING waqf2-ar.pdf
 %{_bindir}/othman-browser
-%{python_sitelib}/othman/gtkUi.p*
+%{python2_sitelib}/othman/gtkUi.p*
 %{_datadir}/applications/*.desktop
 %{_datadir}/locale/*/*/*.mo
 %{_datadir}/icons/hicolor/*/apps/*.png
 
 %files -n python-othman
 %defattr(-,root,root,-)
-%doc LICENSE-en LICENSE-ar.txt README README-ar.txt COPYING
-%dir %{python_sitelib}/othman
+%doc README README-ar.txt COPYING waqf2-ar.pdf
+%dir %{python2_sitelib}/othman
 %dir %{_datadir}/othman
-%{python_sitelib}/*.egg-info
-%{python_sitelib}/othman/core.p*
-%{python_sitelib}/othman/varuints.p*
-%{python_sitelib}/othman/__init__.p*
+%{python2_sitelib}/*.egg-info
+%{python2_sitelib}/othman/core.p*
+%{python2_sitelib}/othman/*varuints.p*
+%{python2_sitelib}/othman/__init__.p*
 %{_datadir}/othman/*
 
 %changelog
+* Mon Jun 4 2012 Mosaab Alzoubi <moceap at hotmail.com> - 0.3-1
+- New Relese
+
+* Mon Jun 4 2012 Mosaab Alzoubi <moceap at hotmail.com> - 0.2.8-2
+- General Revision.
+
+* Mon Jun 4 2012  Muayyad Saleh AlSadi <alsadi at ojuba.org> - 0.2.8-1
+- port to gtk3
+
 * Sat Jun 12 2010  Muayyad Saleh AlSadi <alsadi at ojuba.org> - 0.2.5-1
 - update to new version
 
 * Wed Apr 28 2010 Muayyad Saleh Alsadi <alsadi at ojuba.org> - 0.2.0-1
 - initial release
-
diff --git a/othman/core.py b/othman/core.py
index 32ab60d..f5095d0 100644
--- a/othman/core.py
+++ b/othman/core.py
@@ -23,221 +23,250 @@ import sqlite3
 import array
 from itertools import imap
 import threading
-import varuints
+import univaruints
 
-data_dir=None
+data_dir = None
 
 def guessDataDir():
-  global data_dir
-  if data_dir: return data_dir
-  if not hasattr(sys, "frozen"):
-    # we are not in py2exe
-    f=os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
-    d=os.path.join(f, '..', 'othman-data')
-    if os.path.exists(d): data_dir=os.path.abspath(os.path.realpath(d)); return data_dir
-    d=os.path.join(f,'..', '..', '..', '..', 'share', 'othman')
-    if os.path.exists(d): data_dir=os.path.abspath(os.path.realpath(d)); return data_dir
-  # we are in py2exe or DATA can't be located relative to __FILE__
-  f=os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
-  d=os.path.join(f, 'othman-data')
-  if os.path.exists(d): data_dir=os.path.abspath(os.path.realpath(d)); return data_dir
-  d=os.path.join(f, '..', 'share', 'othman')
-  data_dir=os.path.abspath(os.path.realpath(d))
-  return data_dir
+    global data_dir
+    if data_dir: return data_dir
+    if not hasattr(sys, "frozen"):
+        # we are not in py2exe
+        f = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
+        d = os.path.join(f, '..', 'othman-data')
+        if os.path.exists(d):
+            data_dir=os.path.abspath(os.path.realpath(d))
+            return data_dir
+        d = os.path.join(f,'..', '..', '..', '..', 'share', 'othman')
+        if os.path.exists(d):
+            data_dir = os.path.abspath(os.path.realpath(d))
+            return data_dir
+    # we are in py2exe or DATA can't be located relative to __FILE__
+    f = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
+    d = os.path.join(f, 'othman-data')
+    if os.path.exists(d):
+        data_dir=os.path.abspath(os.path.realpath(d))
+        return data_dir
+    d = os.path.join(f, '..', 'share', 'othman')
+    data_dir = os.path.abspath(os.path.realpath(d))
+    return data_dir
 
 def cmp_bisect_right(ccmp, a, x, lo=0, hi=None):
     """
-    same as bisect.bisect but uses custom cmp function
+        same as bisect.bisect but uses custom cmp function
     """
     if lo < 0:
         raise ValueError('lo must be non-negative')
     if hi is None:
         hi = len(a)
     while lo < hi:
-        mid = (lo+hi)>>1
-        if ccmp(a[mid],x)>0: hi = mid # ie. if x < a[mid]
-        else: lo = mid+1
+        mid = (lo + hi) >> 1
+        if ccmp(a[mid], x) > 0:
+            hi = mid # ie. if x < a[mid]
+        else:
+            lo = mid + 1
     return lo
+
 def cmp_bisect_left(ccmp, a, x, lo=0, hi=None):
     """
-    same as bisect.bisect_left but uses custom cmp function
+        same as bisect.bisect_left but uses custom cmp function
     """
     if lo < 0:
         raise ValueError('lo must be non-negative')
     if hi is None:
         hi = len(a)
     while lo < hi:
-        mid = (lo+hi)>>1
-        if ccmp(x, a[mid])>0: lo = mid+1 # ie. if a[mid] < x
-        else: hi = mid
+        mid = (lo + hi) >> 1
+        if ccmp(x, a[mid]) > 0:
+            lo = mid + 1 # ie. if a[mid] < x
+        else:
+            hi = mid
     return lo
 
 
-class othmanCore:
-  SQL_GET_AYAT='SELECT othmani, imlai FROM Quran WHERE id>=? ORDER BY id LIMIT ?'
-  SQL_GET_SURA_INFO='SELECT rowid, sura_name, other_names, makki, starting_row, comment FROM SuraInfo ORDER BY rowid'
-  def __init__(self, load_ix=True):
-    self.data_dir = d = guessDataDir()
-    self.db_fn = db_fn=os.path.join(d,'quran.db')
-    self._cn = {}
-    cn=self._getConnection()
-    l=list(cn.execute(self.SQL_GET_SURA_INFO).fetchall())
-    if len(l)!=114: raise IOError
-    self.suraIdByName=dict(((i[1],i[0]) for i in l))
-    self.suraInfoById=[list(i[1:])+[0] for i in l]
-    for i in range(113):
-      self.suraInfoById[i][5]=self.suraInfoById[i+1][3]-self.suraInfoById[i][3]
-    self.suraInfoById[-1][5]=6
-    self.basmala, self.basmala_imlai=list(self.getAyatIter(1))[0]
-    self.basmala=self.basmala[:self.basmala.rfind(' ')]
-    self.ix=None
-    if load_ix: self.ix=searchIndexer()
-
-  def _getConnection(self):
-    n = threading.current_thread().name
-    if self._cn.has_key(n):
-      r = self._cn[n]
-    else:
-      r = sqlite3.connect(self.db_fn)
-      self._cn[n] = r
-    return r
-
-  def showSunnahBasmala(self, sura):
-    return sura!=1 and sura!=9
-
-  def suraAyaFromAyaId(self, ayaId):
-    sura=cmp_bisect_right(lambda i,j: cmp(i[3], j), self.suraInfoById, ayaId)
-    aya=ayaId-self.suraInfoById[sura-1][3]+1
-    return sura,aya
-
-  def ayaIdFromSuraAya(self, suraId, aya=1):
-    """
-    suraId: sura number from 1 to 114
-    aya: aya number from 1 to the end of the sura
-    """
-    return self.suraInfoById[suraId-1][3]+aya-1
-
-  def getAyatIter(self, ayaId, number=1):
-    """
-    return a list of (othmani, imlai) tuples
-    """
-    return self._getConnection().execute(self.SQL_GET_AYAT, (ayaId,number))
-
-  def getSuraIter(self, suraId, number=0, fromAya=1):
-    """
-    return a list of (othmani, imlai) tuples for the whole sura
-    suraId: sura number from 1 to 114
-    number of ayat (0 for the whole sura)
-    """
-    a=self.suraInfoById[suraId-1]
-    m=a[5]
-    if number<=0 or number>m: number=m
-    return self.getAyatIter(a[3]+fromAya-1, number)
+class othmanCore(object):
+    SQL_GET_AYAT = 'SELECT othmani, imlai FROM Quran WHERE id>=? ORDER BY id LIMIT ?'
+    SQL_GET_SURA_INFO = 'SELECT rowid, sura_name, other_names, makki, starting_row, comment FROM SuraInfo ORDER BY rowid'
+    def __init__(self, load_ix=True):
+        self.data_dir = d = guessDataDir()
+        self.db_fn = db_fn = os.path.join(d, 'quran.db')
+        self._cn = {}
+        cn = self._getConnection()
+        l = list(cn.execute(self.SQL_GET_SURA_INFO).fetchall())
+        if len(l) != 114:
+            raise IOError
+        self.suraIdByName = dict(((i[1], i[0]) for i in l))
+        self.suraInfoById = [list(i[1:]) + [0] for i in l]
+        for i in range(113):
+            self.suraInfoById[i][5] = self.suraInfoById[i + 1][3] - self.suraInfoById[i][3]
+        self.suraInfoById[-1][5] = 6
+        self.basmala, self.basmala_imlai = list(self.getAyatIter(1))[0]
+        self.basmala = self.basmala[:self.basmala.rfind(' ')]
+        self.ix = None
+        if load_ix:
+            self.ix = searchIndexer()
+
+    def _getConnection(self):
+        n = threading.current_thread().name
+        if self._cn.has_key(n):
+            r = self._cn[n]
+        else:
+            r = sqlite3.connect(self.db_fn)
+            self._cn[n] = r
+        return r
+
+    def showSunnahBasmala(self, sura):
+        return sura != 1 and sura != 9
+
+    def suraAyaFromAyaId(self, ayaId):
+        sura = cmp_bisect_right(lambda i, j: cmp(i[3], j), self.suraInfoById, ayaId)
+        aya = ayaId - self.suraInfoById[sura-1][3] + 1
+        return sura, aya
+
+    def ayaIdFromSuraAya(self, suraId, aya = 1):
+        """
+            suraId: sura number from 1 to 114
+            aya: aya number from 1 to the end of the sura
+        """
+        return self.suraInfoById[suraId-1][3] + aya - 1
+
+    def getAyatIter(self, ayaId, number = 1):
+        """
+            return a list of (othmani, imlai) tuples
+        """
+        return self._getConnection().execute(self.SQL_GET_AYAT, (ayaId,number))
+
+    def getSuraIter(self, suraId, number=0, fromAya=1):
+        """
+            return a list of (othmani, imlai) tuples for the whole sura
+            suraId: sura number from 1 to 114
+            number of ayat (0 for the whole sura)
+        """
+        a = self.suraInfoById[suraId - 1]
+        m = a[5]
+        if number <= 0 or number > m:
+            number = m
+        return self.getAyatIter(a[3] + fromAya - 1, number)
 
 normalize_tb={
-65: 97, 66: 98, 67: 99, 68: 100, 69: 101, 70: 102, 71: 103, 72: 104, 73: 105, 74: 106, 75: 107, 76: 108, 77: 109, 78: 110, 79: 111, 80: 112, 81: 113, 82: 114, 83: 115, 84: 116, 85: 117, 86: 118, 87: 119, 88: 120, 89: 121, 90: 122,
-1600: None, 1569: 1575, 1570: 1575, 1571: 1575, 1572: 1575, 1573: 1575, 1574: 1575, 1577: 1607, 1611: None, 1612: None, 1613: None, 1614: None, 1615: None, 1616: None, 1617: None, 1618: None, 1609: 1575}
-
-def normalize(s): return s.translate(normalize_tb)
+    65: 97, 66: 98, 67: 99, 68: 100, 69: 101, 70: 102,
+    71: 103, 72: 104, 73: 105, 74: 106, 75: 107, 76: 108,
+    77: 109, 78: 110, 79: 111, 80: 112, 81: 113, 82: 114,
+    83: 115, 84: 116, 85: 117, 86: 118, 87: 119, 88: 120,
+    89: 121, 90: 122, 1600: None, 1569: 1575, 1570: 1575,
+    1571: 1575, 1572: 1575, 1573: 1575, 1574: 1575, 1577: 1607,
+    1611: None, 1612: None, 1613: None, 1614: None, 1615: None,
+    1616: None, 1617: None, 1618: None, 1609: 1575}
+
+def normalize(s):
+    return s.translate(normalize_tb)
 
 class searchIndexerItem(set):
-  def __init__(self,*a):
-    set.__init__(self, *a)
+    def __init__(self, *a):
+        set.__init__(self, *a)
+
+    def __or__(self, y):
+        return self.union(y)
 
-  def __or__(self, y):
-    return self.union(y)
+    def __and__(self, y):
+        return self.intersection(y)
 
-  def __and__(self, y):
-    return self.intersection(y)
-  
-  def toAyaIdList(self):
-    l=list(self)
-    l.sort()
-    return l
+    def toAyaIdList(self):
+        l = list(self)
+        l.sort()
+        return l
 
 class searchIndexer:
-  def __init__(self, unlink=False, normalize=normalize):
-    d=guessDataDir()
-    self.db_fn = fn = os.path.join(d, "ix.db")
-    if unlink and os.path.exists(fn): os.unlink(fn)
-    self._cn = {}
-    self.d={}
-    self.normalize=normalize
-    self.maxWordLen=0
-    self.term_vectors_size=0
-    self.terms_count=0
-
-  def _getConnection(self):
-    n = threading.current_thread().name
-    if self._cn.has_key(n):
-      r = self._cn[n]
-    else:
-      r = sqlite3.connect(self.db_fn)
-      self._cn[n] = r
-    return r
-
-  def save(self):
-    cn = self._getConnection()
-    c=cn.cursor()
-    c.execute('CREATE TABLE ix (w TEXT PRIMARY KEY NOT NULL, i BLOB)')
-    for w in self.d:
-      b=varuints.incremental_encode(self.d[w].toAyaIdList())
-      self.term_vectors_size+=len(b)
-      c.execute( 'INSERT INTO ix VALUES(?,?)', (w, sqlite3.Binary(b)) )
-    self.terms_count=len(self.d.keys())
-    cn.commit()
-
-  def _itemFactory(self, r):
-    a=varuints.incremental_decode(r[1])
-    return r[0], searchIndexerItem(a)
-
-  def _itemFactory2(self, r):
-    a=varuints.incremental_decode(r[1])
-    return searchIndexerItem(a)
-
-  def get(self, w):
-    cn = self._getConnection()
-    r=cn.execute('SELECT w, i FROM ix WHERE w=?', (w,)).fetchone()
-    if not r: return None, None
-    return self._itemFactory(r)
-
-  def getPartial(self, w, withWords=False):
-    if "%" in w or "_" in w: return [] # special chars
-    cn = self._getConnection()
-    W="%"+w+"%"
-    f=withWords and self._itemFactory or self._itemFactory2
-    r=cn.execute('SELECT w, i FROM ix WHERE w LIKE ?', (W, ))
-    if not r: return []
-    return imap(lambda i: f(i), r)
-
-  def find(self, words):
-    if not words: return None
-    w=self.normalize(words[0])
-    W,x=self.get(w)
-    if not x: return None
-    for w in words[1:]:
-      W,y=self.get(self.normalize(w))
-      if not y: return None
-      x&=y
-    return x.toAyaIdList()
-
-  def findPartial(self, words):
-    if not words: return None
-    w=self.normalize(words[0])
-    x=reduce( lambda a,b: a|b, self.getPartial(w), searchIndexerItem() )
-    for W in words[1:]:
-      w=self.normalize(W)
-      y=reduce( lambda a,b: a|b, self.getPartial(w), searchIndexerItem() )
-      x&=y
-    return x.toAyaIdList()
-
-  def addWord(self, word, ayaId):
-    w=self.normalize(word)
-    #if not w: print word; return
-    self.maxWordLen=max(self.maxWordLen,len(w))
-    if self.d.has_key(w):
-      self.d[w].add(ayaId)
-    else:
-      self.d[w]=searchIndexerItem((ayaId,))
+    def __init__(self, unlink = False, normalize = normalize):
+        d = guessDataDir()
+        self.db_fn = fn = os.path.join(d, "ix.db")
+        if unlink and os.path.exists(fn):
+            os.unlink(fn)
+        self._cn = {}
+        self.d = {}
+        self.normalize = normalize
+        self.maxWordLen = 0
+        self.term_vectors_size = 0
+        self.terms_count = 0
+
+    def _getConnection(self):
+        n = threading.current_thread().name
+        if self._cn.has_key(n):
+            r = self._cn[n]
+        else:
+            r = sqlite3.connect(self.db_fn)
+            self._cn[n] = r
+        return r
+
+    def save(self):
+        cn = self._getConnection()
+        c = cn.cursor()
+        c.execute('CREATE TABLE ix (w TEXT PRIMARY KEY NOT NULL, i BLOB)')
+        for w in self.d:
+            b = univaruints.incremental_encode(self.d[w].toAyaIdList())
+            self.term_vectors_size += len(b)
+            c.execute( 'INSERT INTO ix VALUES(?,?)', (w, sqlite3.Binary(b)) )
+        self.terms_count = len(self.d.keys())
+        cn.commit()
+
+    def _itemFactory(self, r):
+        a = univaruints.incremental_decode(r[1])
+        return r[0], searchIndexerItem(a)
+
+    def _itemFactory2(self, r):
+        a = univaruints.incremental_decode(r[1])
+        return searchIndexerItem(a)
+
+    def get(self, w):
+        cn = self._getConnection()
+        r = cn.execute('SELECT w, i FROM ix WHERE w=?', (w,)).fetchone()
+        if not r:
+            return None, None
+        return self._itemFactory(r)
+
+    def getPartial(self, w, withWords=False):
+        if "%" in w or "_" in w:
+            return [] # special chars
+        cn = self._getConnection()
+        W = "%" + w + "%"
+        f = withWords and self._itemFactory or self._itemFactory2
+        r = cn.execute('SELECT w, i FROM ix WHERE w LIKE ?', (W, ))
+        if not r:
+            return []
+        return imap(lambda i: f(i), r)
+
+    def find(self, words):
+        if not words:
+            return None
+        w = self.normalize(words[0])
+        W, x = self.get(w)
+        if not x:
+            return None
+        for w in words[1:]:
+            W, y = self.get(self.normalize(w))
+            if not y:
+                return None
+            x &= y
+        return x.toAyaIdList()
+
+    def findPartial(self, words):
+        if not words:
+            return None
+        w = self.normalize(words[0])
+        x = reduce( lambda a,b: a|b, self.getPartial(w), searchIndexerItem() )
+        for W in words[1:]:
+            w = self.normalize(W)
+            y = reduce( lambda a,b: a|b, self.getPartial(w), searchIndexerItem() )
+            x &= y
+        return x.toAyaIdList()
+
+    def addWord(self, word, ayaId):
+        w = self.normalize(word)
+        #if not w: print word; return
+        self.maxWordLen = max(self.maxWordLen,len(w))
+        if self.d.has_key(w):
+            self.d[w].add(ayaId)
+        else:
+            self.d[w] = searchIndexerItem((ayaId,))
 
 
diff --git a/othman/gtkUi.py b/othman/gtkUi.py
index 7f1ceea..aa82061 100644
--- a/othman/gtkUi.py
+++ b/othman/gtkUi.py
@@ -5,391 +5,420 @@ gtkUi - gtk user interface for Othman API
 
 Copyright © 2008-2010, Muayyad Alsadi <alsadi at ojuba.org>
 
-    Released under terms of Waqf Public License.
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the latest version Waqf Public License as
-    published by Ojuba.org.
+        Released under terms of Waqf Public License.
+        This program is free software; you can redistribute it and/or modify
+        it under the terms of the latest version Waqf Public License as
+        published by Ojuba.org.
 
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+        This program is distributed in the hope that it will be useful,
+        but WITHOUT ANY WARRANTY; without even the implied warranty of
+        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
-    The Latest version of the license can be found on
-    "http://waqf.ojuba.org/license"
+        The Latest version of the license can be found on
+        "http://waqf.ojuba.org/license"
 
 """
 import sys, os, os.path, time
 import gettext
-import pango
-import glib
-import gtk
-
+from gi.repository import Gtk, Gdk, GLib, Pango, GdkPixbuf
 from core import othmanCore, searchIndexer
 
-class searchWindow(gtk.Window):
-  def __init__(self, w):
-    gtk.Window.__init__(self)
-    self.w=w
-    self.connect('delete-event', lambda w,*a: w.hide() or True)
-    self.last_txt = None
-    self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
-    self.set_modal(True)
-    self.set_deletable(True)
-    self.set_title(_('Search results'))
-    self.set_transient_for(w)
-    vb=gtk.VBox(False,0); self.add(vb)
-    self.search=gtk.Entry()
-    self.search.set_width_chars(15)
-    vb.pack_start(self.search, False,False, 0)
-    self.scroll=gtk.ScrolledWindow()
-    self.scroll.set_policy(gtk.POLICY_NEVER,gtk.POLICY_ALWAYS)
-    vb.pack_start(self.scroll,True, True, 6)
-    
-    self.ls = gtk.ListStore(int,str,int,int)
-    self.cells=[]; self.cols=[]
-    self.cells.append(gtk.CellRendererText())
-    self.cols.append(gtk.TreeViewColumn(_('Sura'), self.cells[0], text=1))
-    self.cols[0].set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
-    self.cols[0].set_resizable(True)
-
-    self.cells.append(gtk.CellRendererText()); # self.cols[-1].set_expand(False)
-    self.ls_w=gtk.TreeView(self.ls)
-    self.ls_w.connect("cursor-changed", self.move)
-    self.ls_w.set_headers_visible(False)
-    for i in self.cols: self.ls_w.insert_column(i, -1)
-    self.scroll.add(self.ls_w)
-    self.search.connect("activate", self.search_cb)
-    self.show_all()
-
-  def move(self, t):
-    a=self.ls_w.get_selection().get_selected()
-    if not a or len(a)<2 or not a[1]: return
-    sa=self.ls[self.ls.get_path(a[1])[0]]
-    self.w.sura_c.set_active(sa[2]-1)
-    self.w.viewAya(sa[3], sa[2])
-
-  def search_cb(self, b, *a):
-    t=b.get_text()
-    self.w.search.set_text(t)
-    self.find(t)
-
-  def find(self, txt, backward=False):
-    txt=txt.strip()
-    if not txt: self.hide(); return
-    if type(txt)==str: txt=txt.decode('utf-8')
-    if txt==self.last_txt:
-      # TODO: just move cursor to next/prev result before showing it
-      pass
-    else:
-      self.search.set_text(txt)
-      self.last_txt=txt
-      self.ls.clear()
-      for i in self.w.ix.findPartial(txt.split()):
-        sura,aya=self.w.suraAyaFromAyaId(i)
-        name=self.w.suraInfoById[sura-1][0]
-        self.ls.append([i, "%03d %s - %03d" % (sura, name, aya), sura, aya,])
-      self.ls_w.set_cursor((0,))
-    self.show_all()
-
-class othmanUi(gtk.Window, othmanCore):
-  def __init__(self):
-    gtk.window_set_default_icon_name('Othman')
-    gtk.Window.__init__(self)
-    othmanCore.__init__(self)
-    self.sw = None
-    self.lastSearchText=None
-    self.lastSearchResult=[]
-    self.ix=searchIndexer()
-    self.set_title(_('Othman Quran Browser'))
-    self.connect("delete_event", self.quit)
-    self.set_default_size(600, 480)
-
-    self.clip1=gtk.Clipboard(selection="PRIMARY")
-    self.clip2=gtk.Clipboard(selection="CLIPBOARD")
-    self.accel=gtk.AccelGroup()
-
-    vb=gtk.VBox(False,0); self.add(vb)
-    hb=gtk.HBox(False,2)
-    vb.pack_start(hb,False, False, 0)
-
-    self.scroll=gtk.ScrolledWindow()
-    self.scroll.set_policy(gtk.POLICY_NEVER,gtk.POLICY_ALWAYS)
-    self.scroll.connect_after("size-allocate", self.resize_cb)
-    vb.pack_start(self.scroll,True, True, 6)
-
-    img=gtk.Image()
-    img.set_from_stock(gtk.STOCK_COPY,gtk.ICON_SIZE_BUTTON)
-    b=gtk.Button()
-    b.add(img)
-    b.connect("clicked", self.show_cp_dlg)
-    hb.pack_start(b,False, False, 0)
-    hb.pack_start(gtk.VSeparator(),False, False, 6)
-    hb.pack_start(gtk.Label(_("Sura")),False, False, 0)
-
-    self.sura_ls=tuple("%d. %s" % (i+1,j[0]) for (i,j) in enumerate(self.suraInfoById))
-    self.sura_c = gtk.combo_box_new_text()
-    self.sura_c.set_wrap_width(5)
-    for i in self.sura_ls: self.sura_c.append_text(i)
-    self.sura_c.set_tooltip_text(_("choose a Sura"))
-    self.sura_c.connect("changed", self.sura_changed_cb)
-    hb.pack_start(self.sura_c,False, False, 0)
-
-    hb.pack_start(gtk.VSeparator(),False, False, 6)
-    img=gtk.Image()
-    img.set_from_stock(gtk.STOCK_ZOOM_IN, gtk.ICON_SIZE_BUTTON)
-    b=gtk.Button()
-    b.add(img)
-    hb.pack_start(b, False, False, 0)
-    b.connect("clicked", self.zoomIn)
-    
-    img=gtk.Image()
-    img.set_from_stock(gtk.STOCK_ZOOM_OUT, gtk.ICON_SIZE_BUTTON)
-    b=gtk.Button()
-    b.add(img)
-    hb.pack_start(b, False, False, 0)
-    b.connect("clicked", self.zoomOut)
-
-    img=gtk.Image()
-    img.set_from_stock(gtk.STOCK_MEDIA_FORWARD, gtk.ICON_SIZE_BUTTON)
-    b=gtk.ToggleButton()
-    b.add(img)
-    hb.pack_start(b, False, False, 0)
-    self.autoScrolling=False
-    b.connect("clicked", self.autoScrollCb)
-    glib.timeout_add(100, self.autoScroll, b)
-
-    hb.pack_start(gtk.VSeparator(), False, False, 6)
-    hb.pack_start(gtk.image_new_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_BUTTON), False, False, 0)
-    search=gtk.Entry(); search.set_width_chars(15)
-    hb.pack_start(search, False,False, 0)
-    search.connect("activate", self.search_cb)
-    self.search=search
-
-    hb.pack_start(gtk.VSeparator(),False, False, 6)
-    img=gtk.Image()
-    img.set_from_stock(gtk.STOCK_ABOUT, gtk.ICON_SIZE_BUTTON)
-    b=gtk.Button()
-    b.add(img)
-    hb.pack_start(b, False, False, 0)
-    b.connect("clicked", self.about)
-
-
-    self.scale=1
-    self.txt = gtk.ListStore(str,int,str)
-    self.cells=[]; self.cols=[]
-    self.cells.append(gtk.CellRendererText())
-    #self.cols.append(gtk.TreeViewColumn('Quranic Text', self.cells[0], markup=0))
-    self.cols.append(gtk.TreeViewColumn('Quranic Text', self.cells[0], text=0, foreground=2))
-    self.cells[0].set_property("background","#fffff8")
-    #self.cells[0].set_property("foreground","#204000")
-    #self.cells[0].set_property("alignment",pango.ALIGN_CENTER)
-    self.cells[0].set_property("wrap-mode",pango.WRAP_WORD_CHAR)
-    self.cells[0].set_property("wrap-width",500)
-    self.cells[0].set_property("font","Simplified Naskh 32")
-    #self.cells[0].set_property("font","KFGQPC Uthmanic Script HAFS 32")
-    self.cells[0].set_property("scale", self.scale)
-    self.cols[0].set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
-
-    self.cells.append(gtk.CellRendererText()); # self.cols[-1].set_expand(False)
-    self.txt_list=gtk.TreeView(self.txt)
-    self.txt_list.set_headers_visible(False)
-    for i in self.cols: self.txt_list.insert_column(i, -1)
-
-    self.scroll.add(self.txt_list)
-    self.sura_c.set_active(0)
-    self.build_cp_dlg()
-    self.build_about_dlg()
-    self.show_all()
-
-  def build_about_dlg(self):
-    self.about_w=gtk.AboutDialog()
-    self.about_w.set_default_response(gtk.RESPONSE_CLOSE)
-    self.about_w.connect('delete-event', lambda w,*a: w.hide() or True)
-    self.about_w.connect('response', lambda w,*a: w.hide() or True)
-    try: self.about_w.set_program_name("Othman")
-    except: pass
-    self.about_w.set_name(_('Othman Quran Browser'))
-    #self.about_w.set_version(version)
-    self.about_w.set_copyright("Copyright © 2008-2010 Muayyad Saleh Alsadi <alsadi at ojuba.org>")
-    self.about_w.set_comments(_("Electronic Mus-haf"))
-    self.about_w.set_license("""
-    Released under terms of Waqf Public License.
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the latest version Waqf Public License as
-    published by Ojuba.org.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-    The Latest version of the license can be found on
-    "http://waqf.ojuba.org/"
-
-""")
-    self.about_w.set_website("http://othman.ojuba.org/")
-    self.about_w.set_website_label("http://othman.ojuba.org")
-    self.about_w.set_authors(["Muayyad Saleh Alsadi <alsadi at ojuba.org>"])
-    self.about_w.set_translator_credits(_("translator-credits"))
-    fn=os.path.join(self.data_dir, "quran-kareem.svg")
-    try: logo=gtk.gdk.pixbuf_new_from_file_at_size(fn, 128, 128)
-    except:
-      fn=os.path.join(self.data_dir, "quran-kareem.png")
-      logo=gtk.gdk.pixbuf_new_from_file(fn)
-    self.about_w.set_logo(logo)
-
-
-  def about(self, b):
-    self.about_w.show_all()
-
-  def search_cb(self, b, *a):
-    if not self.sw: self.sw = searchWindow(self)
-    self.sw.find(b.get_text())
-
-  def autoScroll(self, b):
-    if not self.autoScrolling: return True
-    v=self.scroll.get_vadjustment()
-    m=v.upper-v.page_size
-    n=min(m, v.get_value() + 2 )
-    if n==m: b.set_active(False)
-    v.set_value(n)
-    return True
-
-  def autoScrollCb(self, b, *a):
-    self.autoScrolling=b.get_active()
-
-  def zoomIn(self, *a):
-    sura,aya=self.getCurrentSuraAya()
-    self.scale+=0.1
-    self.cells[0].set_property("scale", self.scale)
-    self.resize_cb()
-    self.queue_draw()
-    self.viewSura(sura)
-    self.viewAya(aya)
-
-  def zoomOut(self, *a):
-    sura,aya=self.getCurrentSuraAya()
-    self.scale-=0.1
-    self.scale=max(0.2, self.scale)
-    self.cells[0].set_property("scale", self.scale)
-    self.resize_cb()
-    self.queue_draw()
-    self.viewSura(sura)
-    self.viewAya(aya)
-
-  def viewAya(self, aya, sura=None):
-    if sura==None: sura=self.sura_c.get_active()+1
-    aya=max(1,abs(aya))
-    i=aya+int(self.showSunnahBasmala(sura))
-    self.txt_list.scroll_to_cell((i-1,))
-    self.txt_list.get_selection().select_path((i-1,))
-
-  def viewSura(self, i):
-    #self.play_pause.set_active(False)
-    self.txt.clear()
-    if self.showSunnahBasmala(i):
-      #self.txt.append(['<span foreground="#440000">%s</span>' % self.basmala,0,])
-      self.txt.append([self.basmala,0,"#802000",])
-    for j,k in enumerate(self.getSuraIter(i)):
-      self.txt.append([k[0],j+1,"#204000",])
-    self.resize_cb()
-    self.scroll.get_vadjustment().set_value(0)
-    self.txt_list.get_selection().select_path((0,))
-
-  def sura_changed_cb(self, c, *a):
-    self.viewSura(self.sura_c.get_active()+1)
-
-  def resize_cb(self,*args):
-    if self.cols[0].get_width()>10: self.cells[0].set_property("wrap-width",self.cols[0].get_width()-10)
-
-  def cp_cb(self, *a):
-    sura=self.cp_sura.get_active()+1
-    aya1=self.cp_from.get_value()
-    aya2=self.cp_to.get_value()
-    n=aya2-aya1+1
-    i=self.cp_is_imlai.get_active()
-    a=[' ','\n',' * ', ' *\n']
-    s=a[int(i)*2+int(self.cp_aya_perline.get_active())]
-    s=s.join([l[i] for l in self.getSuraIter(sura, n, aya1)])+'\n'
-    self.clip1.set_text(s)
-    self.clip2.set_text(s)
-    self.cp_w.hide()
-
-  def cp_sura_cb(self, *a):
-    sura=self.cp_sura.get_active()+1
-    m=self.suraInfoById[sura-1][5]
-    self.cp_from.set_range(1, m)
-    self.cp_to.set_range(1, m)
-    self.cp_from.set_value(1)
-    self.cp_to.set_value(m)
-
-  def show_cp_dlg(self, *a):
-    sura,aya=self.getCurrentSuraAya()
-    aya=max(1, abs(aya))
-    self.cp_sura.set_active(sura-1)
-    self.cp_sura_cb()
-    self.cp_from.set_value(aya)
-    self.cp_w.show_all()
-
-  def build_cp_dlg(self):
-    self.cp_w = gtk.Window()
-    self.cp_w.set_title(_('Copy to clipboard'))
-    self.cp_w.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
-    self.cp_w.connect('delete-event', lambda w,*a: w.hide() or True)
-    self.cp_sura = gtk.combo_box_new_text(); self.cp_sura.set_wrap_width(5)
-
-    for i in self.sura_ls: self.cp_sura.append_text(i)
-    self.cp_sura.set_tooltip_text(_("choose a Sura"))
-    
-    self.cp_from=gtk.SpinButton(gtk.Adjustment(0, 0, 286, 1, 10, 0))
-    self.cp_to=gtk.SpinButton(gtk.Adjustment(0, 0, 286, 1, 10, 0))
-    self.cp_is_imlai=gtk.CheckButton(_("Imla'i style"))
-    self.cp_aya_perline=gtk.CheckButton(_("an Aya per line"))
-    self.cp_ok=gtk.Button(stock=gtk.STOCK_OK)
-    self.cp_cancel=gtk.Button(stock=gtk.STOCK_CANCEL)
-    vb=gtk.VBox(False,0)
-    self.cp_w.add(vb)
-    hb=gtk.HBox(False,3)
-    vb.pack_start(hb,True,True,3)
-    hb.pack_start(gtk.Label("سورة"),False,False,3)
-    hb.pack_start(self.cp_sura,False,False,6)
-    hb=gtk.HBox(False,6)
-    vb.pack_start(hb,True,True,6)
-    hb.pack_start(gtk.Label("الآيات من"),False,False,3)
-    hb.pack_start(self.cp_from,False,False,3)
-    hb.pack_start(gtk.Label("إلى"),False,False,3)
-    hb.pack_start(self.cp_to,False,False,3)
-    hb=gtk.HBox(False,6)
-    vb.pack_start(hb,True,True,6)
-    hb.pack_start(self.cp_is_imlai,False,False,3)
-    hb.pack_start(self.cp_aya_perline,False,False,3)
-    hb=gtk.HBox(False,6)
-    vb.pack_start(hb,True,True,6)
-    hb.pack_start(self.cp_ok,False,False,6)
-    hb.pack_start(self.cp_cancel,False,False,6)
-    self.cp_sura.connect("changed", self.cp_sura_cb)
-    self.cp_cancel.connect('clicked', lambda *args: self.cp_w.hide())
-    self.cp_ok.connect('clicked', self.cp_cb)
-    self.cp_is_imlai.set_active(True)
-
-  def getCurrentSuraAya(self):
-    a=self.txt_list.get_selection().get_selected()
-    aya=1
-    if a: aya=self.txt[self.txt.get_path(a[1])[0]][1]
-    aya=max(aya,1)
-    return self.sura_c.get_active()+1, aya
-
-  def quit(self,*args):
-     gtk.main_quit()
-     return False
+class searchWindow(Gtk.Window):
+    def __init__(self, w):
+        Gtk.Window.__init__(self)
+        self.w = w
+        self.connect('delete-event', lambda w,*a: w.hide() or True)
+        self.last_txt = None
+        self.set_type_hint(Gdk.WindowTypeHint.UTILITY)
+        self.set_modal(True)
+        self.set_deletable(True)
+        self.set_title(_('Search results'))
+        self.set_transient_for(w)
+        vb = Gtk.VBox(False,0)
+        self.add(vb)
+        
+        self.search = Gtk.Entry()
+        self.search.set_width_chars(15)
+        vb.pack_start(self.search, False,False, 0)
+        
+        self.scroll = Gtk.ScrolledWindow()
+        self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC,Gtk.PolicyType.AUTOMATIC)
+        self.scroll.set_size_request(100, 250)
+        vb.pack_start(self.scroll,True, True, 6)
+        
+        self.ls = Gtk.ListStore(int,str,int,int)
+        self.cells = []
+        self.cols = []
+        self.cells.append(Gtk.CellRendererText())
+        self.cols.append(Gtk.TreeViewColumn(_('Sura'), self.cells[0], text=1))
+        self.cols[0].set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
+        self.cols[0].set_resizable(True)
+
+        self.cells.append(Gtk.CellRendererText()); # self.cols[-1].set_expand(False)
+        self.ls_w = Gtk.TreeView(self.ls)
+        self.ls_w.connect("cursor-changed", self.move)
+        self.ls_w.set_direction(Gtk.TextDirection.RTL)
+        self.ls_w.set_headers_visible(False)
+        for i in self.cols:
+            self.ls_w.insert_column(i, -1)
+        self.scroll.add(self.ls_w)
+        self.search.connect("activate", self.search_cb)
+        self.show_all()
+
+    def move(self, t):
+        a = self.ls_w.get_selection().get_selected()
+        if not a or len(a) < 2 or not a[1]:
+            return
+        sa = self.ls[self.ls.get_path(a[1])]
+        self.w.sura_c.set_active(sa[2]-1)
+        self.w.viewAya(sa[3], sa[2])
+
+    def search_cb(self, b, *a):
+        t = b.get_text()
+        self.w.search.set_text(t)
+        self.find(t)
+
+    def find(self, txt, backward = False):
+        txt = txt.strip()
+        if not txt:
+            self.hide()
+            return
+        if type(txt) == str:
+            txt = txt.decode('utf-8')
+        if txt == self.last_txt:
+            # TODO: just move cursor to next/prev result before showing it
+            pass
+        else:
+            self.search.set_text(txt)
+            self.last_txt = txt
+            self.ls.clear()
+            for i in self.w.ix.findPartial(txt.split()):
+                sura, aya = self.w.suraAyaFromAyaId(i)
+                name = self.w.suraInfoById[sura-1][0]
+                self.ls.append([i, "%03d %s - %03d" % (sura, name, aya), sura, aya,])
+            self.ls_w.set_cursor(Gtk.TreePath(path=0), None, False)
+        self.show_all()
+
+class othmanUi(Gtk.Window, othmanCore):
+    def __init__(self):
+        Gtk.Window.set_default_icon_name('Othman')
+        Gtk.Window.__init__(self)
+        othmanCore.__init__(self)
+        self.sw = None
+        self.lastSearchText = None
+        self.lastSearchResult = []
+        self.ix = searchIndexer()
+        self.set_title(_('Othman Quran Browser'))
+        self.connect("delete_event", self.quit)
+        self.connect('destroy', self.quit)
+        self.set_default_size(600, 480)
+        self.maximize()
+        self.clip1 = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY)
+        self.clip2 = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
+        self.accel = Gtk.AccelGroup()
+
+        vb = Gtk.VBox(False,0)
+        self.add(vb)
+        hb = Gtk.HBox(False,2)
+        vb.pack_start(hb, False, False, 0)
+
+        self.scroll = Gtk.ScrolledWindow()
+        self.scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
+        self.scroll.connect_after("size-allocate", self.resize_cb)
+        vb.pack_start(self.scroll, True, True, 6)
+
+        img = Gtk.Image()
+        img.set_from_stock(Gtk.STOCK_COPY, Gtk.IconSize.BUTTON)
+        b = Gtk.Button()
+        b.add(img)
+        b.connect("clicked", self.show_cp_dlg)
+        hb.pack_start(b,False, False, 0)
+        hb.pack_start(Gtk.VSeparator(), False, False, 6)
+        hb.pack_start(Gtk.Label(_("Sura")), False, False, 0)
+
+        self.sura_ls = tuple("%d. %s" % (i+1,j[0]) for (i,j) in enumerate(self.suraInfoById))
+        self.sura_c = Gtk.ComboBoxText.new()
+        self.sura_c.set_wrap_width(5)
+        for i in self.sura_ls:
+            self.sura_c.append_text(i)
+        self.sura_c.set_tooltip_text(_("choose a Sura"))
+        self.sura_c.connect("changed", self.sura_changed_cb)
+        hb.pack_start(self.sura_c, False, False, 0)
+
+        hb.pack_start(Gtk.VSeparator(),False, False, 6)
+        img = Gtk.Image()
+        img.set_from_stock(Gtk.STOCK_ZOOM_IN, Gtk.IconSize.BUTTON)
+        b = Gtk.Button()
+        b.add(img)
+        hb.pack_start(b, False, False, 0)
+        b.connect("clicked", self.zoomIn)
+        
+        img = Gtk.Image()
+        img.set_from_stock(Gtk.STOCK_ZOOM_OUT, Gtk.IconSize.BUTTON)
+        b = Gtk.Button()
+        b.add(img)
+        hb.pack_start(b, False, False, 0)
+        b.connect("clicked", self.zoomOut)
+
+        img = Gtk.Image()
+        img.set_from_stock(Gtk.STOCK_MEDIA_FORWARD, Gtk.IconSize.BUTTON)
+        b = Gtk.ToggleButton()
+        b.add(img)
+        hb.pack_start(b, False, False, 0)
+        self.autoScrolling = False
+        b.connect("clicked", self.autoScrollCb)
+        GLib.timeout_add(100, self.autoScroll, b)
+
+        hb.pack_start(Gtk.VSeparator(), False, False, 6)
+        hb.pack_start(Gtk.Image.new_from_stock(Gtk.STOCK_FIND, Gtk.IconSize.BUTTON), False, False, 0)
+        search = Gtk.Entry(); search.set_width_chars(15)
+        hb.pack_start(search, False,False, 0)
+        search.connect("activate", self.search_cb)
+        self.search = search
+
+        hb.pack_start(Gtk.VSeparator(),False, False, 6)
+        img = Gtk.Image()
+        img.set_from_stock(Gtk.STOCK_ABOUT, Gtk.IconSize.BUTTON)
+        b = Gtk.Button()
+        b.add(img)
+        hb.pack_start(b, False, False, 0)
+        b.connect("clicked", lambda *a: self.show_about_dlg(self))
+
+
+        self.scale = 1
+        self.txt = Gtk.ListStore(str,int,str)
+        self.cells = []
+        self.cols = []
+        self.cells.append(Gtk.CellRendererText())
+        #self.cols.append(Gtk.TreeViewColumn('Quranic Text', self.cells[0], markup=0))
+        self.cols.append(Gtk.TreeViewColumn('Quranic Text', self.cells[0], text = 0, foreground = 2))
+        self.cells[0].set_property("background","#fffff8")
+        #self.cells[0].set_property("foreground","#204000")
+        #self.cells[0].set_property("alignment",Pango.ALIGN_CENTER)
+        self.cells[0].set_property("wrap-mode", Pango.WrapMode.WORD)
+        self.cells[0].set_property("wrap-width", 500)
+        self.cells[0].set_property("font", "Simplified Naskh 32")
+        #self.cells[0].set_property("font","KFGQPC Uthmanic Script HAFS 32")
+        self.cells[0].set_property("scale", self.scale)
+        self.cols[0].set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
+
+        self.cells.append(Gtk.CellRendererText()); # self.cols[-1].set_expand(False)
+        self.txt_list = Gtk.TreeView(self.txt)
+        self.txt_list.set_headers_visible(False)
+        self.txt_list.set_direction(Gtk.TextDirection.RTL)
+        for i in self.cols:
+            self.txt_list.insert_column(i, -1)
+
+        self.scroll.add(self.txt_list)
+        self.sura_c.set_active(0)
+        self.build_cp_dlg()
+        self.show_all()
+
+    def show_about_dlg(self, parent):
+        dlg = Gtk.AboutDialog()
+        dlg.set_type_hint(Gdk.WindowTypeHint.DIALOG)
+        dlg.set_modal(True)
+        dlg.set_transient_for(parent)
+        dlg.set_default_response(Gtk.ResponseType.CLOSE)
+        dlg.connect('delete-event', lambda w,*a: w.hide() or True)
+        dlg.connect('response', lambda w,*a: w.hide() or True)
+        try:
+            dlg.set_program_name("Othman")
+        except:
+            pass
+        dlg.set_name(_('Othman Quran Browser'))
+        #dlg.set_version(version)
+        dlg.set_copyright("Copyright © 2008-2010 Muayyad Saleh Alsadi <alsadi at ojuba.org>")
+        dlg.set_comments(_("Electronic Mus-haf"))
+        dlg.set_license("""
+        Released under terms of Waqf Public License.
+        This program is free software; you can redistribute it and/or modify
+        it under the terms of the latest version Waqf Public License as
+        published by Ojuba.org.
+
+        This program is distributed in the hope that it will be useful,
+        but WITHOUT ANY WARRANTY; without even the implied warranty of
+        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+        The Latest version of the license can be found on
+        "http://waqf.ojuba.org/"
+
+        """)
+        dlg.set_website("http://othman.ojuba.org/")
+        dlg.set_website_label("http://othman.ojuba.org")
+        dlg.set_authors(["Muayyad Saleh Alsadi <alsadi at ojuba.org>"])
+        dlg.set_translator_credits(_("translator-credits"))
+        fn = os.path.join(self.data_dir, "quran-kareem.svg")
+        try:
+            logo = GdkPixbuf.Pixbuf.new_from_file_at_size(fn, 128, 128)
+        except:
+            fn = os.path.join(self.data_dir, "quran-kareem.png")
+            logo = GdkPixbuf.pixbuf_new_from_file(fn)
+        dlg.set_logo(logo)
+        #dlg.set_logo_icon_name('Othman')
+        dlg.run()
+        dlg.destroy()
+
+    def search_cb(self, b, *a):
+        if not self.sw:
+            self.sw = searchWindow(self)
+        self.sw.find(b.get_text())
+
+    def autoScroll(self, b):
+        if not self.autoScrolling:
+            return True
+        v = self.scroll.get_vadjustment()
+        m = v.get_upper() - v.get_page_size()
+        n = min(m, v.get_value() + 2 )
+        if n == m:
+            b.set_active(False)
+        v.set_value(n)
+        return True
+
+    def autoScrollCb(self, b, *a):
+        self.autoScrolling = b.get_active()
+
+    def zoomIn(self, *a):
+        sura, aya = self.getCurrentSuraAya()
+        self.scale += 0.1
+        self.cells[0].set_property("scale", self.scale)
+        self.resize_cb()
+        self.queue_draw()
+        self.viewSura(sura)
+        self.viewAya(aya)
+
+    def zoomOut(self, *a):
+        sura, aya = self.getCurrentSuraAya()
+        self.scale -= 0.1
+        self.scale = max(0.2, self.scale)
+        self.cells[0].set_property("scale", self.scale)
+        self.resize_cb()
+        self.queue_draw()
+        self.viewSura(sura)
+        self.viewAya(aya)
+
+    def viewAya(self, aya, sura = None):
+        if sura == None:
+            sura = self.sura_c.get_active() + 1
+        aya = max(1,abs(aya))
+        i = aya + int(self.showSunnahBasmala(sura))
+        self.txt_list.scroll_to_cell((i - 1,))
+        self.txt_list.get_selection().select_path((i - 1,))
+
+    def viewSura(self, i):
+        #self.play_pause.set_active(False)
+        self.txt.clear()
+        if self.showSunnahBasmala(i):
+            #self.txt.append(['<span foreground="#440000">%s</span>' % self.basmala,0,])
+            self.txt.append([self.basmala, 0, "#802000",])
+        for j, k in enumerate(self.getSuraIter(i)):
+            self.txt.append([k[0], j + 1, "#204000",])
+        self.resize_cb()
+        self.scroll.get_vadjustment().set_value(0)
+        self.txt_list.get_selection().select_path((0,))
+
+    def sura_changed_cb(self, c, *a):
+        self.viewSura(self.sura_c.get_active() + 1)
+
+    def resize_cb(self,*args):
+        if self.cols[0].get_width() > 10:
+            self.cells[0].set_property("wrap-width", self.cols[0].get_width() - 10)
+
+    def cp_cb(self, *a):
+        sura = self.cp_sura.get_active() + 1
+        aya1 = self.cp_from.get_value()
+        aya2 = self.cp_to.get_value()
+        n = aya2 - aya1 + 1
+        i = self.cp_is_imlai.get_active()
+        a = [' ', '\n', ' * ', ' *\n']
+        s = a[int(i) * 2 + int(self.cp_aya_perline.get_active())]
+        s = s.join([l[i] for l in self.getSuraIter(sura, n, aya1)]) + '\n'
+        self.clip1.set_text(s, -1)
+        self.clip2.set_text(s, -1)
+        self.cp_w.hide()
+
+    def cp_sura_cb(self, *a):
+        sura = self.cp_sura.get_active() + 1
+        m = self.suraInfoById[sura - 1][5]
+        self.cp_from.set_range(1, m)
+        self.cp_to.set_range(1, m)
+        self.cp_from.set_value(1)
+        self.cp_to.set_value(m)
+
+    def show_cp_dlg(self, *a):
+        sura, aya = self.getCurrentSuraAya()
+        aya = max(1, abs(aya))
+        self.cp_sura.set_active(sura - 1)
+        self.cp_sura_cb()
+        self.cp_from.set_value(aya)
+        self.cp_w.show_all()
+
+    def build_cp_dlg(self):
+        self.cp_w = Gtk.Window()
+        self.cp_w.set_title(_('Copy to clipboard'))
+        self.cp_w.set_type_hint(Gdk.WindowTypeHint.DIALOG)
+        self.cp_w.connect('delete-event', lambda w,*a: w.hide() or True)
+        self.cp_sura = Gtk.ComboBoxText.new()
+        self.cp_sura.set_wrap_width(5)
+
+        for i in self.sura_ls:
+            self.cp_sura.append_text(i)
+        self.cp_sura.set_tooltip_text(_("choose a Sura"))
+        adj = Gtk.Adjustment(0, 0, 286, 1, 10, 0)
+        self.cp_from = s = Gtk.SpinButton()
+        s.set_adjustment(adj)
+        self.cp_to = s = Gtk.SpinButton()
+        s.set_adjustment(adj)
+        self.cp_is_imlai = Gtk.CheckButton(_("Imla'i style"))
+        self.cp_aya_perline = Gtk.CheckButton(_("an Aya per line"))
+        self.cp_ok = Gtk.Button(stock=Gtk.STOCK_OK)
+        self.cp_cancel = Gtk.Button(stock=Gtk.STOCK_CANCEL)
+        vb = Gtk.VBox(False,0)
+        self.cp_w.add(vb)
+        hb = Gtk.HBox(False,3)
+        vb.pack_start(hb,True,True,3)
+        hb.pack_start(Gtk.Label(_("Sorat:")),False,False,3)
+        hb.pack_start(self.cp_sura,False,False,6)
+        hb = Gtk.HBox(False,6)
+        vb.pack_start(hb,True,True,6)
+        hb.pack_start(Gtk.Label(_("Ayat from:")),False,False,3)
+        hb.pack_start(self.cp_from,False,False,3)
+        hb.pack_start(Gtk.Label(_("To")),False,False,3)
+        hb.pack_start(self.cp_to,False,False,3)
+        hb = Gtk.HBox(False,6)
+        vb.pack_start(hb,True,True,6)
+        hb.pack_start(self.cp_is_imlai,False,False,3)
+        hb.pack_start(self.cp_aya_perline,False,False,3)
+        hb = Gtk.HBox(False,6)
+        vb.pack_start(hb,True,True,6)
+        hb.pack_start(self.cp_ok,False,False,6)
+        hb.pack_start(self.cp_cancel,False,False,6)
+        self.cp_sura.connect("changed", self.cp_sura_cb)
+        self.cp_cancel.connect('clicked', lambda *args: self.cp_w.hide())
+        self.cp_ok.connect('clicked', self.cp_cb)
+        self.cp_is_imlai.set_active(True)
+
+    def getCurrentSuraAya(self):
+        a = self.txt_list.get_selection().get_selected()
+        aya = 1
+        if a:
+            aya = self.txt[self.txt.get_path(a[1])][1]
+        aya = max(aya, 1)
+        return self.sura_c.get_active() + 1, aya
+
+    def quit(self,*args):
+         Gtk.main_quit()
+         return False
 
 def main():
-  exedir=os.path.dirname(sys.argv[0])
-  ld=os.path.join(exedir,'..','share','locale')
-  if not os.path.exists(ld): ld=os.path.join(exedir, 'locale')
-  gettext.install('othman', ld, unicode=0)
-  w=othmanUi()
-  gtk.main()
+    exedir = os.path.dirname(sys.argv[0])
+    ld = os.path.join(exedir,'..', 'share', 'locale')
+    if not os.path.exists(ld):
+        ld = os.path.join(exedir, 'locale')
+    gettext.install('othman', ld, unicode = 0)
+    w = othmanUi()
+    Gtk.main()
 
 if __name__ == "__main__":
-  main()
+    main()
 
diff --git a/othman/univaruints.py b/othman/univaruints.py
new file mode 100644
index 0000000..1babaf5
--- /dev/null
+++ b/othman/univaruints.py
@@ -0,0 +1,302 @@
+# -*- coding: UTF-8 -*-
+"""
+univaruints is a serialization of integer list
+Copyright © 2009-2013, Muayyad Alsadi <alsadi at ojuba.org>
+
+
+
+this implementation is unit-tested (by running this module)
+"""
+
+import struct, bisect
+int64=struct.Struct('>Q')
+shifts=[0, 128, 16512, 2113664, 270549120, 34630287488, 4432676798592, 567382630219904, 72624976668147840]
+shifts2=shifts[2:]
+n_by_chr='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x [...]
+
+def bisect_right7(a, x):
+	if x<a[3]:
+		if x<a[1]:
+			if (x<a[0]):
+				return 0
+			else:
+				return 1
+		else:
+			if x<a[2]:
+				return 2
+			else:
+				return 3
+	else:
+		if x<a[5]:
+			if x<a[4]:
+				return 4
+			else:
+				return 5
+		else:
+			if x<a[6]:
+				return 6
+			else:
+				return 7
+
+
+
+def write(f, s, max_items=0, incremental=0, unique=0, last_item=0):
+  """
+  encode the sequence s and write the string into the file-like object f
+
+  only max_items are encoded (0 mean infinity)
+  if incremental is set to True then the sequence is assumed to be incremental
+  which would result in more compact output
+  if you know that the sequence is strictly increasing then set unique=1
+  """
+  # NOTE: below some lookups before loop for optimizations
+  fwrite=f.write
+  rbisect=bisect_right7 #bisect.bisect_right
+  int64pack=int64.pack
+  char=chr
+
+  count=0
+  last_item-=unique
+  for item in s:
+    if max_items and count>=max_items: break
+    count+=1
+    v=item
+    if incremental:
+      if item<last_item+unique: raise ValueError
+      v-=last_item+unique
+    if v<128:
+      fwrite(char(v))
+    else:
+      n=rbisect(shifts2, v)+1
+      offset=shifts[n]
+      v-=offset
+      fwrite(char(((0b1111111100000000>>n) & 255) | ( (127>>n) & (v>>(n<<3)) ))+int64pack(v)[8-n:])
+    last_item=item
+  return count
+
+def read(f, max_items=0, incremental=0, unique=0, last_item=0):
+  """
+  read and decode sequence at most max_items from the file-like object
+
+  parameters are just like write
+  """
+  # NOTE: below some lookups before loop for optimizations
+  fread=f.read
+  int64unpack=int64.unpack
+  chr2int=ord
+
+  count=0
+  last_item-=unique
+
+  while True:
+    if max_items and count>=max_items: break
+    ch=fread(1)
+    if not ch: break
+    count+=1
+    o=chr2int(ch)
+    if o<128:
+      v=o
+    else:
+      n_ch=n_by_chr[o]
+      n=chr2int(n_ch)
+      mask=127>>n
+      payload=fread(n)
+      if len(payload)<n: raise IOError
+      v=shifts[n] + (((o & mask)<< (n<<3)) | ( (int64unpack(('\0'*(8-n))+payload))[0] ))
+    if incremental: v+=last_item+unique
+    yield v
+    last_item=v
+
+
+def decode_single(s):
+  """
+  return number of bytes consumed and the decoded value
+  """   
+  o=ord(s[0])
+  if o<128: return 1, o
+  n_ch=n_by_chr[o]
+  n=ord(n_ch)
+  mask=127>>n
+  return n+1, shifts[n] + (((o & mask)<< (n<<3)) | ( (int64.unpack(('\0'*(8-n))+s[1:n+1]))[0] ))
+
+def decode(s):
+  "return a generator that yields all decoded integers"
+  offset=0
+  while offset<len(s):
+    o=ord(s[offset])
+    offset+=1
+    if o<128: yield o # just an optimization
+    else:
+      n_ch=n_by_chr[o]
+      n=ord(n_ch)
+      mask=127>>n
+      yield shifts[n] + (((o & mask)<< (n<<3)) | ( (int64.unpack(('\0'*(8-n))+s[offset:offset+n]))[0] ))
+      offset+=n
+
+def encode_single(v):
+    if v<128: return chr(v)
+    n=bisect_right7(shifts2, v)+1 #bisect.bisect_right(shifts2, v)+1
+    offset=shifts[n]
+    v-=offset
+    return chr(((0b1111111100000000>>n) & 255) | ( (127>>n) & (v>>(n<<3)) )) + int64.pack(v)[8-n:]
+
+def encode_single_alt(v):
+    if v<128: return chr(v) # just an optimization
+    offset=128
+    m=0
+    # enumerate was slower
+    #for i,m in enumerate(shifts2):
+    for i in shifts2: # although we can use bisect, but we only got 8 elements
+        n=m+1
+        if v<i:
+            v-=offset
+            msb=((0b1111111100000000>>n) & 255) | ( (127>>n) & (v>>(n<<3)) )
+            p=int64.pack(v)
+            return chr(msb) + p[8-n:]
+        offset=i
+        m+=1
+    #m+=1 # if enumerate is used uncomment this line
+    v-=offset
+    n=m+1
+    msb=((0b1111111100000000>>n) & 255) | ( (127>>n) & (v>>(n<<3)) )
+    p=int64.pack(v)
+    return chr(msb) + p[8-n:]
+
+def encode(a):
+    return "".join(map(encode_single, a))
+
+def incremental_encode_list(a, unique=1, last=0):
+  if unique!=1 and unique!=0: raise ValueError
+  last-=unique
+  for i in a:
+    if i<last+unique: raise ValueError
+    yield i-last-unique
+    last=i
+
+def incremental_decode_list(a, unique=1, last=0):
+  if unique!=1 and unique!=0: raise ValueError
+  last-=unique
+  for i in a:
+    j=i+last+unique
+    yield j
+    last=j
+
+def incremental_encode(a, unique=1, last=0):
+  return encode(incremental_encode_list(a, unique, last))
+
+def incremental_decode(s, unique=1, last=0):
+  return incremental_decode_list(decode(s), unique, last)
+
+#import unittest
+#class TestSequenceFunctions(unittest.TestCase):
+#    def setUp(self):
+#        self.seq = range(10)
+#    def test_t1(self):
+#        self.assertEqual(x, y)
+#        self.assertRaises(TypeError, random.shuffle, (1,2,3))
+#        self.assertTrue(element in self.seq)
+# in main run unittest.main()
+
+if __name__ == "__main__":
+  import time, itertools, random
+  from cStringIO import StringIO
+  boundary=[(i-1,i,i+1) for i in shifts[1:]]
+  boundary=list(itertools.chain(*boundary))
+  boundary.insert(0,0)
+  print "simple unit tests..."
+  l1=[0,1,100,200,300,500,1000,10000]
+  for i in l1:
+    print 'before dec:', i, ', hex:', hex(i), ', bin:', bin(i)
+    e=encode_single(i)
+    print 'after len:',len(e), ', str:', repr(e)
+    assert i == decode_single(encode_single(i))[1]
+  f=StringIO()
+  write(f, l1)
+  f.seek(0)
+  assert l1==list(read(f))
+  print "boundary unit tests..."
+  for i in boundary:
+    print 'before dec:', i, ', hex:', hex(i), ', bin:', bin(i)
+    e=encode_single(i)
+    print 'after len:',len(e), ', str:', repr(e)
+    assert i == decode_single(encode_single(i))[1]
+  assert boundary == list(decode(encode(boundary)))
+  assert boundary == list(incremental_decode(incremental_encode(boundary, unique=0), unique=0))
+  assert boundary == list(incremental_decode(incremental_encode(boundary, unique=1), unique=1))
+  
+  f=StringIO()
+  write(f, boundary, 0, 0, 0)
+  f.seek(0)
+  assert boundary == list(read(f, 0, 0, 0))
+  f=StringIO()
+  write(f, boundary, 0, 1, 0)
+  f.seek(0)
+  assert boundary == list(read(f, 0, 1, 0))
+  f=StringIO()
+  write(f, boundary, 0, 1, 1)
+  f.seek(0)
+  assert boundary == list(read(f, 0, 1, 1))
+
+
+  print "random unit tests..."
+  l=[random.randint(0, 5000000) for i in range(1000)]
+  s=encode(l)
+  l2=list(decode(s))
+  assert l2==l
+  ll=0
+  l=[0]
+  for i in range(1000):
+    ll+=random.randint(0, 5000000)
+    l.append(ll)
+  l2=list(incremental_decode(incremental_encode(l, unique=0), unique=0))
+  assert l2==l
+
+  ll=0
+  l=[0]
+  for i in range(1000):
+    ll+=random.randint(1, 5000000)
+    l.append(ll)
+  l2=list(incremental_decode(incremental_encode(l, unique=1), unique=1))
+  assert l2==l
+
+  print "pass"
+  print "performance tests"
+  q=struct.Struct('>Q')
+  pack=lambda l: ''.join(itertools.imap(lambda i: q.pack(i), l))
+  def unpack(s):
+      for i in range(0,len(s),8):
+          yield q.unpack(s[i:i+8])[0]
+  t1=time.time()
+  for i in range(1000): list(unpack(pack(boundary)))
+  t2=time.time()
+  delta_pack=t2-t1
+  print 'struct-based done in ', delta_pack
+
+  f=StringIO()
+  t1=time.time()
+  for i in range(1000):
+    f.seek(0)
+    write(f, boundary)
+    f.seek(0)
+    list(read(f))
+  t2=time.time()
+  print 'file-like done in ', t2-t1
+
+
+  t1=time.time()
+  for i in range(1000): list(decode(encode(boundary)))
+  t2=time.time()
+  delta_our=t2-t1
+  print 'we are done in ', delta_our
+  t1=time.time()
+  for i in range(1000): encode(boundary)
+  t2=time.time()
+  delta_our=t2-t1
+  print 'we are done in encoding in ', delta_our
+  e=encode(boundary)
+  t1=time.time()
+  for i in range(1000): list(decode(e))
+  t2=time.time()
+  delta_our=t2-t1
+  print 'we are done in decoding in ', delta_our
+
diff --git a/othman/varuints.py b/othman/varuints.py
deleted file mode 100644
index 4d60e1a..0000000
--- a/othman/varuints.py
+++ /dev/null
@@ -1,170 +0,0 @@
-# -*- coding: UTF-8 -*-
-"""
-Othman - Quran browser
-varuints is a serialization of integer list
-
-Copyright © 2009-2011, Muayyad Alsadi <alsadi at ojuba.org>
-
-    Released under terms of Waqf Public License.
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the latest version Waqf Public License as
-    published by Ojuba.org.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-    The Latest version of the license can be found on
-    "http://waqf.ojuba.org/license"
-
-varuints is a serialization of integer list
-based on idea from http://code.google.com/apis/protocolbuffers/docs/encoding.html
-
-but unlike protocolbuffers it preserve order by saving most significant first
-
-in this implementation a single varuint can be something like
-
-1xxx-xxxx 1xxx-xxxx 0xxx-xxxx
-
-MSB in each byte is "has_more", and rest bits are base-128 int
-the above is xxx-xxx xxx-xxxx xxx-xxxx
-
-
-0xxx-xxxx is 0-127
-
-1xxx-xxxx 0xxx-xxxx  is 128-16511
-
-and so on
-
-use it like this
-
-s=varuints.decode([150,5,7])
-a=from_varints(s)
-
-"""
-
-def decode(s):
-  v=0
-  for c in s:
-    c=ord(c)
-    v+=(c&127)
-    if (c&128)==0: yield v; v=0
-    else: v+=1
-    v<<=7
-  if v: raise ValueError
-
-def decode_single(s):
-  v=0
-  for c in s:
-    c=ord(c)
-    v+=(c&127)
-    if (c&128)==0: return v; v=0
-    else: v+=1
-    v<<=7
-  if v: raise ValueError
-
-
-def encode_single(i):
-  r=""
-  k=0
-  j,m=0,0
-  while(1):
-      r=chr(m|(i&127))+r
-      m=128
-      j+=1
-      i>>=7
-      if i==0: return r
-      i-=1
-  raise ValueError # never reached
-
-
-def encode(a):
-  r=[]
-  k=0
-  for i in a:
-    j,m=0,0
-    while(1):
-      r.insert(k,chr(m|(i&127)))
-      m=128
-      j+=1
-      i>>=7
-      if i==0: break
-      i-=1
-    k+=j
-  return "".join(r)
-
-def write(f, a):
-  """encode members of a and write them to file f and return the number of bytes written"""
-  s=encode(a)
-  f.write(s)
-  return len(s)
-
-def read(f, limit=1):
-  """read and decode up to limit integers from file f and return them"""
-  v,n=0,0
-  while(n<limit):
-    c=f.read(1)
-    if c=='': raise ValueError
-    c=ord(c)
-    v+=(c&127)
-    if (c&128)==0: yield v; v=0; n+=1
-    else: v+=1
-    v<<=7
-  if v: raise ValueError
-
-def read_single(f):
-  """read and decode a single varuint from file f and return it"""
-  return read(f,1).next()
-
-
-def incremental_encode_list(a, unique=1, last=0):
-  if unique!=1 and unique!=0: raise ValueError
-  for i in a:
-    if i<last+unique: raise ValueError
-    yield i-last-unique
-    last=i
-
-def incremental_decode_list(a, unique=1, last=0):
-  if unique!=1 and unique!=0: raise ValueError
-  for i in a:
-    j=i+last+unique
-    yield j
-    last=j
- 
-def incremental_encode(a, unique=1, last=0):
-  return encode(incremental_encode_list(a, unique, last))
-
-def incremental_decode(s, unique=1, last=0):
-  return incremental_decode_list(decode(s), unique, last)
-
-def incremental_write(f, a, unique=1, last=0):
-  return write(f, incremental_encode_list(a, unique, last))
-
-def incremental_read(f, unique=1, limit=1, last=0):
-  return incremental_decode_list(read(f, limit), unique, last)
-
-
-def decode_safe(s):
-  v=0
-  for c in s:
-    c=safe_ord(c)
-    v<<=6
-    v+=c&63
-    if (c&64)==0: yield v; v=0
-  if v: raise
-
-def encode_safe(a):
-  r=[]
-  k=0
-  for i in a:
-    j,m=0,0
-    while(i>0):
-      r.insert(k,safe_chr(m|(i&63)))
-      i>>=6
-      m=64
-      j+=1
-    if j==0: r.insert(k,safe_chr(0)); k+=1
-    else: k+=j
-  return "".join(r)
-
-
diff --git a/po/ar.po b/po/ar.po
index 723f3c3..b849d58 100644
--- a/po/ar.po
+++ b/po/ar.po
@@ -6,50 +6,62 @@ msgid ""
 msgstr ""
 "Project-Id-Version: othman 0.2.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-05-04 17:44+0300\n"
+"POT-Creation-Date: 2012-06-04 05:56+0200\n"
 "PO-Revision-Date: 2010-04-28 18:31+0300\n"
 "Last-Translator: alsadi <alsadi at ojuba.org>\n"
 "Language-Team: thawab at ojuba.org\n"
+"Language: ar\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Language: ar\n"
 "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
 "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
 "X-Generator: Virtaal 0.5.0\n"
 
-#: ../Othman.desktop.in.h:1 ../othman/gtkUi.py:205
+#: ../Othman.desktop.in.h:1 ../othman/gtkUi.py:232
 msgid "Electronic Mus-haf"
 msgstr "المصحف الإلكتروني"
 
-#: ../Othman.desktop.in.h:2 ../othman/gtkUi.py:96 ../othman/gtkUi.py:202
+#: ../Othman.desktop.in.h:2 ../othman/gtkUi.py:111 ../othman/gtkUi.py:229
 msgid "Othman Quran Browser"
 msgstr "مصحف عثمان الإلكتروني"
 
-#: ../othman/gtkUi.py:37
+#: ../othman/gtkUi.py:35
 msgid "Search results"
 msgstr "نتائج البحث"
 
-#: ../othman/gtkUi.py:50 ../othman/gtkUi.py:120
+#: ../othman/gtkUi.py:53 ../othman/gtkUi.py:137
 msgid "Sura"
 msgstr "سورة"
 
-#: ../othman/gtkUi.py:126 ../othman/gtkUi.py:327
+#: ../othman/gtkUi.py:144 ../othman/gtkUi.py:366
 msgid "choose a Sura"
 msgstr "اختر سورة"
 
-#: ../othman/gtkUi.py:223
+#: ../othman/gtkUi.py:250
 msgid "translator-credits"
 msgstr "مؤيد صالح السعدي <alsadi at ojuba.org>"
 
-#: ../othman/gtkUi.py:321
+#: ../othman/gtkUi.py:358
 msgid "Copy to clipboard"
 msgstr "نسخ إلى الحافظة"
 
-#: ../othman/gtkUi.py:331
+#: ../othman/gtkUi.py:372
 msgid "Imla'i style"
 msgstr "بالرسم الإملائي"
 
-#: ../othman/gtkUi.py:332
+#: ../othman/gtkUi.py:373
 msgid "an Aya per line"
 msgstr "كل آية على كل سطر مستقل"
+
+#: ../othman/gtkUi.py:380
+msgid "Sorat:"
+msgstr "سورة :"
+
+#: ../othman/gtkUi.py:384
+msgid "Ayat from:"
+msgstr "الآيات من:"
+
+#: ../othman/gtkUi.py:386
+msgid "To"
+msgstr "إلى :"
diff --git a/po/de.po b/po/de.po
index 8d21a59..4cebb5a 100644
--- a/po/de.po
+++ b/po/de.po
@@ -7,52 +7,59 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-05-04 17:44+0300\n"
+"POT-Creation-Date: 2012-06-04 05:56+0200\n"
 "PO-Revision-Date: 2010-08-27 23:29+0100\n"
 "Last-Translator: cegerxwin <cegerxwin at web.de>\n"
 "Language-Team: LANGUAGE <LL at li.org>\n"
+"Language: \n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: ../Othman.desktop.in.h:1
-#: ../othman/gtkUi.py:205
+#: ../Othman.desktop.in.h:1 ../othman/gtkUi.py:232
 msgid "Electronic Mus-haf"
 msgstr "Elektronischer Mus-Haf"
 
-#: ../Othman.desktop.in.h:2
-#: ../othman/gtkUi.py:96
-#: ../othman/gtkUi.py:202
+#: ../Othman.desktop.in.h:2 ../othman/gtkUi.py:111 ../othman/gtkUi.py:229
 msgid "Othman Quran Browser"
 msgstr "Othman Koran Browser"
 
-#: ../othman/gtkUi.py:37
+#: ../othman/gtkUi.py:35
 msgid "Search results"
 msgstr "Suchergebnisse"
 
-#: ../othman/gtkUi.py:50
-#: ../othman/gtkUi.py:120
+#: ../othman/gtkUi.py:53 ../othman/gtkUi.py:137
 msgid "Sura"
 msgstr "Sure"
 
-#: ../othman/gtkUi.py:126
-#: ../othman/gtkUi.py:327
+#: ../othman/gtkUi.py:144 ../othman/gtkUi.py:366
 msgid "choose a Sura"
 msgstr "Wähle eine Sure aus"
 
-#: ../othman/gtkUi.py:223
+#: ../othman/gtkUi.py:250
 msgid "translator-credits"
 msgstr "Übersetzer"
 
-#: ../othman/gtkUi.py:321
+#: ../othman/gtkUi.py:358
 msgid "Copy to clipboard"
 msgstr "In Zwischenablage kopieren"
 
-#: ../othman/gtkUi.py:331
+#: ../othman/gtkUi.py:372
 msgid "Imla'i style"
 msgstr "Imla'i Stil"
 
-#: ../othman/gtkUi.py:332
+#: ../othman/gtkUi.py:373
 msgid "an Aya per line"
 msgstr "eine Aya pro Zeile"
 
+#: ../othman/gtkUi.py:380
+msgid "Sorat:"
+msgstr ""
+
+#: ../othman/gtkUi.py:384
+msgid "Ayat from:"
+msgstr ""
+
+#: ../othman/gtkUi.py:386
+msgid "To"
+msgstr ""
diff --git a/po/othman.pot b/po/othman.pot
index cd85fe3..43d7cfb 100644
--- a/po/othman.pot
+++ b/po/othman.pot
@@ -8,46 +8,59 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-05-04 17:44+0300\n"
+"POT-Creation-Date: 2012-06-04 05:56+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
 "Language-Team: LANGUAGE <LL at li.org>\n"
+"Language: \n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: ../Othman.desktop.in.h:1 ../othman/gtkUi.py:205
+#: ../Othman.desktop.in.h:1 ../othman/gtkUi.py:232
 msgid "Electronic Mus-haf"
 msgstr ""
 
-#: ../Othman.desktop.in.h:2 ../othman/gtkUi.py:96 ../othman/gtkUi.py:202
+#: ../Othman.desktop.in.h:2 ../othman/gtkUi.py:111 ../othman/gtkUi.py:229
 msgid "Othman Quran Browser"
 msgstr ""
 
-#: ../othman/gtkUi.py:37
+#: ../othman/gtkUi.py:35
 msgid "Search results"
 msgstr ""
 
-#: ../othman/gtkUi.py:50 ../othman/gtkUi.py:120
+#: ../othman/gtkUi.py:53 ../othman/gtkUi.py:137
 msgid "Sura"
 msgstr ""
 
-#: ../othman/gtkUi.py:126 ../othman/gtkUi.py:327
+#: ../othman/gtkUi.py:144 ../othman/gtkUi.py:366
 msgid "choose a Sura"
 msgstr ""
 
-#: ../othman/gtkUi.py:223
+#: ../othman/gtkUi.py:250
 msgid "translator-credits"
 msgstr ""
 
-#: ../othman/gtkUi.py:321
+#: ../othman/gtkUi.py:358
 msgid "Copy to clipboard"
 msgstr ""
 
-#: ../othman/gtkUi.py:331
+#: ../othman/gtkUi.py:372
 msgid "Imla'i style"
 msgstr ""
 
-#: ../othman/gtkUi.py:332
+#: ../othman/gtkUi.py:373
 msgid "an Aya per line"
 msgstr ""
+
+#: ../othman/gtkUi.py:380
+msgid "Sorat:"
+msgstr ""
+
+#: ../othman/gtkUi.py:384
+msgid "Ayat from:"
+msgstr ""
+
+#: ../othman/gtkUi.py:386
+msgid "To"
+msgstr ""
diff --git a/waqf2-ar.pdf b/waqf2-ar.pdf
new file mode 100644
index 0000000..b4a0f47
Binary files /dev/null and b/waqf2-ar.pdf differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-islamic/packages/othman.git



More information about the Debian-islamic-commits mailing list