Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRuben Rodriguez <ruben@activitycentral.com>2012-09-11 12:30:30 (GMT)
committer Ruben Rodriguez <ruben@activitycentral.com>2012-09-11 12:30:30 (GMT)
commitd5c250f42dd763ff3989189e703d2be089d49800 (patch)
treef01adfb910fd7d8db53943e5c0dc030c53e0d95d
parentb74da84c4833281dd7149f406b19db858e04e12a (diff)
parent1a547d51db460bd0b7138a3860b6fdc8a0fc893c (diff)
Merge branch 'bleeding-edge'; commit '1a547d51' into AU
-rw-r--r--config/dextrose3-common.ini1
-rw-r--r--examples/olpc-os-11.3.1-xo1.5.ini2
-rw-r--r--examples/olpc-os-11.3.1-xo1.75.ini2
-rw-r--r--examples/olpc-os-11.3.1-xo1.ini2
-rw-r--r--modules/base/kspost.10.core.inc46
-rw-r--r--modules/library_homepage/kspost.50.nochroot.library.sh1
-rw-r--r--modules/sd_card_image/image.50.makefs.sh5
-rw-r--r--modules/x11/kspost.60.misc.inc3
-rw-r--r--modules/xo1_75/kspkglist.50.xo1_75.inc3
-rwxr-xr-xosbuilder.py2
-rw-r--r--rpms/buildall.sh49
-rw-r--r--rpms/buildrpm.sh123
-rw-r--r--rpms/sugar-artwork/sugar-artwork.spec8
-rw-r--r--rpms/sugar-toolkit/sugar-toolkit.spec7
-rw-r--r--rpms/sugar/0000-Add-files-from-git-that-are-missing-from-tarball.patch2900
-rw-r--r--rpms/sugar/0000-langs.patch11
-rw-r--r--rpms/sugar/0063-Add-quz-and-aym-to-ALL_LINGUAS-take-2.patch27
-rw-r--r--rpms/sugar/0130-1-to-N-feature-via-School-Server.patch1954
-rw-r--r--rpms/sugar/0131-ac-2265-Displaying-the-laptop-model-in-the-control-p.patch72
-rw-r--r--rpms/sugar/0132-ac-2266-Displaying-the-upgrade-version-in-the-contro.patch178
-rw-r--r--rpms/sugar/0133-ac-2268-Extensions-removal-touchpad-modes-system-mon.patch642
-rw-r--r--rpms/sugar/0134-translation-fix-closes-sdxo-2218.patch28
-rw-r--r--rpms/sugar/0135-ac-2233-Change-the-behaviour-of-Sugar-not-connect-to.patch45
-rw-r--r--rpms/sugar/0136-ac-126-PART-Backporting-the-mainline-patch-that-inco.patch50
-rw-r--r--rpms/sugar/0137-sugar-gnomekeyring.patch33
-rw-r--r--rpms/sugar/AUlangs.diff11
-rw-r--r--rpms/sugar/sugar.spec23
27 files changed, 3248 insertions, 2980 deletions
diff --git a/config/dextrose3-common.ini b/config/dextrose3-common.ini
index 7358d19..facde34 100644
--- a/config/dextrose3-common.ini
+++ b/config/dextrose3-common.ini
@@ -48,6 +48,7 @@ dx3_common_packages_add=
httpd,
; au#1588: need "openssl-devel" package, for "libcrypto.so".
openssl-devel,
+ mod_ssl,
; accessibility packages
; Already added as dependencies for sugar-control-accessibility
diff --git a/examples/olpc-os-11.3.1-xo1.5.ini b/examples/olpc-os-11.3.1-xo1.5.ini
index 18f1061..9b3293b 100644
--- a/examples/olpc-os-11.3.1-xo1.5.ini
+++ b/examples/olpc-os-11.3.1-xo1.5.ini
@@ -1,5 +1,5 @@
[global]
-suggested_oob_version=4.0
+suggested_oob_version=4.1
fedora_release=14
olpc_version_major=11
olpc_version_minor=3
diff --git a/examples/olpc-os-11.3.1-xo1.75.ini b/examples/olpc-os-11.3.1-xo1.75.ini
index 2f67e59..53b7f99 100644
--- a/examples/olpc-os-11.3.1-xo1.75.ini
+++ b/examples/olpc-os-11.3.1-xo1.75.ini
@@ -1,5 +1,5 @@
[global]
-suggested_oob_version=4.0
+suggested_oob_version=4.1
fedora_release=14
olpc_version_major=11
olpc_version_minor=3
diff --git a/examples/olpc-os-11.3.1-xo1.ini b/examples/olpc-os-11.3.1-xo1.ini
index 02137e5..93819ef 100644
--- a/examples/olpc-os-11.3.1-xo1.ini
+++ b/examples/olpc-os-11.3.1-xo1.ini
@@ -1,5 +1,5 @@
[global]
-suggested_oob_version=4.0
+suggested_oob_version=4.1
fedora_release=14
olpc_version_major=11
olpc_version_minor=3
diff --git a/modules/base/kspost.10.core.inc b/modules/base/kspost.10.core.inc
index d3324d9..27e1e4a 100644
--- a/modules/base/kspost.10.core.inc
+++ b/modules/base/kspost.10.core.inc
@@ -217,18 +217,43 @@ SearchAndDeleteLineContainingRegex $filename " *<LWIN> = 133; *"
SearchAndReplaceRegex $filename "<CAPS> = 66;" "<CAPS> = 133;"
# uy#1769 : Set up "httpd", to host "WebDAV" shares.
-filename="/etc/httpd/conf/httpd.conf"
-SearchAndReplaceRegex $filename "#<VirtualHost \*:80>" "<VirtualHost \*:80>"
-SearchAndDeleteLineContainingRegex $filename "#<\/VirtualHost>"
-
-mkdir -p /var/www/web1/web
+#
+#
+# Make the directories (if not already), and set the permissions.
+#
mkdir -p /var/www/web1/web/.Sugar-Metadata
+chmod -R 0777 /var/www/web1/
+# Some necessary tweaks in "httpd" service.
+#
rm /etc/httpd/logs
mkdir /etc/httpd/logs
-cat << EOF >> /etc/httpd/conf/httpd.conf
- DocumentRoot /var/www/web1/web/
+# Generate the ssl-key and certificate.
+# Note that initially, all XOs will be having the same pair
+# (since the same image will be installled on all XOs).
+#
+# However, a new unique pair will be generated per XO, once the user
+# creates her sugar-profile (on first startup of the XO).
+mkdir -p /home/olpc/.sugar/default
+openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" -keyout /home/olpc/.sugar/default/ssl.key -out /home/olpc/.sugar/default/ssl.crt
+
+# Replace the key- and crt-path in conf-file, so that secure-transfer may be enabled.
+#
+filename="/etc/httpd/conf.d/ssl.conf"
+SearchAndReplaceRegex $filename "SSLCertificateKeyFile \/etc\/pki\/tls\/private\/localhost.key" "SSLCertificateKeyFile \/home\/olpc\/.sugar\/default\/ssl.key"
+SearchAndReplaceRegex $filename "SSLCertificateFile \/etc\/pki\/tls\/certs\/localhost.crt" "SSLCertificateFile \/home\/olpc\/.sugar\/default\/ssl.crt"
+
+# Create the password file for WebDAV.
+#
+htpasswd -bc /var/www/web1/passwd.dav test olpc
+
+# Finally, configure "VirtualHost".
+filename="/etc/httpd/conf.d/ssl.conf"
+SearchAndDeleteLineContainingRegex $filename "<\/VirtualHost>"
+cat << EOF >> /etc/httpd/conf.d/ssl.conf
+
+ DocumentRoot /var/www/web1/web
<Directory /var/www/web1/web/>
Options Indexes MultiViews
AllowOverride None
@@ -246,13 +271,10 @@ cat << EOF >> /etc/httpd/conf/httpd.conf
Require valid-user
</Location>
</VirtualHost>
-
EOF
-
-chmod -R 0777 /var/www/web1/web
-chmod -R 0777 /var/www/web1/web/.Sugar-Metadata
-htpasswd -bc /var/www/web1/passwd.dav test olpc
+# Change the startup preferences of services.
+#
/sbin/chkconfig httpd --levels 5 on
# uy#1769 customizations end.
diff --git a/modules/library_homepage/kspost.50.nochroot.library.sh b/modules/library_homepage/kspost.50.nochroot.library.sh
index ca0a27d..5ca1f38 100644
--- a/modules/library_homepage/kspost.50.nochroot.library.sh
+++ b/modules/library_homepage/kspost.50.nochroot.library.sh
@@ -17,3 +17,4 @@ fi
# synchronize the files within the path, conserving directory structure
echo "rsync -rlpt \"$path\"/ \"\$INSTALL_ROOT/usr/share/library-common/\""
+echo "chmod -R ugo+rx \"\$INSTALL_ROOT/usr/share/library-common/\""
diff --git a/modules/sd_card_image/image.50.makefs.sh b/modules/sd_card_image/image.50.makefs.sh
index 4fdc677..a88f72a 100644
--- a/modules/sd_card_image/image.50.makefs.sh
+++ b/modules/sd_card_image/image.50.makefs.sh
@@ -50,7 +50,10 @@ make_image()
8192,131072,83,*
139264,,,
EOF
- local img_sectors=$(sfdisk -uS -l $img | grep img2 | awk '{print $4}')
+ # sfdisk output truncates paths that are too long
+ pushd $intermediatesdir
+ local img_sectors=$(sfdisk -uS -l $(basename $img) | grep img2 | awk '{print $4}')
+ popd
echo "(1 losetup error is normal here)"
losetup -d /dev/loop6 || :
losetup -o $((8192 * $BLOCK_SIZE)) --sizelimit $((131072 * $BLOCK_SIZE)) /dev/loop6 $img
diff --git a/modules/x11/kspost.60.misc.inc b/modules/x11/kspost.60.misc.inc
index 1b284e3..d812e59 100644
--- a/modules/x11/kspost.60.misc.inc
+++ b/modules/x11/kspost.60.misc.inc
@@ -1,6 +1,3 @@
-# Workaround an unknown bug where TamTam sound is crackly on XO-1.5 (#9414)
-sed -i -e 's/dmix.rate 48000/dmix.rate 44100/' /usr/share/alsa/alsa.conf
-
# Don't try and autospawn pulseaudio (#9470)
sed -i -e 's/; autospawn = yes/autospawn = no/' /etc/pulse/client.conf
diff --git a/modules/xo1_75/kspkglist.50.xo1_75.inc b/modules/xo1_75/kspkglist.50.xo1_75.inc
index 99c85ae..5229ebc 100644
--- a/modules/xo1_75/kspkglist.50.xo1_75.inc
+++ b/modules/xo1_75/kspkglist.50.xo1_75.inc
@@ -5,3 +5,6 @@ olpc-runin-tests
# currently not pulled in by ARM for some reason
ntfs-3g
+
+# 2-bpp version of Adwaita cursors
+cursors-adwaita2b
diff --git a/osbuilder.py b/osbuilder.py
index 2893166..6dc5165 100755
--- a/osbuilder.py
+++ b/osbuilder.py
@@ -18,7 +18,7 @@
#
# canonical source of version number
-VERSION="4.0.0"
+VERSION="4.1.0"
# "make install" modifies this in the installed copy
INSTALLED=0
diff --git a/rpms/buildall.sh b/rpms/buildall.sh
new file mode 100644
index 0000000..f0723b3
--- /dev/null
+++ b/rpms/buildall.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# Copyright (C) 2012 Ruben Rodriguez <ruben@trisquel.info>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Builds all Dextrose-patched Sugar RPMs and puts them in ~/repo
+
+arch |grep -q arm && ARCH=armv5tel || ARCH=i686
+BRANCH=$( git branch|grep '*' |cut -c3- )
+
+mkdir ~/repo/specs ~/repo/$ARCH/os ~/repo/$ARCH/debug ~/repo/source ~/repo/buildlogs -p
+
+makeandpush() {
+ PACKAGE=$2
+ VERSION=$1
+
+ sh buildrpm.sh $VERSION $PACKAGE 2>&1 | tee ~/repo/buildlogs/$PACKAGE-$VERSION-$(date +%Y%m%d)-$ARCH.rpmbuild.log
+
+ cp -v ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec ~/repo/specs/$PACKAGE-$(date +%Y%m%d)-$ARCH.spec
+ cp -v ~/rpmbuild/SRPMS/* ~/repo/source
+ cp -v ~/rpmbuild/RPMS/*/* ~/repo/$ARCH/os
+ cp -v ~/rpmbuild/RPMS/$PACKAGE-$VERSION.appliedpatches ~/repo/buildlogs/$PACKAGE-$VERSION-$(date +%Y%m%d)-$ARCH.appliedpatches.log
+ cp -v ~/rpmbuild/RPMS/$PACKAGE-$VERSION.failedpatches ~/repo/buildlogs/$PACKAGE-$VERSION-$(date +%Y%m%d)-$ARCH.failedpatches.log
+ mv -v ~/repo/$ARCH/os/*debuginfo* ~/repo/$ARCH/debug
+}
+
+makeandpush 0.94.1 sugar
+makeandpush 0.94.1 sugar-toolkit
+makeandpush 0.94.0 sugar-artwork
+
+createrepo ~/repo/$ARCH/os
+createrepo ~/repo/source
+createrepo ~/repo/$ARCH/debug
+
+[ $ARCH = "i686" ] && rsync -va ~/repo//* quidam@shell.sugarlabs.org:dextrose-repo/v3/$BRANCH/
+[ $ARCH = "armv5tel" ] && rsync -va ~/repo/armv5tel repo/buildlogs quidam@shell.sugarlabs.org:dextrose-repo/v3/$BRANCH/
diff --git a/rpms/buildrpm.sh b/rpms/buildrpm.sh
new file mode 100644
index 0000000..1b935e2
--- /dev/null
+++ b/rpms/buildrpm.sh
@@ -0,0 +1,123 @@
+#!/bin/bash
+#
+# Copyright (C) 2012 Ruben Rodriguez <ruben@trisquel.info>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+# This script builds Dextrose patched, Sugar rpms from git repositories
+# Requirements: git, yum-utils, rpmbuild, patch, libtool, intltool, createrepo
+
+set -e
+
+if [ $# != 2 ]
+then
+ echo Usage: sh $0 version package
+ echo Example: sh $0 0.94.1 sugar-toolkit
+ exit 1
+fi
+
+# Let's make sure we have all we need
+yum -y install git yum-utils rpmbuild patch libtool intltool createrepo
+
+WD=$PWD
+VERSION=$1
+PACKAGE=$2
+FUZZ=20
+ARCH=$(rpm -q glibc |sed 's/.*\.//;s/i686/i386/')
+TEST=$(mktemp -d)
+
+rm -rf ~/rpmbuild/SOURCES ~/rpmbuild/SPECS
+
+mkdir -p ~/rpmbuild/BUILD ~/rpmbuild/BUILDROOT ~/rpmbuild/RPMS ~/rpmbuild/SOURCES ~/rpmbuild/SPECS/$PACKAGE ~/rpmbuild/SRPMS
+
+
+cp $PACKAGE/$PACKAGE.spec ~/rpmbuild/SPECS/$PACKAGE/
+[ -f $PACKAGE/macros.$PACKAGE ] && cp $PACKAGE/macros.$PACKAGE ~/rpmbuild/SOURCES/
+
+git clone git://git.sugarlabs.org/$PACKAGE/mainline.git ~/rpmbuild/SOURCES/$PACKAGE-$VERSION
+cd ~/rpmbuild/SOURCES/$PACKAGE-$VERSION
+git checkout v$VERSION
+cd $WD
+sed "s/Version:.*/Version: $VERSION/" ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+sed "s/Release:.*/Release: $(date +%Y%m%d)dx3/" ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+# Since sugar and sugar-artwork DX3 specs *already* have epoch set to the
+# date number, we will continue that hack for DX3. BUT THIS IS WRONG!!!
+sed '/^Epoch:/d' -i ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec
+sed "/^Name:/s/$/\nEpoch: $(date +%Y%m%d)/" -i ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec
+
+# Let's allow some fuzz
+sed "1s/$/\n%define _default_patch_fuzz $FUZZ/" -i ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec
+
+cd ~/rpmbuild/SOURCES/$PACKAGE-$VERSION
+[ $PACKAGE = "sugar-artwork" ] && sed '/GNOME_COMPILE_WARNINGS/d' configure.ac -i
+sh autogen.sh
+cd ..
+tar -jcvf $PACKAGE-$VERSION.tar.bz2 $PACKAGE-$VERSION
+cd $WD
+
+############################################################################
+
+# Set tokens for adding patches to the spec file
+sed "/^Source0/s/$/\n\#ListPatches/" ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+sed "/^%setup/s/$/\n\#MakePatches/" ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+sed "/^Patch/d" ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+sed "/^%*patch/d" ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+
+# number, name, string, strip
+addpatch(){
+sed "/ListPatches/s%^%Patch$1: $3\n%" ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+sed "/MakePatches/s/^/%patch$1 -p$4 -b $2\n/" ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+}
+
+rm -rf ~/rpmbuild/RPMS/$PACKAGE-$VERSION.*patches
+cp ~/rpmbuild/SOURCES/$PACKAGE-$VERSION $TEST/src -a
+cd $TEST/src
+for i in $WD/$PACKAGE/*patch
+do
+ file=${i//*\//}
+ number=${file//-*/}
+ log=$(patch -N -t -F$FUZZ --dry-run -p1 < $i 2>&1)
+ if [ $? = 0 ]
+ then
+ echo APPLYED PATCH: $file | tee -a ~/rpmbuild/RPMS/$PACKAGE-$VERSION.appliedpatches
+ patch -F$FUZZ -p1 < $i
+ cp $i ~/rpmbuild/SOURCES/
+ addpatch $number .$number "$file" 1
+ else
+ if echo $log |grep -q "previously applied"
+ then
+ echo ALREADY APPLIED: $file | tee -a ~/rpmbuild/RPMS/$PACKAGE-$VERSION.failedpatches
+ else
+ echo FAILED TO APPLY: $file | tee -a ~/rpmbuild/RPMS/$PACKAGE-$VERSION.failedpatches
+ fi
+ fi
+done
+cd $WD
+rm -rf $TEST
+
+# Clean tokens
+sed '/ListPatches/d; /MakePatches/d' ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec -i
+
+############################################################################
+
+grep BuildRequires ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec |sed s/.*\ //|xargs yum -y install
+rpmbuild --clean ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec
+if rpm -q glibc |grep -q armv5
+then
+ rpmbuild --target armv5tel -ba ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec
+else
+ rpmbuild -ba ~/rpmbuild/SPECS/$PACKAGE/$PACKAGE.spec
+fi
diff --git a/rpms/sugar-artwork/sugar-artwork.spec b/rpms/sugar-artwork/sugar-artwork.spec
index 5baef18..4573e74 100644
--- a/rpms/sugar-artwork/sugar-artwork.spec
+++ b/rpms/sugar-artwork/sugar-artwork.spec
@@ -4,11 +4,9 @@ Summary: Artwork for Sugar look-and-feel
Name: sugar-artwork
Epoch: 20120502
Version: 0.94.0
-Release: 2.dx3%{?dist}
+Release: dx3
URL: http://sugarlabs.org/
Source0: http://download.sugarlabs.org/sources/sucrose/glucose/%{name}/%{name}-%{version}.tar.bz2
-Source1: http://people.sugarlabs.org/~silbe/dextrose/patchsets/%{name}-dx3-20120502.tar.gz
-
License: LGPLv2+
Group: User Interface/Desktops
@@ -31,9 +29,7 @@ sugar-artwork contains the themes and icons that make up the Sugar default
look and feel.
%prep
-%setup -T -c -a 1 -n patches
-%setup -D -q
-for patch in ../patches/* ; do patch -p1 < "${patch}" ; done
+%setup -q
%build
autoreconf -i
diff --git a/rpms/sugar-toolkit/sugar-toolkit.spec b/rpms/sugar-toolkit/sugar-toolkit.spec
index a0f3c7c..4f7f562 100644
--- a/rpms/sugar-toolkit/sugar-toolkit.spec
+++ b/rpms/sugar-toolkit/sugar-toolkit.spec
@@ -3,12 +3,11 @@
Summary: Sugar toolkit
Name: sugar-toolkit
Epoch: 1
-Version: 0.94.0
+Version: 0.94.1
Release: 20120425.dx3%{?dist}
URL: http://sugarlabs.org/
Source0: http://download.sugarlabs.org/sources/sucrose/glucose/%{name}/%{name}-%{version}.tar.bz2
Source1: macros.sugar
-Source2: http://people.sugarlabs.org/~silbe/dextrose/patchsets/%{name}-dx3-20120425.tar.gz
License: LGPLv2+
Group: System Environment/Libraries
@@ -39,9 +38,7 @@ a set of widgets to build HIG compliant applications and interfaces
to interact with system services like presence and the datastore.
%prep
-%setup -T -c -a 2 -n patches
-%setup -D -q
-for patch in ../patches/* ; do patch -p1 < "${patch}" ; done
+%setup -q
%build
libtoolize
diff --git a/rpms/sugar/0000-Add-files-from-git-that-are-missing-from-tarball.patch b/rpms/sugar/0000-Add-files-from-git-that-are-missing-from-tarball.patch
deleted file mode 100644
index 91f84a8..0000000
--- a/rpms/sugar/0000-Add-files-from-git-that-are-missing-from-tarball.patch
+++ /dev/null
@@ -1,2900 +0,0 @@
-From 9d3dabd3c477e6d2939c7b2d1e10478987cd7195 Mon Sep 17 00:00:00 2001
-From: Sascha Silbe <sascha-pgp@silbe.org>
-Date: Tue, 13 Dec 2011 13:07:38 +0100
-Subject: [PATCH] Add files from git that are missing from tarball
-
-Since we're applying patches directly exported from git, we need to have all
-the files the git repository has.
-
-This patch was created using the following commands:
-
-wget -nd http://download.sugarlabs.org/sources/sucrose/glucose/sugar/sugar-0.94.1.tar.bz2
-tar -xjf sugar-0.94.1.tar.bz2
-cd sugar-0.94.1
-find * -type f | sort > ../tarball-files.lst
-cd ..
-git clone git://git.sugarlabs.org/sugar/mainline sugar
-cd sugar
-git checkout v0.94.1
-find * -type f | sort > ../git-files.lst
-comm -13 ../tarball-files.lst ../git-files.lst > ../missing-files.lst
-git diff 2cc103db83ed1550e2a9e92bf3306e4476c1297a..v0.94.1 -- $(cat ../missing-files.lst ) > ../0000-add-missing-files.patch
-git rm -f $(cat ../missing-files.lst )
-git commit -m "remove files missing from tarball"
-git apply ../0000-add-missing-files.patch
-git add -A
-git commit
----
- MAINTAINERS | 9 +
- autogen.sh | 4 +
- data/.gitignore | 2 +
- docs/GPL-C.txt | 18 +
- docs/GPL-python.txt | 16 +
- docs/LGPL-C.txt | 18 +
- docs/LGPL-python.txt | 17 +
- docs/controls.txt | 199 ++++++
- docs/design.txt | 126 ++++
- docs/release_howto.txt | 73 ++
- po/hy.po | 1764 ++++++++++++++++++++++++++++++++++++++++++++++++
- po/pseudo.po | 517 ++++++++++++++
- src/jarabe/.gitignore | 1 +
- 13 files changed, 2764 insertions(+), 0 deletions(-)
- create mode 100644 MAINTAINERS
- create mode 100755 autogen.sh
- create mode 100644 data/.gitignore
- create mode 100644 docs/GPL-C.txt
- create mode 100644 docs/GPL-python.txt
- create mode 100644 docs/LGPL-C.txt
- create mode 100644 docs/LGPL-python.txt
- create mode 100644 docs/controls.txt
- create mode 100644 docs/design.txt
- create mode 100644 docs/release_howto.txt
- create mode 100644 po/hy.po
- create mode 100644 po/pseudo.po
- create mode 100644 src/jarabe/.gitignore
-
-diff --git a/MAINTAINERS b/MAINTAINERS
-new file mode 100644
-index 0000000..9c63644
---- /dev/null
-+++ b/MAINTAINERS
-@@ -0,0 +1,9 @@
-+== Current maintainers ==
-+
-+Aleksey Lim <alsroot@member.fsf.org> -- Journal
-+Tomeu Vizoso <tomeu@sugarlabs.org>
-+
-+== Past maintainers ==
-+
-+Marco Pesenti Gritti <marcopg@sugarlabs.org>
-+
-diff --git a/autogen.sh b/autogen.sh
-new file mode 100755
-index 0000000..a71e202
---- /dev/null
-+++ b/autogen.sh
-@@ -0,0 +1,4 @@
-+#!/bin/sh
-+intltoolize
-+autoreconf -i
-+./configure --enable-maintainer-mode "$@"
-diff --git a/data/.gitignore b/data/.gitignore
-new file mode 100644
-index 0000000..8263f12
---- /dev/null
-+++ b/data/.gitignore
-@@ -0,0 +1,2 @@
-+*.gtkrc
-+sugar.schemas
-diff --git a/docs/GPL-C.txt b/docs/GPL-C.txt
-new file mode 100644
-index 0000000..aa909b4
---- /dev/null
-+++ b/docs/GPL-C.txt
-@@ -0,0 +1,18 @@
-+/*
-+ * Copyright (C) 2006, Red Hat, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * 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. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-diff --git a/docs/GPL-python.txt b/docs/GPL-python.txt
-new file mode 100644
-index 0000000..96e81d1
---- /dev/null
-+++ b/docs/GPL-python.txt
-@@ -0,0 +1,16 @@
-+# Copyright (C) 2006, Red Hat, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# 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. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software
-+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+
-diff --git a/docs/LGPL-C.txt b/docs/LGPL-C.txt
-new file mode 100644
-index 0000000..88798f8
---- /dev/null
-+++ b/docs/LGPL-C.txt
-@@ -0,0 +1,18 @@
-+/*
-+ * Copyright (C) 2006, Red Hat, Inc.
-+ *
-+ * This library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * This library 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. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the
-+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ * Boston, MA 02111-1307, USA.
-+ */
-diff --git a/docs/LGPL-python.txt b/docs/LGPL-python.txt
-new file mode 100644
-index 0000000..1db1ea4
---- /dev/null
-+++ b/docs/LGPL-python.txt
-@@ -0,0 +1,17 @@
-+# Copyright (C) 2006, Red Hat, Inc.
-+#
-+# This library is free software; you can redistribute it and/or
-+# modify it under the terms of the GNU Lesser General Public
-+# License as published by the Free Software Foundation; either
-+# version 2 of the License, or (at your option) any later version.
-+#
-+# This library 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. See the GNU
-+# Lesser General Public License for more details.
-+#
-+# You should have received a copy of the GNU Lesser General Public
-+# License along with this library; if not, write to the
-+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+# Boston, MA 02111-1307, USA.
-+
-diff --git a/docs/controls.txt b/docs/controls.txt
-new file mode 100644
-index 0000000..fa977ef
---- /dev/null
-+++ b/docs/controls.txt
-@@ -0,0 +1,199 @@
-+Colors
-+
-+Black - palettes, popups
-+Toolbar Grey #262626 - toolbars, expanded palette
-+Button Grey #808080 - buttons
-+Selection Grey #A6A6A6 - selection, expanded panels
-+Panel Grey #C0C0C0 - panel, desktop
-+Text field Grey #E5E5E5 - text field background
-+White - pressed states and multiline text areas
-+
-+States
-+
-+Default - gtk.STATE_NORMAL
-+Focused - gtk.STATE_SELECTED
-+Pressed - gtk.STATE_ACTIVE
-+Hover - gtk.STATE_PRELIGHT
-+Inactive - gtk.STATE_INSENSITIVE
-+
-+gtk.Button
-+
-+* The image should work the same of the image button
-+* Need to write a theme to match the visual style
-+* Cancel should never be default because you can always activate it with Esc
-+* Radius should be 1/2 of the control height
-+* Write a list of stock icons people should use and replace them in the theme to match our visual style
-+
-+sugar.Icon
-+
-+* Used in canvas-like views so probably an Hippo item.
-+* Svg Only.
-+* It should support xo colors easily.
-+* Rollovers with a focus mark.
-+
-+sugar.IconButton
-+
-+* Support for SVG and png.
-+* Icons should be grey scale. But might be coloured with the XO colors (svg only)
-+* Size of the button is 75 pixels, size of the icon canvas is 55 and suggested icon size is around 45.
-+* States, defaults:
-+ Hover : Black
-+ Pressed : Rounded rectangle 61 pixels, 10 pixels of radius, filled in selection grey
-+ Focused : Rounded rectangle 61 pixels, 10 pixels of radius, stroked in white 2.25 points
-+ Inactive. Fallbacks if no inactive icon is specified.
-+ Svg: Remove the fill and render the stroke in button grey
-+ Png: just do some effect on the pixbuf, which also work for grey icons
-+* You can set an icon for each states which replace the default except for the Hover state of buttons which has rollover.
-+* "palette" boolean property. If true show an arrow active immediately on click (but also on hover)
-+
-+sugar.ToolButton (support for rollovers)
-+
-+* Contains IconButton
-+* There is no palette but a tooltip.
-+* Normal: Button grey rounded filled rectangle
-+* Inactive: Button grey rounded stroked rectangle
-+
-+sugar.ToggleIconButton
-+
-+* Toggled should be like Pressed
-+* Inconsistent should be the same of Default (the action depend on the cases)
-+* Pressed state and Toggled state is Selection grey
-+
-+sugar.ToolIconButton
-+
-+* Contains a ToggleIconButton
-+
-+gtk.CheckButton
-+
-+* Match the visual design, shoul be possible with just theme changes
-+
-+gtk.RadioButton
-+
-+* Exactly like CheckButton just a different indicator
-+
-+gtk.OptionMenu
-+
-+* Match the visual style. Hopefully only theme changes.
-+* Add the scroll thing.
-+* Groups. Either by a normal separator or a titled separator.
-+* Optional support for showing just the icon from the menu (maybe, low priority)
-+* Allow fixed sizing of the "button" and ellipsize the label
-+
-+sugar.Entry
-+
-+* Support for packing icons before and after the entry. Extend gtk.Entry.
-+* Activate/Cancel functionality.
-+ Two buttons at the end to the entry and key bindings (Esc and Enter). They are visible only when there are changes.
-+ The icons appear only when the field is focused and the content is changed since it gained focus.
-+ When hitting escape revert and select all the text.
-+
-+gtk.ComboxBox
-+
-+* We miss accept/cancel functionality. Probably patch gtk to allow to replace the entry in the combo box with sugar.Entry.
-+
-+sugar.SearchEntry
-+
-+* Use sugar.Entry
-+* Search button on the left. Clicking should focus the entry.
-+* Cancel button (Esc) on the right, always visible when there is text in the entry. Clicking it will clear the text and focus the textfield.
-+* Activate button (Enter) on the right displayed when the content of the text field changed from the last focus or activation.
-+* While activating:
-+ the Activate button becomes a Spinner.
-+ clicking the close button also cancel the search.
-+* When activation is completed:
-+ The spinner goes away.
-+ We *don't* clear the entry but we select the text.
-+* Search can either be incremental or on activation. For incremental there is no Accept button. start_spinning and stop_spinning to control the spin icon. start would only spin for an amount of time decided by the widget itself (and documented).
-+* The suggestions list is provided by the application. Need to figure out which api to use, either model or signal based.
-+* Default implementation of suggestions which automatically save the latest searches.
-+
-+sugar.DateSelector
-+sugar.DateComboBox (lower priority)
-+
-+* Pluggable calendar implementation to support different kind of calendars (localization).
-+* Might reuse gtk.Calendar. We should unify month/year selectors and accellerate the movement gradually.
-+
-+gtk.SpinButton
-+
-+* Make it match the visual design, hopefully just theme changes
-+
-+sugar.ToolItem
-+
-+* Optional label, either text or icon
-+* Used for example to have a label near a SpinButton. Clicking on the label should focus the spin button.
-+
-+gtk.ProgressBar
-+
-+* Make it match the visual design, hopefully just theme changes.
-+* For determinate progress bars should we always pulse to show that there is activity (power consumption? necessary feedback?)
-+* Do not use text inside the progress bar
-+
-+sugar.Spinner
-+
-+* pulse() call to keep it running with a timeout
-+* stop()
-+
-+gtk.Range (or sugar.Slider?)
-+
-+* Property to show the fill in white color, probably default on.
-+* Draw the discrete steps.
-+* For colored sliders, subclass gtk.Range and add a gradient.
-+
-+sugar.LevelIndicator
-+
-+* Set the number of blocks
-+* Set the level as percentage
-+* Property for discrete or not
-+* We can probably use a GtkAdjustment for most of the above.Rollovers
-+
-+
-+gtk.TextView
-+
-+gtk.ScrolledWindow
-+
-+* Theme it to match the visual.
-+
-+sugar.ScrolledWindow
-+
-+* Support for markers. Line as default and optional support for other shapes (star for bookmarks, circles for xos...). Generic way of add marks and keep them updated (observer?)
-+
-+gtk.Expander
-+
-+gtk.Separator
-+
-+sugar.GroupBox
-+
-+* just a container
-+* set_title and set_title_widget (checkbox, radiobutton...)
-+* different color and separator under title
-+
-+gtk.TreeView
-+
-+gtk.Notebook
-+
-+* Expand to fill the whole space by default but property to turn it off
-+* Switching tabs with the little arrows should page
-+
-+Palettes in ToolIconButton, IconButton
-+* Inmediately on rollover, show the black background.
-+* After a very short delay, show the primary state (name of the action and key shortcut).
-+* After a bigger delay, show the popup secondary state.
-+* Could be animated.
-+* Menu Items would go on the top and then the free-form rollover content.
-+* The popup would be a gtk.Window that contains a Label, a MenuShell, an hippo.Canvas (or whatever) and finally a button bar (OK/Cancel).
-+* The popup will have a setPrimaryState(label, accelerator) method. For action buttons would be a MenuItem, for the others would only be a Label.
-+* The primary state should already have the same width as the secondary state and the expandable areas.
-+* Primary states appear and disappear automatically (with a short delay). A click outside makes it disappear instantly.
-+* Secondary states appear after a delay, or with a single click on the icon.
-+* Secondary disappears with the esc key, clicking outside the popup or clicking on a button inside.
-+
-+Toolbox
-+* When an activity opens, the activity tab should be opened and the focus on the activity title.
-+* We must provide an activity tab in the toolbox and would be good to also provide an standard Edit tab.
-+
-+Grab key
-+* We probably will need the grab mode.
-+* Highlight the scrollbar in the view the pointer is (the view that will scroll when moving the pointer).
-+
-+Clipboard
-+* Window manager to handle in an invisible window in every corner and forward the events when they are not in the corner, or use XEvIE (X Event Interception Extension).
-diff --git a/docs/design.txt b/docs/design.txt
-new file mode 100644
-index 0000000..37061af
---- /dev/null
-+++ b/docs/design.txt
-@@ -0,0 +1,126 @@
-+= Frame =
-+
-+== Activation and deactivation ==
-+
-+* Immediately access the frame by hitting any corner pixel (the exact corner point)
-+* Hitting any of the screen edges activate the frame after 0.5s delay
-+* Pressing and holding the frame key activate the frame until the key is released.
-+* Pressing the frame key momentarily toggle the frame. To deactivate it another key press is necessary.
-+
-+= IRC logs =
-+
-+Frame
-+
-+eliason marcopg: First, you can immediately access the frame by hitting any corner pixel.
-+dcbw marcopg: I think that's the issue, yes
-+eliason Second, you can activate it from any edge, but there is a half second delay. In addition to the delay, the timer on the delay only ticks when the mouse is on an edge pixel and also below some threshold velocity, so if the mouse is moving it will not show up.
-+eliason marcopg: Third, there will be a frame key. Pressing and holding this key will invoke the frame until the key is released. Pressing this key momentarily, however, will toggle the frame and keep it in view until the key is pressed again.
-+eliason marcopg: All of these things are implemented in Flash (The frame key is 8, I think...), with the exception of the mouse velocity threshold on the edges.
-+eliason marcopg: The only other minor usability issue I could see is adding a hit area in the corners. That is, once the frame is out, have an invisible triangle in each corner that is still considered part of the frame, so that rolling out of the frame to get from one edge to another doesn't hide the frame, by accident. In fact, doing this would make the delay on hide unnecessary.
-+eliason marcopg: Oh, and other important edges case to think about on the frame: 1) When someone is dragginan object (XO, file, image, etc) the frame should come out prematurely and without delay (maybe once within a large grid cell of the edge) and highlight to indicate where the object could be dropped. 2) When the search field is active, the frame should remain out even if the mouse isn't over it. Only when the search is cleared should it hide again.
-+eliason marcopg: The rollover states are as follows: 1) Immediate rollover is a black square in the frame cell itself. 2) Very shortly thereafter (about 1/4 sec) Is the Primary information label and 3) a bit longer after that (about 1/2 sec) the extended panel appears with additional info.
-+
-+Menu
-+
-+eliason marcopg: Deactivation is instantaneous at the moment, but again, based on testing with the software we may want to add a very short delay. Also, we may want again to have a invisible triangles between the grid cell in the frame and the extended panel.
-+eliason Delay between mouse rollover and showing black square: 0
-+eliason Delay before primary info animation begins: 1/10 sec
-+eliason Duration of primary info extension animation: 1/5 sec
-+eliason Delay from end of primary info animation until secondary info: 1/2 sec
-+Duration of secondary info animation: 1/5 sec
-+
-+Text layout
-+
-+eliason marcopg: Well, first of all, in the latest screens which we haven't sent out yet, the primary info rollover is designed to fit the text to the nearest microgrid, regardless of the size of the secondary info panel. The second animation segment will both extend the width and height to fit.
-+eliason marcopg: As far as cutoff goes, I think that's a reasonable solution. We should allow the primary info text to be as long as the secondary info panel, and beyond that an ellipsis would be a good way to go, though hopefully designers are strongly encouraged NOT to let that happen.
-+eliason marcopg: However, there may be cases when we don't want that to happen. I can think of one, which you haven't seen yet: "Invite with X X X X X." The new activity/invite rollover might have the XOs who you are implicitly inviting to start an activity with listed, and we couldn't cut that off (Though we CANget around it and list, say, a max of three people and then indicate that there are 5 more not shown, etc.)
-+eliason marcopg: Right. I think that, in most cases, there should be some template for it. If the designer is creating a GUI for an application and making toolsets (such as the color chooser), then we know how big all of those are. Things like "just text" will mostly show up in OS applications like the clippings and such, so we can just pick a preferred size that shows enough text to be meaningful without compromising too much of the screen.
-+
-+Mesh view
-+
-+eliason marcopg: also important regarding the results: the fill color should be the background color, so they look like outlines, and the line color should be near enough to the background to make them less contrasty. Also, all XOs in the result set should be z-sorted to the front of their groups. That's key.
-+eliason marcopg: The activity icons and XOs are treated separately, so it may be the case that several XOs in a group match the search but the activity their in doesn't, and they would be grayed out independently.
-+eliason marcopg: yes, only the color change. Colored stuff is the result. We don't want to actually make things disappear.
-+
-+
-+Mesh discussion
-+
-+eliason marcopg: Well, the terminology we're now using for the zoom level labels is: My Activities, My Friends, My Neighbors.
-+eliason marcopg: Alright, true, so the working terminology (not the labels for the search field, but still used by all of us) is: home, friends, mesh
-+eliason marcopg: If you treat each frieeliason marcopg: If you treat each friend or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly.nd or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly.
-+eliason marcopg: If you treat each friend or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly.
-+eliason marcopg: There's lots of info on this type of thing online. To do it right within a given box, you also have to add anchored springs at the corners and such to stretch the whole thing out to fill the space.
-+eliason OK, so another basic idea is to keep a very rough downsampled grayscale image around....
-+eliason The grayscale value would map to the number of XOs within the grid cell on screen.
-+eliason marcopg: Then, when placing a new one you could just find the best place to place it , though now that I think about it that would probably require a simulated annealing algorithm or something else clever to do...
-+marcopg eliason, do you mean macro cell here?
-+marcopg i.e. every buddy would be placed in one macro cell
-+eliason marcopg: Well, actually I guess you'd kind of want a blurred brayscale image, where each object placed represents a white circle, but with a gaussian blur so that it acts like a topographic map of the mesh.
-+eliason marcopg: The white spots would be dense, like hills, the black spots would be void of people, like holes. Then to place a new one, you kind of roll a simulated marble around until you find a good hole to place it in...
-+eliason marcopg: And, yet another idea, which could be used in conjunction with or independent of the above. You could simply place a small repulsive force between the objects, so that they push each other apart slightly. You could just place at random and have them adjust accordingly. This works very much like the spring model, though.
-+eliason Of course, the drawback of the third idea is that it's n^2 in the number of groups on the mesh, but that number should never be that large.
-+eliason The spring model is a little more complicated, but you only have to place springs between nearby objects, which reduces that somewhat.
-+eliason marcopg: But actually, I think #3 might be the easiest to implement, and work just as well. It works nicely since it could still allow you to drag them around and the rest of the mesh would react naturally. In the spring model, you'd have to dynamically add and break spring connections when a node is moved around.
-+marcopg eliason, mm was just thinking about this would interact with custom placed nodes...
-+marcopg eliason, I never done something similar before so I will really need to play a bit with it...
-+eliason marcopg: Also, #3 is more forgiving: In the spring model, placing one new node will move EVERY node in the mesh somewhat, if even just a small amount, since the whole system adjusts. With the repulsion force, only nearby nodes would be affected, except of course through a chain reaction...
-+eliason marcopg: I'm sure we can find documentation. Basically, you calculate the distance between the two nodes (pythag) and if that distance is less than some threshold you compute the angle between them (atan2) and then you give each one a small repulsive acceleration, and update each frame by treating each with its own acceleration, velocity, and position.
-+eliason marcopg: radiusConstant + (numXos*radiusScale) + ((index%3)*offsetScale) <-- that gets pretty close to what I'm working with now.
-+eliason marcopg: One addition: When the groups are small, we don't want to add the snowflake effect, since they fit in neat geometric shapes around the ring. So we get....actually, here's the ugly line of code: radius = 25 + .3*(Math.max(participants.length-10,0)) + (i%3)*.5*(Math.max(participants.length-10,0));
-+eliason marcopg: The added ugliness is a bit of code that zeros out the 2nd two quantities if there are less than 10 people in the group. You could just place them in an if block actually, but I'd done it this way in case I wanted to change the thresholds independently...eliason marcopg: The added ugliness is a bit of code that zeros out the 2nd two quantities if there are less than 10 people in the group. You could just place them in an if block actually, but I'd done it this way in case I wanted to change the thresholds independently...
-+eliason marcopg: OK, cool. The animation is a simple easing algorithm: position += (targetPostition - position)*percentage.
-+eliason marcopg: Well, that's a function of the radius and the angle computed from above. targetX = radius*cos(angle), targetY = radius*sin(angle), for each XO.
-+marcopg eliason, aaah I see now
-+
-+eliason marcopg: The basic problem is that people are crossing an index that is a multiple of the mod, so everyone shifts in and out. What if, instead, we adjusted the indeces of every XO with an index of modValue*c greater than the XO that left, and subtract modValue from each of their indices?
-+eliason With mod 3, we basically have 3 levels of the ring. This solution would just shift ONE of those rings couter-clockwise one XO position, leaving the other two rings intact as is. We move many fewer XOs than before, but we minimize the movement any given XO has to make by spreading it across the ring level instead of moving the last XO all the way across the circle...eliason marcopg: The basic problem is that people are crossing an index that is a multiple of the mod, so everyone shifts in and out. What if, instead, we adjusted the indeces of every XO with an index of modValue*c greater than the XO that left, and subtract modValue from each of their indices?
-+eliason With mod 3, we basically have 3 levels of the ring. This solution would just shift ONE of those rings couter-clockwise one XO position, leaving the other two rings intact as is. We move many fewer XOs than before, but we minimize the movement any given XO has to make by spreading it across the ring level instead of moving the last XO all the way across the circle...
-+eliason marcopg: The final detail of that, beyond shifting each index down by the mod value, is to shift the very last group of people in the ring down to fill all the holes, if you get my meaning...
-+
-+Activity startup feedback
-+
-+I agree we certainly need feedback for this sort of thing. For
-+starters, the icon of the selected activity should immediately appear
-+in the ring. Perhaps we can apply some small animation to this
-+activity icon to indicate that it is starting up. Marco, could you
-+use HSV for the icon color, and modulate the S(aturation) on a sin
-+curve so the color pulses betwen, say, 0 and 192 until the activity
-+starts, at which point it slides up to 255?
-+
-+Clipboard
-+
-+<marcopg> eliason, when should the frame be automatically showed? when
-+starting the drag or when hitting the corner
-+<marcopg> eliason, (the first one would be tricky to implement)
-+<eliason> marcopg: Initially we wanted it to happen on drag, but after
-+thinking about this more, it's a bad idea, since it would hide the toolbars,
-+and some activities may have toolbars that support drag and drop also. As
-+such, we probably just keep the hot corners as is, and perhaps implement the
-+"warm edges" too, but only when dragging...
-+<marcopg> eliason, which reminds me... the plan is to completely drop edges at
-+this point? or at least give it a try? (for the not dragging case)
-+<eliason> I still think it's worth trying, but I think the general consensus
-+was that we should drop it. That's also the easier option, so for now, I
-+guess it's fine.
-+<marcopg> ok
-+<marcopg> eliason, what should be the title of the clipboard rollover? (we are
-+trying to get text objects right for now, but if you have general ideas...)
-+<eliason> marcopg: Well, it would depend on what is in the clipboard. For
-+instance, if I copy some text, it should say "text clipping", or if I copy an
-+image it should say "picture clipping"
-+<marcopg> eliason, so [name of the object] + clipping?
-+<eliason> marcopg: If it is an activity object, it should be the name of the
-+object i.e. "Eben's Shark Drawing", etc.
-+<marcopg> oh ok
-+<eliason> It's only a clipping if it is part of another larger context.
-+<eliason> If the whole thing is an object itself, we use the object's name.
-+<marcopg> eliason, I see now
-+<marcopg> eliason, we want a preview of the objectm right? For text, should we
-+show part of the text in the rollover?
-+<eliason> marcopg: yeah, probably the first n characters of it, with an
-+ellipsis at the end.
-+<marcopg> eliason, on multiple lines I guess?
-+<marcopg> something like, 4 lines of text on a 2 grid cells large menu, and
-+ellipsize after that
-+<marcopg> (the exact numbers doesn't matter, just the logic
-+<eliason> marcopg: Right.
-diff --git a/docs/release_howto.txt b/docs/release_howto.txt
-new file mode 100644
-index 0000000..841809a
---- /dev/null
-+++ b/docs/release_howto.txt
-@@ -0,0 +1,73 @@
-+""" This is the release process of the sugar tarballs sugar(shell),
-+sugar-toolkit and sugar-base described in a pytish way and
-+instructions for sugar packagers
-+"""
-+
-+# Release sugar tarballs
-+
-+for package in [sugar, sugar-toolkit, sugar-base, sugar-artwork]:
-+ # Release a new version in git
-+ Pull the latest sources.
-+ Increase the version number in configure.ac
-+ # this will create you a tarball and does a check if it builds fine
-+ # e.g. it will check if all the files containing translations are
-+ # in po/POTFILES.in
-+ make distcheck
-+
-+ if that succeed:
-+ # commit the change, log it as "Release [version_number]" (e.g. 0.79.1)
-+ git commit -a
-+ # Tag the release:
-+ git tag v[version_number]
-+ # Then push both the tag and the change:
-+ git push --tags
-+ git push
-+ else:
-+ break
-+
-+ # Upload the package
-+ Upload the tarball to
-+ shell.sugarlabs.org:/pub/sugarlabs/sources/sucrose/glucose/$name/$name-$version
-+
-+ # Verify the upload of the package
-+ Check that the package has been uploaded fine: \
-+ http://download.sugarlabs.org/sources/sucrose/glucose/$name/$name-$version
-+
-+# Package sugar for Fedora
-+# - For announcements of the Sucrose release subscribe at the sugar-devel
-+# mailing list; you can filter for the [ANNOUNCE] tag
-+# - Uploaded tarballs can be found at:
-+# glucose: http://download.sugarlabs.org/sources/sucrose/glucose/$name/$name-$version
-+# fructose: http://download.sugarlabs.org/sources/sucrose/fructose/$name/$name-$version
-+# more about the taxonomy: http://sugarlabs.org/go/Taxonomy
-+
-+# more info on fedora packaging:
-+# http://fedoraproject.org/wiki/PackageMaintainers/UpdatingPackageHowTo
-+# request permissions to contribute to the fedora package:
-+# https://admin.fedoraproject.org/pkgdb/packages/name/[package]
-+
-+if not cvs_package:
-+ # Get sugar from fedora cvs:
-+ CVSROOT=:ext:erikos@cvs.fedoraproject.org:/cvs/pkgs cvs co [package]
-+ cd cvs_package
-+else:
-+ cd cvs_package
-+ cvs update
-+
-+cd current release
-+make new-sources FILES="[tarball-created-with-make_distcheck]"
-+
-+# Change the version in the spec
-+Bump the release number
-+Edit the Changelog
-+# verify your changes
-+cvs diff -u
-+make srpm
-+
-+make clog
-+cvs commit -F clog
-+
-+make tag
-+make build
-+
-+# Do the same for the other branches e.g. devel
-diff --git a/po/hy.po b/po/hy.po
-new file mode 100644
-index 0000000..9ee2940
---- /dev/null
-+++ b/po/hy.po
-@@ -0,0 +1,1764 @@
-+# SOME DESCRIPTIVE TITLE.
-+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-+# This file is distributed under the same license as the PACKAGE package.
-+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-+#, fuzzy
-+msgid ""
-+msgstr ""
-+"Project-Id-Version: PACKAGE VERSION\n"
-+"Report-Msgid-Bugs-To: \n"
-+"POT-Creation-Date: 2011-09-23 11:55-0400\n"
-+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-+"Language-Team: LANGUAGE <LL@li.org>\n"
-+"MIME-Version: 1.0\n"
-+"Content-Type: text/plain; charset=UTF-8\n"
-+"Content-Transfer-Encoding: 8bit\n"
-+"X-Generator: Translate Toolkit 1.7.0\n"
-+
-+#: ../extensions/cpsection/aboutme/__init__.py:24
-+msgid "About Me"
-+msgstr "իմ մասին"
-+
-+#: ../extensions/cpsection/aboutme/model.py:48
-+msgid "You must enter a name."
-+msgstr "Դուք պետ է մուտքագրեք անուն:"
-+
-+#: ../extensions/cpsection/aboutme/model.py:75
-+#, python-format
-+msgid "stroke: color=%s hue=%s"
-+msgstr "գիծ. գույն=%s երանգ=%s"
-+
-+#: ../extensions/cpsection/aboutme/model.py:78
-+#, python-format
-+msgid "stroke: %s"
-+msgstr "գիծ. %s"
-+
-+#: ../extensions/cpsection/aboutme/model.py:80
-+#, python-format
-+msgid "fill: color=%s hue=%s"
-+msgstr "լցնել. գույն=%s երանգ=%s"
-+
-+#: ../extensions/cpsection/aboutme/model.py:82
-+#, python-format
-+msgid "fill: %s"
-+msgstr "լցնել. %s"
-+
-+#: ../extensions/cpsection/aboutme/model.py:94
-+msgid "Error in specified color modifiers."
-+msgstr "Վրիպում գույնի ընտրված ցուցիչներում:"
-+
-+#: ../extensions/cpsection/aboutme/model.py:97
-+msgid "Error in specified colors."
-+msgstr "Ընտրված գույների վրիպում:"
-+
-+#: ../extensions/cpsection/aboutme/view.py:235
-+msgid "Click to change your color:"
-+msgstr "Քլիք գույնը փոփոխելու համար."
-+
-+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
-+msgid "About my Computer"
-+msgstr "Իմ Համակարգչի մասին"
-+
-+#: ../extensions/cpsection/aboutcomputer/model.py:42
-+msgid "Not available"
-+msgstr "Մատչելի չէ"
-+
-+#: ../extensions/cpsection/aboutcomputer/model.py:171
-+#, python-format
-+msgid "%(interface)s: %(version)s"
-+msgstr "%(interface)s: %(version)s"
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:61
-+msgid "Identity"
-+msgstr "Ինքնություն"
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:70
-+msgid "Serial Number:"
-+msgstr "Շարքյին Համար."
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:92
-+msgid "Software"
-+msgstr "Ծրագրային մատակարարում"
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:101
-+msgid "Build:"
-+msgstr "Կառուցել."
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:116
-+msgid "Sugar:"
-+msgstr "Sugar."
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:132
-+msgid "Firmware:"
-+msgstr "Ծրագրաշար."
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:147
-+msgid "Wireless Firmware:"
-+msgstr "Անլար Ծրագրաշար."
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:170
-+msgid "Copyright and License"
-+msgstr "Հեղինակային իրավունք և Արտոնագիր"
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:188
-+msgid ""
-+"Sugar is the graphical user interface that you are looking at. Sugar is free "
-+"software, covered by the GNU General Public License, and you are welcome to "
-+"change it and/or distribute copies of it under certain conditions described "
-+"therein."
-+msgstr ""
-+"Sugar-ը օգտվողի հետ հաղորդակցող այն գծագրային ծրագիրն է, որ դուք տեսում եք: "
-+"Sugar-ը անվճար ծրագիր է և կարգավորվում է GNU General Public արտոնագրով: Դուք "
-+"կարող եք օգտագործել և տարածել այն որոշակի ներքոշյալ պայմանների ներքո:"
-+
-+#: ../extensions/cpsection/aboutcomputer/view.py:200
-+msgid "Full license:"
-+msgstr "Ամբողջական Արտոնագիր."
-+
-+#: ../extensions/cpsection/datetime/__init__.py:21
-+msgid "Date & Time"
-+msgstr "Ամսաթիվը և ժամը"
-+
-+#: ../extensions/cpsection/datetime/model.py:92
-+msgid "Error timezone does not exist."
-+msgstr "Վրիպում` ժամանակային գոտին գոյություն չունի:"
-+
-+#: ../extensions/cpsection/datetime/view.py:70 ../data/sugar.schemas.in.h:52
-+msgid "Timezone"
-+msgstr "ժամանակային գոտի"
-+
-+#: ../extensions/cpsection/frame/__init__.py:21
-+msgid "Frame"
-+msgstr "Շրջանակ"
-+
-+#: ../extensions/cpsection/frame/model.py:41
-+#: ../extensions/cpsection/frame/model.py:66
-+msgid "Value must be an integer."
-+msgstr "Առժեքը պետք է տրվի ամբողջ թվով:"
-+
-+#: ../extensions/cpsection/frame/view.py:27
-+msgid "never"
-+msgstr "երբեք"
-+
-+#: ../extensions/cpsection/frame/view.py:28
-+msgid "instantaneous"
-+msgstr "ակնթարթային"
-+
-+#: ../extensions/cpsection/frame/view.py:29
-+#, python-format
-+msgid "%s seconds"
-+msgstr "%s վարկյան"
-+
-+#: ../extensions/cpsection/frame/view.py:54
-+msgid "Activation Delay"
-+msgstr "Ակտիվացման Հետաձգում"
-+
-+#: ../extensions/cpsection/frame/view.py:78
-+msgid "Corner"
-+msgstr "Անկույն"
-+
-+#: ../extensions/cpsection/frame/view.py:113
-+msgid "Edge"
-+msgstr "Կող"
-+
-+#: ../extensions/cpsection/keyboard/__init__.py:21
-+#: ../extensions/cpsection/keyboard/view.py:32
-+msgid "Keyboard"
-+msgstr "Ստեղնաշար"
-+
-+#: ../extensions/cpsection/keyboard/view.py:190
-+msgid "Keyboard Model"
-+msgstr "Ստեղնաշարի Մոդել"
-+
-+#: ../extensions/cpsection/keyboard/view.py:250
-+msgid "Key(s) to change layout"
-+msgstr "Դասավորությունը փոփոխման ծածքաբառեր"
-+
-+#: ../extensions/cpsection/keyboard/view.py:319
-+msgid "Keyboard Layout(s)"
-+msgstr "Ստեղնաշարի Դասավորություն"
-+
-+#: ../extensions/cpsection/language/__init__.py:21
-+#: ../extensions/cpsection/language/view.py:33
-+msgid "Language"
-+msgstr "Լեզու"
-+
-+#: ../extensions/cpsection/language/model.py:30
-+msgid "Could not access ~/.i18n. Create standard settings."
-+msgstr "Հնարավոր չէ մուտք գործել ~/.i18n. Ստեղծել ստանդարտ կարգավորումներ:"
-+
-+#: ../extensions/cpsection/language/model.py:129
-+#, python-format
-+msgid "Language for code=%s could not be determined."
-+msgstr "Ծածկագրի լեզուն code=%s չի կարող որոշվել:"
-+
-+#: ../extensions/cpsection/language/model.py:152
-+#, python-format
-+msgid "Sorry I do not speak '%s'."
-+msgstr "Ներողություն, ես չեմ խոսում '%s':"
-+
-+#: ../extensions/cpsection/language/view.py:57
-+msgid ""
-+"Add languages in the order you prefer. If a translation is not available, "
-+"the next in the list will be used."
-+msgstr ""
-+"Ավելացրեք լեզուները ձեր նախընտրած հաջորդականությամբ: Եթե թարգմանությունը "
-+"մատչելի չէ, կօգտագործվի ցուցակով հաջյորդը:"
-+
-+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
-+msgid "Modem Configuration"
-+msgstr "Մոդեմի կազմաձևումը"
-+
-+#: ../extensions/cpsection/modemconfiguration/view.py:94
-+msgid "Username:"
-+msgstr "Մականուն."
-+
-+#: ../extensions/cpsection/modemconfiguration/view.py:106
-+msgid "Password:"
-+msgstr "Գաղտնաբառ."
-+
-+#: ../extensions/cpsection/modemconfiguration/view.py:118
-+msgid "Number:"
-+msgstr "Համար."
-+
-+#: ../extensions/cpsection/modemconfiguration/view.py:130
-+msgid "Access Point Name (APN):"
-+msgstr "Միացման Կետի Անունը (APN)."
-+
-+#: ../extensions/cpsection/modemconfiguration/view.py:142
-+msgid "Personal Identity Number (PIN):"
-+msgstr "Անձնական Անհատական Համար (PIN)."
-+
-+#: ../extensions/cpsection/modemconfiguration/view.py:154
-+msgid "Personal Unblocking Key (PUK):"
-+msgstr "Անձնական Արգելափակման բացման Գաղտնաբառ (PUK)."
-+
-+#: ../extensions/cpsection/modemconfiguration/view.py:175
-+msgid ""
-+"You will need to provide the following information to set up a mobile "
-+"broadband connection to a cellular (3G) network."
-+msgstr ""
-+"Շարժական լայնաշերտ բջջային (3G) ցանցին միանալու համար ձեզ անհրաժեշտ է "
-+"տրամադրել հետևյալ տեղեկությունները`:"
-+
-+#: ../extensions/cpsection/network/__init__.py:21
-+#: ../extensions/cpsection/network/view.py:29
-+msgid "Network"
-+msgstr "Ցանց"
-+
-+#: ../extensions/cpsection/network/model.py:71
-+msgid "State is unknown."
-+msgstr "Կարգավիճակն անհայտ է:"
-+
-+#: ../extensions/cpsection/network/model.py:99
-+msgid "Error in specified radio argument use on/off."
-+msgstr "Վրիպում ընտրված ռադիո տիրույթում` օգտագործել on/off:"
-+
-+#: ../extensions/cpsection/network/model.py:140
-+msgid "Error in specified argument use 0/1."
-+msgstr "Վրիպում ընտրված տիրույթում` օգտագործել 0/1:"
-+
-+#: ../extensions/cpsection/network/view.py:61
-+msgid "Wireless"
-+msgstr "Անլար"
-+
-+#: ../extensions/cpsection/network/view.py:69
-+msgid "Turn off the wireless radio to save battery life"
-+msgstr "Անջատել անլար ռադիո սարքերը մարտկոցի հզորությունը տնտեսելու համար"
-+
-+#: ../extensions/cpsection/network/view.py:82
-+msgid "Radio"
-+msgstr "Ռադիո"
-+
-+#: ../extensions/cpsection/network/view.py:98
-+msgid "Discard network history if you have trouble connecting to the network"
-+msgstr "Ջնջել ցանցին միացման պատմությունը միացման խնդիրների ծագման դեպքում"
-+
-+#: ../extensions/cpsection/network/view.py:107
-+msgid "Discard network history"
-+msgstr "Ջնջել ցանցին միացման պատմությունը"
-+
-+#: ../extensions/cpsection/network/view.py:122
-+msgid "Collaboration"
-+msgstr "Համագործակցություն"
-+
-+#: ../extensions/cpsection/network/view.py:130
-+msgid ""
-+"The server is the equivalent of what room you are in; people on the same "
-+"server will be able to see each other, even when they aren't on the same "
-+"network."
-+msgstr ""
-+"Սերվերը համառժեք է բոլոր օգտվողների համար անկախ նրանց իրական գտնվելու "
-+"վայրից: Օգտվողները կարող են տեսնել միմյանց, նույնիսկ եթե նրանք նույն ցանցում "
-+"չեն:"
-+
-+#: ../extensions/cpsection/network/view.py:140
-+msgid "Server:"
-+msgstr "Սերվեր."
-+
-+#: ../extensions/cpsection/power/__init__.py:21
-+msgid "Power"
-+msgstr "Սնուցում"
-+
-+#: ../extensions/cpsection/power/model.py:90
-+msgid "Error in automatic pm argument, use on/off."
-+msgstr "Վրիպում ավտոմատիկ pm տիրույթում՝ օգտագործել on/off:"
-+
-+#: ../extensions/cpsection/power/model.py:120
-+msgid "Error in extreme pm argument, use on/off."
-+msgstr "Վրիպում արտակարգ pm տիրույթում՝ օգտագործել on/off:"
-+
-+#: ../extensions/cpsection/power/view.py:48
-+msgid "Power management"
-+msgstr "Սնուցման կառավարում"
-+
-+#: ../extensions/cpsection/power/view.py:58
-+msgid "Automatic power management (increases battery life)"
-+msgstr ""
-+"Ավտոմատ սնուցման կառավարում (Երկարացնում է մարտկոցի կյանքի տևողությունը)"
-+
-+#: ../extensions/cpsection/power/view.py:86
-+msgid ""
-+"Extreme power management (disables wireless radio, increases battery life)"
-+msgstr ""
-+
-+#: ../extensions/cpsection/updater/__init__.py:21
-+msgid "Software update"
-+msgstr "Ծրագրային արդիականացում"
-+
-+#: ../extensions/cpsection/updater/view.py:63
-+msgid ""
-+"Software updates correct errors, eliminate security vulnerabilities, and "
-+"provide new features."
-+msgstr ""
-+"Ծրագրային արդիականացումն ուղղում է վրիպումները, վերացնում է խոցելի "
-+"հատվածները և ընդձեռում նոր հնարավորութուններ"
-+
-+#: ../extensions/cpsection/updater/view.py:125
-+#, python-format
-+msgid "Checking %s..."
-+msgstr "Ստուգում %s..."
-+
-+#: ../extensions/cpsection/updater/view.py:127
-+#, python-format
-+msgid "Downloading %s..."
-+msgstr "Բեռնում %s..."
-+
-+#: ../extensions/cpsection/updater/view.py:129
-+#, python-format
-+msgid "Updating %s..."
-+msgstr "Արդիականացում %s..."
-+
-+#: ../extensions/cpsection/updater/view.py:139
-+msgid "Your software is up-to-date"
-+msgstr "Ձեր ծրագրերը արդիականացված են"
-+
-+#: ../extensions/cpsection/updater/view.py:141
-+#, python-format
-+msgid "You can install %s update"
-+msgid_plural "You can install %s updates"
-+msgstr[0] "Դուք կարող եք տեղադրել %s արդիականացումը"
-+msgstr[1] ""
-+
-+#: ../extensions/cpsection/updater/view.py:159
-+msgid "Checking for updates..."
-+msgstr "Արդիականացումների որոնում..."
-+
-+#: ../extensions/cpsection/updater/view.py:164
-+msgid "Installing updates..."
-+msgstr "Արդիականացումների տեղադրում"
-+
-+#: ../extensions/cpsection/updater/view.py:173
-+#, python-format
-+msgid "%s update was installed"
-+msgid_plural "%s updates were installed"
-+msgstr[0] "Արդիականացումների %s տեղադրված է"
-+msgstr[1] ""
-+
-+#: ../extensions/cpsection/updater/view.py:255
-+msgid "Install selected"
-+msgstr "Տեղադրել ըտրածը"
-+
-+#: ../extensions/cpsection/updater/view.py:276
-+#, python-format
-+msgid "Download size: %s"
-+msgstr "Բեռնման չափսը. %s"
-+
-+#: ../extensions/cpsection/updater/view.py:364
-+#, python-format
-+msgid "From version %(current)s to %(new)s (Size: %(size)s)"
-+msgstr "Ընթացիկ տարբերակից %(current)s դեպի նորը %(new)s (Չափս. %(size)s)"
-+
-+#. TRANS: download size is 0
-+#: ../extensions/cpsection/updater/view.py:382
-+msgid "None"
-+msgstr "Ոչինչ"
-+
-+#. TRANS: download size of very small updates
-+#: ../extensions/cpsection/updater/view.py:385
-+msgid "1 KB"
-+msgstr "1 KB"
-+
-+#. TRANS: download size of small updates, e.g. '250 KB'
-+#: ../extensions/cpsection/updater/view.py:388
-+#, python-format
-+msgid "%.0f KB"
-+msgstr "%.0f KB"
-+
-+#. TRANS: download size of updates, e.g. '2.3 MB'
-+#: ../extensions/cpsection/updater/view.py:391
-+#, python-format
-+msgid "%.1f MB"
-+msgstr "%.1f MB"
-+
-+#: ../extensions/deviceicon/battery.py:71
-+msgid "My Battery"
-+msgstr "իմ Մարտկոցը"
-+
-+#: ../extensions/deviceicon/battery.py:147
-+msgid "Removed"
-+msgstr "Հեռացված"
-+
-+#: ../extensions/deviceicon/battery.py:150
-+msgid "Charging"
-+msgstr "Լիցքավորում"
-+
-+#: ../extensions/deviceicon/battery.py:153
-+msgid "Very little power remaining"
-+msgstr "Մնացել է չափազանց պոքր հզորություն"
-+
-+#: ../extensions/deviceicon/battery.py:158
-+#, python-format
-+msgid "%(hour)d:%(min).2d remaining"
-+msgstr "մնացել է. %(hour)d:%(min).2d"
-+
-+#: ../extensions/deviceicon/battery.py:161
-+msgid "Charged"
-+msgstr "Լիցքվորոած է"
-+
-+#: ../extensions/deviceicon/network.py:49
-+#, python-format
-+msgid "IP address: %s"
-+msgstr "IP հասցեն է` %s"
-+
-+#: ../extensions/deviceicon/network.py:104
-+#: ../extensions/deviceicon/network.py:303
-+#: ../src/jarabe/desktop/networkviews.py:140
-+#: ../src/jarabe/desktop/networkviews.py:508
-+msgid "Disconnect"
-+msgstr "Անջատել"
-+
-+#: ../extensions/deviceicon/network.py:112
-+#: ../extensions/deviceicon/network.py:295
-+#: ../src/jarabe/desktop/networkviews.py:243
-+#: ../src/jarabe/desktop/networkviews.py:547
-+#: ../src/jarabe/desktop/networkviews.py:680
-+msgid "Connecting..."
-+msgstr "Միացում..."
-+
-+#: ../extensions/deviceicon/network.py:117
-+#: ../extensions/deviceicon/network.py:185
-+#: ../src/jarabe/desktop/networkviews.py:253
-+#: ../src/jarabe/desktop/networkviews.py:553
-+#: ../src/jarabe/desktop/networkviews.py:686
-+msgid "Connected"
-+msgstr "Միացած է"
-+
-+#: ../extensions/deviceicon/network.py:130
-+msgid "No wireless connection"
-+msgstr ""
-+
-+#: ../extensions/deviceicon/network.py:144
-+msgid "Channel"
-+msgstr "Կապուղի"
-+
-+#: ../extensions/deviceicon/network.py:159
-+msgid "Wired Network"
-+msgstr "Լարային ցանց"
-+
-+#: ../extensions/deviceicon/network.py:188
-+msgid "Speed"
-+msgstr "Արագություն"
-+
-+#: ../extensions/deviceicon/network.py:213
-+msgid "Wireless modem"
-+msgstr "Անլար մոդեմ"
-+
-+#: ../extensions/deviceicon/network.py:281
-+msgid "Please wait..."
-+msgstr "Խնդրում ենք սպասել..."
-+
-+#: ../extensions/deviceicon/network.py:286
-+#: ../src/jarabe/desktop/networkviews.py:136
-+#: ../src/jarabe/desktop/networkviews.py:504
-+#: ../src/jarabe/desktop/networkviews.py:637
-+msgid "Connect"
-+msgstr "Միացնել"
-+
-+#: ../extensions/deviceicon/network.py:287
-+msgid "Disconnected"
-+msgstr "Միացած չէ"
-+
-+#: ../extensions/deviceicon/network.py:294
-+#: ../src/jarabe/controlpanel/toolbar.py:119
-+#: ../src/jarabe/desktop/homebox.py:71
-+#: ../src/jarabe/frame/activitiestray.py:602
-+#: ../src/jarabe/frame/activitiestray.py:704
-+#: ../src/jarabe/frame/activitiestray.py:732
-+msgid "Cancel"
-+msgstr "Չեղարկել"
-+
-+#: ../extensions/deviceicon/network.py:333
-+msgid "Try connection again"
-+msgstr "Կրկին փորձեք միանալ"
-+
-+#: ../extensions/deviceicon/network.py:336
-+#, python-format
-+msgid "Error: %s"
-+msgstr "Վրիպում. %s"
-+
-+#: ../extensions/deviceicon/network.py:340
-+#, python-format
-+msgid "Suggestion: %s"
-+msgstr "Առաջարկություն` %s"
-+
-+#: ../extensions/deviceicon/network.py:349
-+#, python-format
-+msgid "Connected for %s"
-+msgstr "Միացած է %s"
-+
-+#: ../extensions/deviceicon/network.py:355
-+#: ../extensions/deviceicon/network.py:356
-+#, python-format
-+msgid "%d KB"
-+msgstr "%d KB"
-+
-+#: ../extensions/deviceicon/network.py:361
-+msgid "Check your Pin/Puk configuration."
-+msgstr "Ստուգեք ձեր PIN/PUK կազմաձևումը:"
-+
-+#: ../extensions/deviceicon/network.py:364
-+msgid "Check your Access Point Name (APN) configuration"
-+msgstr "Ստուգեք ձեր Միացման Կետի Անվանման (APN) կազմաձևումը"
-+
-+#: ../extensions/deviceicon/network.py:368
-+msgid "Check the Number configuration."
-+msgstr "Ստուգեք ձեր Համարի կազմաձևումը:"
-+
-+#: ../extensions/deviceicon/network.py:370
-+msgid "Check your configuration."
-+msgstr "Ստուգեք ձեր կազմաձևումը:"
-+
-+#: ../extensions/deviceicon/network.py:612
-+msgid "Mesh Network"
-+msgstr "Բջջային Ցանց"
-+
-+#: ../extensions/deviceicon/network.py:656
-+#, python-format
-+msgid "Mesh Network %s"
-+msgstr "Բջջային Ցանց %s"
-+
-+#: ../extensions/deviceicon/network.py:779
-+msgid "No GSM connection available."
-+msgstr "GSM միացումն մատչելի չէ:"
-+
-+#: ../extensions/deviceicon/network.py:780
-+msgid "Create a connection in the control panel."
-+msgstr "Ստեղծել միացում կառավարման վահանակի միջոցով:"
-+
-+#: ../extensions/deviceicon/speaker.py:61
-+msgid "My Speakers"
-+msgstr "Իմ Բարձրախոսները"
-+
-+#: ../extensions/deviceicon/speaker.py:138
-+msgid "Unmute"
-+msgstr "Միացնել Ձայնը"
-+
-+#: ../extensions/deviceicon/speaker.py:141
-+msgid "Mute"
-+msgstr "Անջատել Ձայնը"
-+
-+#: ../extensions/deviceicon/touchpad.py:38
-+msgid "finger"
-+msgstr "մատ"
-+
-+#: ../extensions/deviceicon/touchpad.py:39
-+msgid "stylus"
-+msgstr "Գրափայտ"
-+
-+#: ../extensions/deviceicon/touchpad.py:68
-+msgid "My touchpad"
-+msgstr "Իմ թաչփադ"
-+
-+#: ../extensions/globalkey/screenshot.py:59
-+msgid "Mesh"
-+msgstr "Բջիջ"
-+
-+#: ../extensions/globalkey/screenshot.py:61
-+#: ../src/jarabe/frame/zoomtoolbar.py:41
-+msgid "Group"
-+msgstr "Խումբ"
-+
-+#: ../extensions/globalkey/screenshot.py:63
-+#: ../src/jarabe/frame/zoomtoolbar.py:43
-+msgid "Home"
-+msgstr "Տուն"
-+
-+#: ../extensions/globalkey/screenshot.py:69
-+#: ../src/jarabe/frame/zoomtoolbar.py:45
-+msgid "Activity"
-+msgstr "Գործունեություն"
-+
-+#: ../extensions/globalkey/screenshot.py:72
-+msgid "Screenshot"
-+msgstr "Էկրանի հանույթ"
-+
-+#: ../extensions/globalkey/screenshot.py:74
-+#, python-format
-+msgid "Screenshot of \"%s\""
-+msgstr "\"%s\" Էկրանի հանույթ"
-+
-+#: ../data/sugar.schemas.in.h:1
-+msgid ""
-+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
-+"long name."
-+msgstr ""
-+"\"disabled\"` որպեսզի վերահաստալ անձը; \"system\" ` որպեսզի օգտագոծել UNIX "
-+"օգտվողի լրիվ անունը:"
-+
-+#: ../data/sugar.schemas.in.h:2
-+msgid "Additional directories which can contain updated translations."
-+msgstr ""
-+"Ֆայլերի լրացուցիչ գրացուցակները կարող են պարունակել նորացված "
-+"թարգմանություններ:"
-+
-+#: ../data/sugar.schemas.in.h:3
-+msgid "Backup URL"
-+msgstr "Պահուստային URL"
-+
-+#: ../data/sugar.schemas.in.h:4
-+msgid "Bundle IDs of protected activities"
-+msgstr "Պաշտպանված գործունեությունների փաթեթային ID"
-+
-+#: ../data/sugar.schemas.in.h:5
-+msgid ""
-+"Color for the XO icon that is used throughout the desktop. The string is "
-+"composed of the stroke color and fill color, format is that of rgb colors. "
-+"Example: #AC32FF,#9A5200"
-+msgstr ""
-+"XO պատկերի գույնն այն է որ օգտագործվում է սեղանադիրում: Տողը կառուցվում XO "
-+"նրբագծի և լիցքի գույներից: Գույները որոշվում են rbg ֆորմատով: Օրինակ՝ "
-+"#AC32FF, #9A5200"
-+
-+#: ../data/sugar.schemas.in.h:6
-+msgid "Corner Delay"
-+msgstr "Անկյունների ՈԻշացումը"
-+
-+#: ../data/sugar.schemas.in.h:7
-+msgid "Default font face"
-+msgstr "Ենթադրյալ տառատեսակ"
-+
-+#: ../data/sugar.schemas.in.h:8
-+msgid "Default font size"
-+msgstr "Ենթադրյալ տառաչափս"
-+
-+#: ../data/sugar.schemas.in.h:9
-+msgid "Default nick"
-+msgstr "Ենթադրյալ մականուն"
-+
-+#: ../data/sugar.schemas.in.h:10
-+msgid "Delay for the activation of the frame using the corners."
-+msgstr "Անկյուններն օգտագործող շրջանակի ուշացում:"
-+
-+#: ../data/sugar.schemas.in.h:11
-+msgid "Delay for the activation of the frame using the edges."
-+msgstr "Սայրերն օգտագործող շրջանակի ուշացում:"
-+
-+#: ../data/sugar.schemas.in.h:12
-+msgid "Directory to search for translations"
-+msgstr "Թարգմանություն որոնելու ֆայլերի գրացուցակ"
-+
-+#: ../data/sugar.schemas.in.h:13
-+msgid "Edge Delay"
-+msgstr "Սայրի ուշացում"
-+
-+#: ../data/sugar.schemas.in.h:14
-+msgid "Favorites Layout"
-+msgstr "Ընտրվածների դասավորություն"
-+
-+#: ../data/sugar.schemas.in.h:15
-+msgid "Favorites resume mode"
-+msgstr "Ընտրվածների Շարունակելու եղանակ"
-+
-+#: ../data/sugar.schemas.in.h:16
-+msgid "Font face that is used throughout the desktop."
-+msgstr "Սեղանադրում օգտագործվող տառատեսակ:"
-+
-+#: ../data/sugar.schemas.in.h:17
-+msgid "Font size that is used throughout the desktop."
-+msgstr "Սեղանադրում օգտագործվող տառաչափս:"
-+
-+#: ../data/sugar.schemas.in.h:18
-+msgid "GSM network APN"
-+msgstr "GSM ցանցի APN"
-+
-+#: ../data/sugar.schemas.in.h:19
-+msgid "GSM network PIN"
-+msgstr "GSM ցանցի PIN"
-+
-+#: ../data/sugar.schemas.in.h:20
-+msgid "GSM network PUK"
-+msgstr "GSM ցանցի PUK"
-+
-+#: ../data/sugar.schemas.in.h:21
-+msgid "GSM network access point name configuration"
-+msgstr "GSM ցանցի միացման կետի անվանման կազմաձևում"
-+
-+#: ../data/sugar.schemas.in.h:22
-+msgid "GSM network number"
-+msgstr "GSM ցանցի համարը"
-+
-+#: ../data/sugar.schemas.in.h:23
-+msgid "GSM network password"
-+msgstr "GSM ցանցի գաղտնաբառը"
-+
-+#: ../data/sugar.schemas.in.h:24
-+msgid "GSM network password configuration"
-+msgstr "GSM ցանցի գաղտնաբառի կազմաձևում"
-+
-+#: ../data/sugar.schemas.in.h:25
-+msgid "GSM network personal identification number configuration"
-+msgstr "GSM ցանցի անհատական անձնական համարանիշի կազմաձևում"
-+
-+#: ../data/sugar.schemas.in.h:26
-+msgid "GSM network personal unlock key configuration"
-+msgstr "GSM ցանցի անհատական անձնական բացման եղանակի կազմաձևում"
-+
-+#: ../data/sugar.schemas.in.h:27
-+msgid "GSM network telephone number configuration"
-+msgstr "GSM ցանցի հեռախոսային համարի կազմաձևում"
-+
-+#: ../data/sugar.schemas.in.h:28
-+msgid "GSM network username"
-+msgstr "GSM ցանցի օգտվողի մականունը"
-+
-+#: ../data/sugar.schemas.in.h:29
-+msgid "GSM network username configuration"
-+msgstr "GSM ցանցի օգտվողի մականունի կազմաձևում"
-+
-+#: ../data/sugar.schemas.in.h:30
-+msgid ""
-+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
-+"server."
-+msgstr ""
-+"եթե TRUE է, ապա Sugar-ը Ձեզ որոնելի կդառցնի Jabber սերվերի այլ օգտվողների "
-+"համար:"
-+
-+#: ../data/sugar.schemas.in.h:31
-+msgid "If TRUE, Sugar will show a \"Log out\" option."
-+msgstr "եթե TRUE է, ապա Sugar-ը կտրամադրի \"Դուրս գալ\" ընտրությունը:"
-+
-+#: ../data/sugar.schemas.in.h:32
-+msgid "If TRUE, Sugar will show a \"Restart\" option."
-+msgstr "եթե TRUE է, ապա Sugar-ը կտրամադրի \"Վերամեկնարկ\" ընտրությունը:"
-+
-+#: ../data/sugar.schemas.in.h:33
-+msgid ""
-+"If TRUE, Sugar will show default Ad-hoc networks for channel 1,6 and 11. If "
-+"Sugar sees no \"known\" network when it starts, it does autoconnect to an Ad-"
-+"hoc network."
-+msgstr ""
-+"Եթե TRUE է, ապա Sugar-ը կտրամադրի Ժամանակավոր ստեղված ցանցեր 1,6 և 11 "
-+"կապուղիների համար: Եթե Sugar-ը չի գտնում \"հայտնի\" ցանցեր, նա կմիացնի Ձեզ "
-+"Ժամանակավոր ցանցին:"
-+
-+#: ../data/sugar.schemas.in.h:34
-+msgid "Jabber Server"
-+msgstr "Jabber սերվեր"
-+
-+#: ../data/sugar.schemas.in.h:35
-+msgid "Keyboard layouts"
-+msgstr "Ստեղնաշարի դասավորության"
-+
-+#: ../data/sugar.schemas.in.h:36
-+msgid "Keyboard model"
-+msgstr "Ստեղնաշարի նմուշ"
-+
-+#: ../data/sugar.schemas.in.h:37
-+msgid "Keyboard options"
-+msgstr "Ստեղնաշարի ընտրություն"
-+
-+#: ../data/sugar.schemas.in.h:38
-+msgid "Layout of the favorites view."
-+msgstr "Ընտրյալների դիտման դասավորության:"
-+
-+#: ../data/sugar.schemas.in.h:39
-+msgid ""
-+"List of keyboard layouts. Each entry should be in the form layout(variant)"
-+msgstr ""
-+"Ստեղնաշարի դասավորության ցուցակ: Յուրաքանչուր մուտք պիտի ունենա "
-+"դասավորության ձև:"
-+
-+#: ../data/sugar.schemas.in.h:40
-+msgid "List of keyboard options."
-+msgstr "Ստեղնաշարի ընտրանքների ցուցակ:"
-+
-+#: ../data/sugar.schemas.in.h:41
-+msgid "Power Automatic"
-+msgstr "Ավտոմատ սնուցում"
-+
-+#: ../data/sugar.schemas.in.h:42
-+msgid "Power Automatic."
-+msgstr "Ավտոմատ Սնուցում:"
-+
-+#: ../data/sugar.schemas.in.h:43
-+msgid "Power Extreme"
-+msgstr "Արտակարգ Սնուցում"
-+
-+#: ../data/sugar.schemas.in.h:44
-+msgid "Power Extreme."
-+msgstr "Արտակարգ Սնուցում:"
-+
-+#: ../data/sugar.schemas.in.h:45
-+msgid "Publish to Gadget"
-+msgstr "Հրատարակել Հարմարանքի միջոցով"
-+
-+#: ../data/sugar.schemas.in.h:46
-+msgid "Setting for muting the sound device."
-+msgstr "Ձայնային սարքն անջատելու եղանակ:"
-+
-+#: ../data/sugar.schemas.in.h:47
-+msgid "Show Log out"
-+msgstr "Ցույց տալ Ելք"
-+
-+#: ../data/sugar.schemas.in.h:48
-+msgid "Show Restart"
-+msgstr "Ցույց տալ Վերամեկնարկ"
-+
-+#: ../data/sugar.schemas.in.h:49
-+msgid "Show Sugar Ad-hoc networks"
-+msgstr "Ցույց տալ Sugar հատուկ ցանցեր"
-+
-+#: ../data/sugar.schemas.in.h:50
-+msgid "Sound Muted"
-+msgstr "Ձայնն անջատված է"
-+
-+#: ../data/sugar.schemas.in.h:51
-+msgid "The keyboard model to be used"
-+msgstr "Օգտագործվող ստեղնաշարի մոդել"
-+
-+#: ../data/sugar.schemas.in.h:53
-+msgid "Timezone setting for the system."
-+msgstr "Համակարգի ժամագոտու կարգավորումը:"
-+
-+#: ../data/sugar.schemas.in.h:54
-+msgid "Url of the jabber server to use."
-+msgstr "Jabber սերվերի Url հասցեն:"
-+
-+#: ../data/sugar.schemas.in.h:55
-+msgid "Url where the backup is saved to."
-+msgstr "Պահուստային պատճեների պահպանման Url հասցեն:"
-+
-+#: ../data/sugar.schemas.in.h:56
-+msgid "User Color"
-+msgstr "Օգտագործողի Գույնը"
-+
-+#: ../data/sugar.schemas.in.h:57
-+msgid "User Name"
-+msgstr "Օգտագործողի Անունը"
-+
-+#: ../data/sugar.schemas.in.h:58
-+msgid "User name that is used throughout the desktop."
-+msgstr "Օգտագործողի անունը, որն օգտագործվում է այս համակարգում:"
-+
-+#: ../data/sugar.schemas.in.h:59
-+msgid ""
-+"Users will not be allowed to erase these activities through the list view."
-+msgstr ""
-+"Օգտագործողներին չի թույլատրվելու ջնջել այս գործողությունները դիտման ցանկից:"
-+
-+#: ../data/sugar.schemas.in.h:60
-+msgid "Volume Level"
-+msgstr "Ուժգնություն"
-+
-+#: ../data/sugar.schemas.in.h:61
-+msgid "Volume level for the sound device."
-+msgstr "Ձայնի սարքի ուժգնություն:"
-+
-+#: ../data/sugar.schemas.in.h:62
-+msgid ""
-+"When in resume mode, clicking on a favorite icon will cause the last entry "
-+"for that activity to be resumed."
-+msgstr ""
-+"Վերամեկնարկի ռեժիմում ընտրյալ պատկերակի սեղմելը կառաջացնի այդ գործողության "
-+"վերջին մուտքի վերամեկնարկը:"
-+
-+#: ../src/jarabe/controlpanel/cmd.py:28
-+#, python-format
-+msgid ""
-+"sugar-control-panel: WARNING, found more than one option with the same name: "
-+"%s module: %r"
-+msgstr ""
-+"sugar-կառավար վահանակ. ԶԳՈՒՇԱՑՈՒՄ, գտնվել է ավելի քան մեկ տարբերակ նույն "
-+"անունով.%s մոդուլը.%r"
-+
-+#: ../src/jarabe/controlpanel/cmd.py:30
-+#, python-format
-+msgid "sugar-control-panel: key=%s not an available option"
-+msgstr "sugar-կառավար վահանակ. key=%s անմատչելի տարբերակ"
-+
-+#: ../src/jarabe/controlpanel/cmd.py:31
-+#, python-format
-+msgid "sugar-control-panel: %s"
-+msgstr "sugar-կառավար վահանակ. %s"
-+
-+#. TRANS: Translators, there's a empty line at the end of this string,
-+#. which must appear in the translated string (msgstr) as well.
-+#: ../src/jarabe/controlpanel/cmd.py:38
-+msgid ""
-+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
-+" Control for the sugar environment. \n"
-+" Options: \n"
-+" -h show this help message and exit \n"
-+" -l list all the available options \n"
-+" -h key show information about this key \n"
-+" -g key get the current value of the key \n"
-+" -s key set the current value for the key \n"
-+" -c key clear the current value for the key \n"
-+" "
-+msgstr ""
-+"Օգտագործում. sugar-կառավար վահանակ [ option ] key [ args ... ] \n"
-+" Sugar միջավայրի վերահսկողության: \n"
-+" Ընտրանքներ. \n"
-+" h ցույց տալ այս օգնության ուղերձը և ավարտել \n"
-+" -l բոլոր ընտրանքների ցանկը \n"
-+" -h key ցույց տալ տեղեկատվություն այս ստեղնի մասին key \n"
-+"-g key ստանալ ներկա արժեքը key \n"
-+"-s key սահմանել ընթացիկ արժեքը key \n"
-+"-c key ջնջել ընթացիկ արժեքը key \n"
-+" "
-+
-+#: ../src/jarabe/controlpanel/cmd.py:52
-+msgid "To apply your changes you have to restart sugar.\n"
-+msgstr "Ձեր փոփոխությունները կիրառելու համար դուք պետք է վերամեկնարկեք sugar-ը:\n"
-+
-+#: ../src/jarabe/controlpanel/gui.py:296 ../src/jarabe/journal/palettes.py:161
-+#: ../src/jarabe/journal/palettes.py:246 ../src/jarabe/journal/palettes.py:279
-+#: ../src/jarabe/journal/volumestoolbar.py:307
-+msgid "Warning"
-+msgstr "Զգուշացում"
-+
-+#: ../src/jarabe/controlpanel/gui.py:297
-+#: ../src/jarabe/controlpanel/sectionview.py:41
-+msgid "Changes require restart"
-+msgstr "Փոփոխությունները պահանջում են վերամեկնարկ"
-+
-+#: ../src/jarabe/controlpanel/gui.py:300
-+msgid "Cancel changes"
-+msgstr "Չեղարկել փոփոխությունները"
-+
-+#: ../src/jarabe/controlpanel/gui.py:305 ../src/jarabe/desktop/homebox.py:73
-+msgid "Later"
-+msgstr "Հետո"
-+
-+#: ../src/jarabe/controlpanel/gui.py:309
-+msgid "Restart now"
-+msgstr "Վերամեկնարկել հիմա"
-+
-+#: ../src/jarabe/controlpanel/toolbar.py:63 ../src/jarabe/intro/window.py:201
-+msgid "Done"
-+msgstr "Պատրաստ է"
-+
-+#: ../src/jarabe/controlpanel/toolbar.py:125
-+#: ../src/jarabe/desktop/favoritesview.py:347
-+msgid "Ok"
-+msgstr "OK"
-+
-+#: ../src/jarabe/desktop/activitieslist.py:230
-+#, python-format
-+msgid "Version %s"
-+msgstr "Տարբերակ %s"
-+
-+#: ../src/jarabe/desktop/activitieslist.py:356
-+msgid "Confirm erase"
-+msgstr "Հաստատեք ջնջելը"
-+
-+#: ../src/jarabe/desktop/activitieslist.py:358
-+#, python-format
-+msgid "Confirm erase: Do you want to permanently erase %s?"
-+msgstr "Հաստատեք ջնջելը. Արդյո՞ք ցանկանում եք ընդմիշտ ջնջել %s:"
-+
-+#: ../src/jarabe/desktop/activitieslist.py:362
-+#: ../src/jarabe/frame/clipboardmenu.py:67
-+#: ../src/jarabe/view/viewsource.py:280
-+msgid "Keep"
-+msgstr "Պահել"
-+
-+#: ../src/jarabe/desktop/activitieslist.py:365
-+#: ../src/jarabe/desktop/activitieslist.py:419
-+#: ../src/jarabe/journal/journaltoolbox.py:398
-+#: ../src/jarabe/journal/palettes.py:126
-+msgid "Erase"
-+msgstr "Ջնջել"
-+
-+#: ../src/jarabe/desktop/activitieslist.py:435
-+msgid "Remove favorite"
-+msgstr "Ջնջել ընտրյալը"
-+
-+#: ../src/jarabe/desktop/activitieslist.py:439
-+msgid "Make favorite"
-+msgstr "Նշանակել ընտրյալը"
-+
-+#. TRANS: label for the freeform layout in the favorites view
-+#: ../src/jarabe/desktop/favoriteslayout.py:127
-+msgid "Freeform"
-+msgstr "Ազատ ձև"
-+
-+#. TRANS: label for the ring layout in the favorites view
-+#: ../src/jarabe/desktop/favoriteslayout.py:215
-+msgid "Ring"
-+msgstr "Օղակ"
-+
-+#. TRANS: label for the spiral layout in the favorites view
-+#: ../src/jarabe/desktop/favoriteslayout.py:402
-+msgid "Spiral"
-+msgstr "Գալարաձև"
-+
-+#. TRANS: label for the box layout in the favorites view
-+#: ../src/jarabe/desktop/favoriteslayout.py:472
-+msgid "Box"
-+msgstr "Տուփ"
-+
-+#. TRANS: label for the box layout in the favorites view
-+#: ../src/jarabe/desktop/favoriteslayout.py:515
-+msgid "Triangle"
-+msgstr "Եռանկյուն"
-+
-+#: ../src/jarabe/desktop/favoritesview.py:338
-+msgid "Registration Failed"
-+msgstr "Գրանցումը Չհաջողվեց"
-+
-+#: ../src/jarabe/desktop/favoritesview.py:339
-+#, python-format
-+msgid "%s"
-+msgstr "%s"
-+
-+#: ../src/jarabe/desktop/favoritesview.py:341
-+msgid "Registration Successful"
-+msgstr "Գրանցումը Հաջողվեց"
-+
-+#: ../src/jarabe/desktop/favoritesview.py:342
-+msgid "You are now registered with your school server."
-+msgstr "Դուք այժմ գրանցված եք ձեր դպրոցի սերվերում:"
-+
-+#: ../src/jarabe/desktop/favoritesview.py:641
-+msgid "Register"
-+msgstr "Գրանցվել"
-+
-+#: ../src/jarabe/desktop/favoritesview.py:643
-+#: ../src/jarabe/desktop/favoritesview.py:660
-+msgid "Register again"
-+msgstr "Գրանցել կրկին"
-+
-+#: ../src/jarabe/desktop/homebox.py:66
-+msgid "Software Update"
-+msgstr " Ծրագրի Արդիականացում"
-+
-+#: ../src/jarabe/desktop/homebox.py:67
-+msgid "Update your activities to ensure compatibility with your new software"
-+msgstr ""
-+"Արդիականացրեք Ձեր գործունեությունները Ձեր նոր ծրագրակազմի հետ "
-+"համատեղելիությունը ապահովելու նպատակով"
-+
-+#: ../src/jarabe/desktop/homebox.py:76
-+msgid "Check now"
-+msgstr "Ստուգել հիմա"
-+
-+#: ../src/jarabe/desktop/homebox.py:197
-+msgid "List view"
-+msgstr "Ցուցակի տեսքով"
-+
-+#: ../src/jarabe/desktop/homebox.py:198
-+msgid "<Ctrl>2"
-+msgstr "<Ctrl>2"
-+
-+#: ../src/jarabe/desktop/homebox.py:253
-+msgid "Favorites view"
-+msgstr "Ընտրյալների տեսքով"
-+
-+#: ../src/jarabe/desktop/homebox.py:254
-+msgid "<Ctrl>1"
-+msgstr "<Ctrl>1"
-+
-+#: ../src/jarabe/desktop/keydialog.py:143
-+msgid "Key Type:"
-+msgstr "Ստեղնատեսակը."
-+
-+#: ../src/jarabe/desktop/keydialog.py:163
-+msgid "Authentication Type:"
-+msgstr "Նույնականացման Տեսակը."
-+
-+#: ../src/jarabe/desktop/keydialog.py:229
-+msgid "WPA & WPA2 Personal"
-+msgstr "WPA & WPA2 Անհատական"
-+
-+#: ../src/jarabe/desktop/keydialog.py:238
-+msgid "Wireless Security:"
-+msgstr "Անլար կապի անվտանգության."
-+
-+#. TRANS: Action label for resuming an activity.
-+#: ../src/jarabe/desktop/meshbox.py:91
-+#: ../src/jarabe/journal/journaltoolbox.py:494
-+#: ../src/jarabe/journal/palettes.py:71 ../src/jarabe/view/palettes.py:84
-+msgid "Resume"
-+msgstr "Շարունակել"
-+
-+#: ../src/jarabe/desktop/meshbox.py:96
-+#: ../src/jarabe/frame/activitiestray.py:182
-+msgid "Join"
-+msgstr "Միանալ"
-+
-+#: ../src/jarabe/desktop/networkviews.py:500
-+#, python-format
-+msgid "Ad-hoc Network %d"
-+msgstr "Ժամանակավոր Ցանց %d"
-+
-+#: ../src/jarabe/desktop/networkviews.py:634
-+#, python-format
-+msgid "Mesh Network %d"
-+msgstr "Բջջային Ցանց %d"
-+
-+#: ../src/jarabe/desktop/schoolserver.py:143
-+msgid "Cannot connect to the server."
-+msgstr "Հնարավոր չէ միանալ սերվերին:"
-+
-+#: ../src/jarabe/desktop/schoolserver.py:150
-+msgid "The server could not complete the request."
-+msgstr "Սերվերը չի կարող լրացնել հարցումը:"
-+
-+#: ../src/jarabe/frame/activitiestray.py:187
-+#: ../src/jarabe/frame/activitiestray.py:574
-+msgid "Decline"
-+msgstr "Մերժում"
-+
-+#: ../src/jarabe/frame/activitiestray.py:523
-+#, python-format
-+msgid "%dB"
-+msgstr "%dB"
-+
-+#: ../src/jarabe/frame/activitiestray.py:525
-+#, python-format
-+msgid "%dKB"
-+msgstr "%dKB"
-+
-+#: ../src/jarabe/frame/activitiestray.py:527
-+#, python-format
-+msgid "%dMB"
-+msgstr "%dMB"
-+
-+#: ../src/jarabe/frame/activitiestray.py:544
-+#, python-format
-+msgid "%s of %s"
-+msgstr "%s %s-ից"
-+
-+#: ../src/jarabe/frame/activitiestray.py:558
-+#, python-format
-+msgid "Transfer from %s"
-+msgstr ""
-+
-+#: ../src/jarabe/frame/activitiestray.py:569
-+msgid "Accept"
-+msgstr "Ընդունել"
-+
-+#: ../src/jarabe/frame/activitiestray.py:592
-+#: ../src/jarabe/frame/activitiestray.py:722
-+#, python-format
-+msgid "%s (%s)"
-+msgstr "%s (%s)"
-+
-+#: ../src/jarabe/frame/activitiestray.py:626
-+#: ../src/jarabe/frame/activitiestray.py:639
-+#: ../src/jarabe/frame/activitiestray.py:757
-+msgid "Dismiss"
-+msgstr "Արգելել"
-+
-+#: ../src/jarabe/frame/activitiestray.py:643
-+msgid "The other participant canceled the file transfer"
-+msgstr ""
-+
-+#: ../src/jarabe/frame/activitiestray.py:691
-+#, python-format
-+msgid "Transfer to %s"
-+msgstr ""
-+
-+#: ../src/jarabe/frame/clipboardmenu.py:56
-+msgctxt "Clipboard"
-+msgid "Remove"
-+msgstr ""
-+
-+#: ../src/jarabe/frame/clipboardmenu.py:62
-+#: ../src/jarabe/frame/clipboardmenu.py:85
-+msgid "Open"
-+msgstr "Բացել"
-+
-+#: ../src/jarabe/frame/clipboardmenu.py:90
-+msgid "Open with"
-+msgstr "Բացել ....-ով"
-+
-+#: ../src/jarabe/frame/clipboardobject.py:50
-+#, python-format
-+msgid "%s clipping"
-+msgstr "%s ամրացում"
-+
-+#: ../src/jarabe/frame/zoomtoolbar.py:39
-+msgid "Neighborhood"
-+msgstr "Հարևաններ"
-+
-+#: ../src/jarabe/frame/zoomtoolbar.py:39
-+msgid "F1"
-+msgstr "F1"
-+
-+#: ../src/jarabe/frame/zoomtoolbar.py:41
-+msgid "F2"
-+msgstr "F2"
-+
-+#: ../src/jarabe/frame/zoomtoolbar.py:43
-+msgid "F3"
-+msgstr "F3"
-+
-+#: ../src/jarabe/frame/zoomtoolbar.py:45
-+msgid "F4"
-+msgstr "F4"
-+
-+#: ../src/jarabe/intro/window.py:90
-+msgid "Name:"
-+msgstr "Անուն."
-+
-+#: ../src/jarabe/intro/window.py:126
-+msgid "Click to change color:"
-+msgstr "Քլիք գույնը փոխելու համար."
-+
-+#: ../src/jarabe/intro/window.py:187 ../src/jarabe/journal/detailview.py:105
-+msgid "Back"
-+msgstr "Հետ"
-+
-+#: ../src/jarabe/intro/window.py:204
-+msgid "Next"
-+msgstr "Հաջորդ"
-+
-+#: ../src/jarabe/journal/expandedentry.py:156
-+#: ../src/jarabe/journal/listmodel.py:144 ../src/jarabe/journal/palettes.py:64
-+#: ../src/jarabe/journal/volumestoolbar.py:130
-+msgid "Untitled"
-+msgstr "Անվերնագիր"
-+
-+#: ../src/jarabe/journal/expandedentry.py:245
-+msgid "No preview"
-+msgstr "Առանց նախադիտում"
-+
-+#: ../src/jarabe/journal/expandedentry.py:264
-+#, python-format
-+msgid "Kind: %s"
-+msgstr "Տեսակ. %s"
-+
-+#: ../src/jarabe/journal/expandedentry.py:264
-+#: ../src/jarabe/journal/listmodel.py:150
-+#: ../src/jarabe/journal/listmodel.py:158
-+msgid "Unknown"
-+msgstr "Անճանաչ"
-+
-+#: ../src/jarabe/journal/expandedentry.py:265
-+#, python-format
-+msgid "Date: %s"
-+msgstr "Ամսաթիվ. %s"
-+
-+#: ../src/jarabe/journal/expandedentry.py:266
-+#, python-format
-+msgid "Size: %s"
-+msgstr "Չափս. %s"
-+
-+#: ../src/jarabe/journal/expandedentry.py:294
-+#: ../src/jarabe/journal/misc.py:108
-+msgid "No date"
-+msgstr "Առանց ամսաթիվ"
-+
-+#: ../src/jarabe/journal/expandedentry.py:301
-+msgid "Participants:"
-+msgstr "Մասնակիցներ."
-+
-+#: ../src/jarabe/journal/expandedentry.py:323
-+msgid "Description:"
-+msgstr "Նկարագիր."
-+
-+#: ../src/jarabe/journal/expandedentry.py:348
-+msgid "Tags:"
-+msgstr "Պիտակներ."
-+
-+#: ../src/jarabe/journal/journalactivity.py:115
-+#: ../src/jarabe/journal/journaltoolbox.py:453
-+#: ../src/jarabe/journal/palettes.py:198
-+#: ../src/jarabe/journal/volumestoolbar.py:368
-+msgid "Journal"
-+msgstr "Մատյան"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:71
-+msgid "Search"
-+msgstr "Որոնում"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:138
-+msgid "Anytime"
-+msgstr "Ցանկացած ժամանակ"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:140
-+msgid "Today"
-+msgstr "Այսօր"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:142
-+msgid "Since yesterday"
-+msgstr "Երեկվանից"
-+
-+#. TRANS: Filter entries modified during the last 7 days.
-+#: ../src/jarabe/journal/journaltoolbox.py:144
-+msgid "Past week"
-+msgstr "Վերջին շաբաթվա ընթացքում"
-+
-+#. TRANS: Filter entries modified during the last 30 days.
-+#: ../src/jarabe/journal/journaltoolbox.py:146
-+msgid "Past month"
-+msgstr "Վերջին ամսվա ընթացքում"
-+
-+#. TRANS: Filter entries modified during the last 356 days.
-+#: ../src/jarabe/journal/journaltoolbox.py:148
-+msgid "Past year"
-+msgstr "Վերջին տարվա ընթացքում"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:155
-+msgid "Anyone"
-+msgstr "Բոլորը"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:157
-+msgid "My friends"
-+msgstr "Իմ ընկերները"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:158
-+msgid "My class"
-+msgstr "Իմ դասարանը"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:300
-+msgid "Anything"
-+msgstr "Ամեն ինչը"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:381
-+#: ../src/jarabe/journal/palettes.py:93
-+msgid "Copy to"
-+msgstr ""
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:389
-+#: ../src/jarabe/journal/palettes.py:104 ../src/jarabe/view/viewsource.py:274
-+msgid "Duplicate"
-+msgstr "Կրկնօրինակել"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:422
-+#: ../src/jarabe/journal/palettes.py:141 ../src/jarabe/journal/palettes.py:254
-+#: ../src/jarabe/journal/volumestoolbar.py:315
-+#, python-format
-+msgid "Error while copying the entry. %s"
-+msgstr "Գրառման պատճենահանման վրիպում: %s"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:423
-+#: ../src/jarabe/journal/palettes.py:142 ../src/jarabe/journal/palettes.py:255
-+#: ../src/jarabe/journal/volumestoolbar.py:316
-+msgid "Error"
-+msgstr "Վրիպում"
-+
-+#. TRANS: Action label for starting an entry.
-+#: ../src/jarabe/journal/journaltoolbox.py:497
-+#: ../src/jarabe/journal/palettes.py:74
-+msgid "Start"
-+msgstr "Մեկնարկ"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:525
-+msgid "Sort by date modified"
-+msgstr "Դասավորել ըստ փոփոխման ամսաթվի"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:526
-+msgid "Sort by date created"
-+msgstr "Դասավորել ըստ ստեղծման ամսաթվի"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:527
-+msgid "Sort by size"
-+msgstr "Դասավորել ըստ չափսի"
-+
-+#: ../src/jarabe/journal/journaltoolbox.py:536
-+msgid "Sort view"
-+msgstr "Դասավորված տեսք"
-+
-+#: ../src/jarabe/journal/listview.py:316
-+msgid "Your Journal is empty"
-+msgstr "Ձեր Մատյանը դաատրկ է"
-+
-+#: ../src/jarabe/journal/listview.py:319
-+msgid "Your documents folder is empty"
-+msgstr ""
-+
-+#: ../src/jarabe/journal/listview.py:321
-+msgid "The device is empty"
-+msgstr ""
-+
-+#: ../src/jarabe/journal/listview.py:323
-+msgid "No matching entries"
-+msgstr "Չկա համընկնող գրառում"
-+
-+#: ../src/jarabe/journal/listview.py:397
-+msgid "Clear search"
-+msgstr "Մաքրել որոնումը"
-+
-+#: ../src/jarabe/journal/misc.py:273
-+#, python-format
-+msgid "Older Version Of %s Activity"
-+msgstr "%s գործունեության ավելի հին տարբերակ"
-+
-+#: ../src/jarabe/journal/misc.py:274
-+#, python-format
-+msgid "Do you want to downgrade to version %s"
-+msgstr "Ցանկանում եք ապաարդիականացնել դեպի տարբերակ %s"
-+
-+#: ../src/jarabe/journal/modalalert.py:64
-+msgid "Your Journal is full"
-+msgstr "Ձեր Մատյանը լիքն է"
-+
-+#: ../src/jarabe/journal/modalalert.py:68
-+msgid "Please delete some old Journal entries to make space for new ones."
-+msgstr ""
-+"Խնդրում ենք ջնջել մատյանի որոշ հին գրառումները, որպեսզի տեղ ազատեք նորի "
-+"համար:"
-+
-+#: ../src/jarabe/journal/modalalert.py:80
-+msgid "Show Journal"
-+msgstr "Ցուցադրել Մատյանը"
-+
-+#: ../src/jarabe/journal/objectchooser.py:146
-+msgid "Choose an object"
-+msgstr "Ընտրել օբյեկտը"
-+
-+#: ../src/jarabe/journal/objectchooser.py:151
-+#: ../src/jarabe/view/viewsource.py:410
-+msgid "Close"
-+msgstr "Փակել"
-+
-+#: ../src/jarabe/journal/palettes.py:72
-+msgid "Resume with"
-+msgstr "Շարունակել"
-+
-+#: ../src/jarabe/journal/palettes.py:75
-+msgid "Start with"
-+msgstr "Մեկնարկել"
-+
-+#: ../src/jarabe/journal/palettes.py:88 ../src/jarabe/journal/palettes.py:357
-+msgid "No activity to start entry"
-+msgstr "Գրառումը սկսելու համար չկա ոչ մի գործունեություն"
-+
-+#: ../src/jarabe/journal/palettes.py:112
-+msgid "Send to"
-+msgstr "ՈՒղարկել"
-+
-+#: ../src/jarabe/journal/palettes.py:121
-+msgid "View Details"
-+msgstr "Դիտել Մանրամասները"
-+
-+#: ../src/jarabe/journal/palettes.py:160
-+msgid "Entries without a file cannot be sent."
-+msgstr ""
-+
-+#: ../src/jarabe/journal/palettes.py:245 ../src/jarabe/journal/palettes.py:278
-+#: ../src/jarabe/journal/volumestoolbar.py:306
-+msgid "Entries without a file cannot be copied."
-+msgstr "Առանց ֆայլի գրառումները չեն կարող լինել պատճենահանված:"
-+
-+#: ../src/jarabe/journal/palettes.py:267
-+msgid "Clipboard"
-+msgstr "Սեղմատախտակ"
-+
-+#: ../src/jarabe/journal/palettes.py:322
-+msgid "No friends present"
-+msgstr "Ներկա չի ոչ մի ընկեր"
-+
-+#: ../src/jarabe/journal/palettes.py:327
-+msgid "No valid connection found"
-+msgstr "Ոչ մի վավեր կապ չի գտնվել"
-+
-+#: ../src/jarabe/journal/palettes.py:355
-+msgid "No activity to resume entry"
-+msgstr "Գրառումը շարունակելու համար չկա ոչ մի գործունեություն"
-+
-+#: ../src/jarabe/journal/volumestoolbar.py:209
-+msgid "Documents"
-+msgstr ""
-+
-+#: ../src/jarabe/journal/volumestoolbar.py:391
-+#: ../src/jarabe/view/palettes.py:202 ../src/jarabe/view/palettes.py:254
-+#, python-format
-+msgid "%(free_space)d MB Free"
-+msgstr "%(free_space)d ՄԲ ազատ"
-+
-+#: ../src/jarabe/model/network.py:163
-+msgid "The reason for the device state change is unknown."
-+msgstr "Սարքի վիճակի փոփոխության պատճառը անհայտ է:"
-+
-+#: ../src/jarabe/model/network.py:165
-+msgid "The state change is normal."
-+msgstr "Վիճակի փոփոխությունը սովորական է:"
-+
-+#: ../src/jarabe/model/network.py:167
-+msgid "The device is now managed."
-+msgstr "Սարքը այժմ կառավարվող է:"
-+
-+#: ../src/jarabe/model/network.py:169
-+msgid "The device is no longer managed."
-+msgstr "Սարքը այլևս կառավարվող չէ:"
-+
-+#: ../src/jarabe/model/network.py:171
-+msgid "The device could not be readied for configuration."
-+msgstr "Սարքի կարգավորումները չեն կարդացվում:"
-+
-+#: ../src/jarabe/model/network.py:173
-+msgid ""
-+"IP configuration could not be reserved (no available address, timeout, etc)."
-+msgstr ""
-+"IP կոնֆիգուրացիան չի կարող հաստատվել (չկա հասանելի հասցե, ժամասպառ, և այլն):"
-+
-+#: ../src/jarabe/model/network.py:176
-+msgid "The IP configuration is no longer valid."
-+msgstr "IP կոնֆիգուրացիան այլևս վավեր չէ:"
-+
-+#: ../src/jarabe/model/network.py:178
-+msgid "Secrets were required, but not provided."
-+msgstr "Գաղտնիքներ էր պահանջվում, բայց չեն տրամադրվել:"
-+
-+#: ../src/jarabe/model/network.py:180
-+msgid ""
-+"The 802.1X supplicant disconnected from the access point or authentication "
-+"server."
-+msgstr "802.1X հայցողը անջատված է միացման կետից կամ վավերացման սերվերից:"
-+
-+#: ../src/jarabe/model/network.py:183
-+msgid "Configuration of the 802.1X supplicant failed."
-+msgstr "802.1X հայցողի կարգավորումների վրիպւմ:"
-+
-+#: ../src/jarabe/model/network.py:185
-+msgid "The 802.1X supplicant quit or failed unexpectedly."
-+msgstr "802.1X հայցողը անսպասելիորեն ավարտեց կամ անջատվեց:"
-+
-+#: ../src/jarabe/model/network.py:187
-+msgid "The 802.1X supplicant took too long to authenticate."
-+msgstr "802.1X դիմորդի վավերացումը շատ երկար տեւեց:"
-+
-+#: ../src/jarabe/model/network.py:189
-+msgid "The PPP service failed to start within the allowed time."
-+msgstr "PPP սպասարկումը թույլատրված ժամկետում չսկսեց:"
-+
-+#: ../src/jarabe/model/network.py:191
-+msgid "The PPP service disconnected unexpectedly."
-+msgstr "PPP սպասարկումն անսպասելիորեն անջատվեց:"
-+
-+#: ../src/jarabe/model/network.py:193
-+msgid "The PPP service quit or failed unexpectedly."
-+msgstr "PPP սպասարկումն անսպասելիորեն դադարեց կամ անհաջողության մատնվեց:"
-+
-+#: ../src/jarabe/model/network.py:195
-+msgid "The DHCP service failed to start within the allowed time."
-+msgstr "DHCP սպասարկումը թույկատրված ժամկետում չսկսեց:"
-+
-+#: ../src/jarabe/model/network.py:197
-+msgid "The DHCP service reported an unexpected error."
-+msgstr "DHCP սպասարկումն անսպասելի սխալ հաղորդեց:"
-+
-+#: ../src/jarabe/model/network.py:199
-+msgid "The DHCP service quit or failed unexpectedly."
-+msgstr "DHCP սպասարկումն անսպասելիորեն դադարեց կամ անհաջողության մատնվեց:"
-+
-+#: ../src/jarabe/model/network.py:201
-+msgid "The shared connection service failed to start."
-+msgstr "Ընդհանուր միացման սպասարկումը չսկսեց:"
-+
-+#: ../src/jarabe/model/network.py:203
-+msgid "The shared connection service quit or failed unexpectedly."
-+msgstr ""
-+"Ընդհանուր միացման սպասարկումն անսպասելիորեն դադարեց կամ անհաջողության "
-+"մատնվեց:"
-+
-+#: ../src/jarabe/model/network.py:206
-+msgid "The AutoIP service failed to start."
-+msgstr "AutoIP սպասարկումը չսկսեց:"
-+
-+#: ../src/jarabe/model/network.py:208
-+msgid "The AutoIP service reported an unexpected error."
-+msgstr "AutoIP սպասարկումն անսպասելի սխալ հաղորդեց:"
-+
-+#: ../src/jarabe/model/network.py:210
-+msgid "The AutoIP service quit or failed unexpectedly."
-+msgstr "AutoIP սպասարկումն անսպասելիորեն դադարեց կամ անհաջողության մատնվեց:"
-+
-+#: ../src/jarabe/model/network.py:212
-+msgid "Dialing failed because the line was busy."
-+msgstr "Զանգահարել չհաջողվեց, որովհետեւ գիծը զբաղված էր:"
-+
-+#: ../src/jarabe/model/network.py:214
-+msgid "Dialing failed because there was no dial tone."
-+msgstr "Զանգահարել չհաջողվեց, որովհետեւ զանգի ձայնանշան չկար:"
-+
-+#: ../src/jarabe/model/network.py:216
-+msgid "Dialing failed because there was no carrier."
-+msgstr ""
-+"Զանգահարել չհաջողվեց ծառայություն մատուցող ընկերության բացակայության "
-+"պատճառով:"
-+
-+#: ../src/jarabe/model/network.py:218
-+msgid "Dialing timed out."
-+msgstr "Զանգահարման համար թույլատրված ժամանակը սպառվեց:"
-+
-+#: ../src/jarabe/model/network.py:220
-+msgid "Dialing failed."
-+msgstr "Զանգահարել չհաջողվեց:"
-+
-+#: ../src/jarabe/model/network.py:222
-+msgid "Modem initialization failed."
-+msgstr "Մոդեմի գործարկումը չհաջողվեց:"
-+
-+#: ../src/jarabe/model/network.py:224
-+msgid "Failed to select the specified GSM APN"
-+msgstr "Չկարողացավ ընտրել տրված GSM APN-ը"
-+
-+#: ../src/jarabe/model/network.py:226
-+msgid "Not searching for networks."
-+msgstr "Ցանցեր չի փնտրում:"
-+
-+#: ../src/jarabe/model/network.py:228
-+msgid "Network registration was denied."
-+msgstr "Ցանցի գրանցումը մերժվեց:"
-+
-+#: ../src/jarabe/model/network.py:230
-+msgid "Network registration timed out."
-+msgstr "Ցանցի գրանցման համար հատկացված ժամանակը սպառվեց:"
-+
-+#: ../src/jarabe/model/network.py:232
-+msgid "Failed to register with the requested GSM network."
-+msgstr "Չկարողացավ գրանցվել տվյալ GSM ցանցում:"
-+
-+#: ../src/jarabe/model/network.py:234
-+msgid "PIN check failed."
-+msgstr "Անձնական համարի ստուգումը չհաջողվեց:"
-+
-+#: ../src/jarabe/model/network.py:236
-+msgid "Necessary firmware for the device may be missing."
-+msgstr "Սարքի անհրաժեշտ ծրագրային ապահովումը պակասում է:"
-+
-+#: ../src/jarabe/model/network.py:238
-+msgid "The device was removed."
-+msgstr "Սարքը հանվել է:"
-+
-+#: ../src/jarabe/model/network.py:240
-+msgid "NetworkManager went to sleep."
-+msgstr "Ցանցային կառավարիչը քուն մտավ:"
-+
-+#: ../src/jarabe/model/network.py:242
-+msgid "The device's active connection was removed or disappeared."
-+msgstr "Սարքի գործուն կապը հանվեց կամ անհետացավ:"
-+
-+#: ../src/jarabe/model/network.py:245
-+msgid "A user or client requested the disconnection."
-+msgstr "Օգտագործողը կամ հաճախորդը խնդրեց կապի դադարեցում:"
-+
-+#: ../src/jarabe/model/network.py:247
-+msgid "The device's carrier/link changed."
-+msgstr "Սարքին կապի ծառայություն մատուցողը / հանգույցը փոխվեց:"
-+
-+#: ../src/jarabe/view/buddymenu.py:67
-+msgid "Remove friend"
-+msgstr "Հեռացնել ընկերոջը:"
-+
-+#: ../src/jarabe/view/buddymenu.py:70
-+msgid "Make friend"
-+msgstr "Ընկերություն հաստատել:"
-+
-+#: ../src/jarabe/view/buddymenu.py:87
-+msgid "Shutdown"
-+msgstr "Անջատել"
-+
-+#: ../src/jarabe/view/buddymenu.py:95
-+msgid "Restart"
-+msgstr "Վերագործարկել"
-+
-+#: ../src/jarabe/view/buddymenu.py:101
-+msgid "Logout"
-+msgstr "Դուրս գալ համակարգից"
-+
-+#: ../src/jarabe/view/buddymenu.py:106
-+msgid "My Settings"
-+msgstr "Իմ չափանիշները"
-+
-+#: ../src/jarabe/view/buddymenu.py:142
-+#, python-format
-+msgid "Invite to %s"
-+msgstr "Հրավիրել %s"
-+
-+#: ../src/jarabe/view/launcher.py:145
-+#, python-format
-+msgid "<b>%s</b> failed to start."
-+msgstr "<b>%s</b>-ը չգործարկվեց:"
-+
-+#: ../src/jarabe/view/palettes.py:48
-+msgid "Starting..."
-+msgstr "Սկսած..."
-+
-+#: ../src/jarabe/view/palettes.py:58
-+msgid "Activity failed to start"
-+msgstr "Գործողությունը չկարողացավ սկսել"
-+
-+#. TODO: share-with, keep
-+#: ../src/jarabe/view/palettes.py:91
-+msgid "View Source"
-+msgstr "Դիտել աղբյուրը"
-+
-+#: ../src/jarabe/view/palettes.py:102
-+msgid "Stop"
-+msgstr "Կանգառ"
-+
-+#: ../src/jarabe/view/palettes.py:139
-+msgid "Start new"
-+msgstr "Սկսել նորը"
-+
-+#: ../src/jarabe/view/palettes.py:180
-+msgid "Show contents"
-+msgstr "Ցույց տալ բովանդակությունը"
-+
-+#: ../src/jarabe/view/palettes.py:229
-+msgctxt "Volume"
-+msgid "Remove"
-+msgstr ""
-+
-+#: ../src/jarabe/view/viewsource.py:263
-+msgid "Instance Source"
-+msgstr "Միջադեպի աղբյուր"
-+
-+#: ../src/jarabe/view/viewsource.py:312
-+msgid "Source"
-+msgstr "Աղբյուր"
-+
-+#: ../src/jarabe/view/viewsource.py:374
-+msgid "Activity Bundle Source"
-+msgstr "Գործողությունների փաթեթի աղբյուր"
-+
-+#: ../src/jarabe/view/viewsource.py:393
-+msgid "Sugar Toolkit Source"
-+msgstr ""
-+
-+#: ../src/jarabe/view/viewsource.py:400 ../src/jarabe/view/viewsource.py:401
-+#, python-format
-+msgid "View source: %r"
-+msgstr "Դիտել աղբյուրը. %r"
-+
-+#: ../src/jarabe/util/emulator.py:40
-+msgid "Sugar in a window"
-+msgstr "Շաքարը պատուհանում"
-diff --git a/po/pseudo.po b/po/pseudo.po
-new file mode 100644
-index 0000000..e184567
---- /dev/null
-+++ b/po/pseudo.po
-@@ -0,0 +1,517 @@
-+# SOME DESCRIPTIVE TITLE.
-+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-+# This file is distributed under the same license as the PACKAGE package.
-+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-+#, fuzzy
-+msgid ""
-+msgstr ""
-+"Project-Id-Version: PACKAGE VERSION\n"
-+"Report-Msgid-Bugs-To: \n"
-+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
-+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-+"Language-Team: LANGUAGE <LL@li.org>\n"
-+"MIME-Version: 1.0\n"
-+"Content-Type: text/plain; charset=UTF-8\n"
-+"Content-Transfer-Encoding: 8bit\n"
-+"X-Generator: Translate Toolkit 1.1.1rc4\n"
-+
-+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
-+msgid "Name:"
-+msgstr ""
-+
-+#: ../src/intro/intro.py:94
-+msgid "Click to change color:"
-+msgstr ""
-+
-+#: ../src/intro/intro.py:145
-+msgid "Back"
-+msgstr ""
-+
-+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
-+msgid "Done"
-+msgstr ""
-+
-+#: ../src/intro/intro.py:162
-+msgid "Next"
-+msgstr ""
-+
-+#: ../src/view/BuddyMenu.py:58
-+msgid "Remove friend"
-+msgstr ""
-+
-+#: ../src/view/BuddyMenu.py:61
-+msgid "Make friend"
-+msgstr ""
-+
-+#: ../src/view/BuddyMenu.py:91
-+#, python-format
-+msgid "Invite to %s"
-+msgstr ""
-+
-+#: ../src/view/clipboardmenu.py:48
-+msgid "Remove"
-+msgstr ""
-+
-+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
-+msgid "Open"
-+msgstr ""
-+
-+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
-+#. TODO: Implement stopping downloads
-+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
-+#. self.append_menu_item(self._stop_item)
-+#: ../src/view/clipboardmenu.py:63
-+msgid "Keep"
-+msgstr ""
-+
-+#: ../src/view/clipboardmenu.py:84
-+msgid "Open with"
-+msgstr ""
-+
-+#: ../src/view/clipboardmenu.py:212
-+#, python-format
-+msgid "Clipboard object: %s."
-+msgstr ""
-+
-+#: ../src/hardware/keydialog.py:150
-+msgid "Key Type:"
-+msgstr ""
-+
-+#: ../src/hardware/keydialog.py:170
-+msgid "Authentication Type:"
-+msgstr ""
-+
-+#: ../src/hardware/keydialog.py:251
-+msgid "Encryption Type:"
-+msgstr ""
-+
-+#: ../src/view/Shell.py:262
-+msgid "Screenshot"
-+msgstr ""
-+
-+#: ../src/view/home/HomeBox.py:147
-+msgid "List view"
-+msgstr ""
-+
-+#: ../src/view/home/HomeBox.py:148
-+msgid "<Ctrl>L"
-+msgstr ""
-+
-+#: ../src/view/home/HomeBox.py:204
-+msgid "Favorites view"
-+msgstr ""
-+
-+#: ../src/view/home/HomeBox.py:205
-+msgid "<Ctrl>R"
-+msgstr ""
-+
-+#. TRANS: label for the freeform layout in the favorites view
-+#: ../src/view/home/HomeBox.py:211
-+msgid "Freeform"
-+msgstr ""
-+
-+#. TRANS: label for the ring layout in the favorites view
-+#: ../src/view/home/HomeBox.py:218
-+msgid "Ring"
-+msgstr ""
-+
-+#: ../src/view/home/MeshBox.py:97
-+msgid "Connect"
-+msgstr ""
-+
-+#: ../src/view/home/MeshBox.py:106
-+msgid "Disconnect"
-+msgstr ""
-+
-+#: ../src/view/home/MeshBox.py:118
-+msgid "Disconnecting..."
-+msgstr ""
-+
-+#: ../src/view/home/MeshBox.py:152
-+msgid "Connecting..."
-+msgstr ""
-+
-+#. TODO: show the channel number
-+#: ../src/view/home/MeshBox.py:159
-+msgid "Connected"
-+msgstr ""
-+
-+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
-+#: ../src/view/devices/network/mesh.py:65
-+#: ../src/view/devices/network/mesh.py:69
-+msgid "Mesh Network"
-+msgstr ""
-+
-+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
-+#: ../src/view/devices/network/mesh.py:86
-+msgid "Disconnect..."
-+msgstr ""
-+
-+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
-+msgid "Resume"
-+msgstr ""
-+
-+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
-+msgid "Join"
-+msgstr ""
-+
-+#: ../src/view/devices/battery.py:42
-+msgid "My Battery"
-+msgstr ""
-+
-+#: ../src/view/devices/battery.py:111
-+msgid "Charging"
-+msgstr ""
-+
-+#: ../src/view/devices/battery.py:114
-+msgid "Very little power remaining"
-+msgstr ""
-+
-+#: ../src/view/devices/battery.py:120
-+#, python-format
-+msgid "%(hour)d:%(min).2d remaining"
-+msgstr ""
-+
-+#: ../src/view/devices/battery.py:124
-+msgid "Charged"
-+msgstr ""
-+
-+#: ../src/view/devices/speaker.py:40
-+msgid "My Speakers"
-+msgstr ""
-+
-+#: ../src/view/devices/speaker.py:104
-+msgid "Unmute"
-+msgstr ""
-+
-+#: ../src/view/devices/speaker.py:107
-+msgid "Mute"
-+msgstr ""
-+
-+#: ../src/view/devices/network/wireless.py:64
-+msgid "Disconnected"
-+msgstr ""
-+
-+#: ../src/view/devices/network/wireless.py:134
-+msgid "Channel"
-+msgstr ""
-+
-+#: ../src/view/frame/zoomtoolbar.py:34
-+msgid "Neighborhood"
-+msgstr ""
-+
-+#: ../src/view/frame/zoomtoolbar.py:36
-+msgid "Group"
-+msgstr ""
-+
-+#: ../src/view/frame/zoomtoolbar.py:38
-+msgid "Home"
-+msgstr ""
-+
-+#: ../src/view/frame/zoomtoolbar.py:40
-+msgid "Activity"
-+msgstr ""
-+
-+#: ../src/controlpanel/cmd.py:26
-+#, python-format
-+msgid ""
-+"sugar-control-panel: WARNING, found more than one option with the same name: "
-+"%s module: %r"
-+msgstr ""
-+
-+#: ../src/controlpanel/cmd.py:28
-+#, python-format
-+msgid "sugar-control-panel: key=%s not an available option"
-+msgstr ""
-+
-+#: ../src/controlpanel/cmd.py:29
-+#, python-format
-+msgid "sugar-control-panel: %s"
-+msgstr ""
-+
-+#: ../src/controlpanel/cmd.py:33
-+msgid ""
-+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
-+" Control for the sugar environment. \n"
-+" Options: \n"
-+" -h show this help message and exit \n"
-+" -l list all the available options \n"
-+" -h key show information about this key \n"
-+" -g key get the current value of the key \n"
-+" -s key set the current value for the key \n"
-+" "
-+msgstr ""
-+
-+#: ../src/controlpanel/cmd.py:45
-+msgid "To apply your changes you have to restart sugar.\n"
-+msgstr ""
-+
-+#: ../src/controlpanel/toolbar.py:115
-+msgid "Cancel"
-+msgstr ""
-+
-+#: ../src/controlpanel/toolbar.py:121
-+msgid "Ok"
-+msgstr ""
-+
-+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
-+msgid "Changes require restart"
-+msgstr ""
-+
-+#: ../src/controlpanel/gui.py:249
-+msgid "Warning"
-+msgstr ""
-+
-+#: ../src/controlpanel/gui.py:253
-+msgid "Cancel changes"
-+msgstr ""
-+
-+#: ../src/controlpanel/gui.py:257
-+msgid "Later"
-+msgstr ""
-+
-+#: ../src/controlpanel/gui.py:261
-+msgid "Restart now"
-+msgstr ""
-+
-+#: ../src/controlpanel/model/aboutme.py:44
-+msgid "You must enter a name."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/aboutme.py:67
-+#, python-format
-+msgid "stroke: color=%s hue=%s"
-+msgstr ""
-+
-+#: ../src/controlpanel/model/aboutme.py:70
-+#, python-format
-+msgid "stroke: %s"
-+msgstr ""
-+
-+#: ../src/controlpanel/model/aboutme.py:72
-+#, python-format
-+msgid "fill: color=%s hue=%s"
-+msgstr ""
-+
-+#: ../src/controlpanel/model/aboutme.py:74
-+#, python-format
-+msgid "fill: %s"
-+msgstr ""
-+
-+#: ../src/controlpanel/model/aboutme.py:85
-+msgid "Error in specified color modifiers."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/aboutme.py:88
-+msgid "Error in specified colors."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/aboutxo.py:24
-+msgid "Not available"
-+msgstr ""
-+
-+#: ../src/controlpanel/model/datetime.py:85
-+msgid "Error timezone does not exist."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
-+msgid "Value must be an integer."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/language.py:28
-+msgid "Could not access ~/.i18n. Create standard settings."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/language.py:104
-+#, python-format
-+msgid "Language for code=%s could not be determined."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/language.py:121
-+#, python-format
-+msgid "Sorry I do not speak '%s'."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/network.py:48
-+msgid "You must enter a server."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/network.py:63
-+msgid "State is unknown."
-+msgstr ""
-+
-+#: ../src/controlpanel/model/network.py:83
-+msgid "Error in specified radio argument use on/off."
-+msgstr ""
-+
-+#: ../src/controlpanel/view/aboutme.py:32
-+msgid "About Me"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/aboutme.py:134
-+msgid "Click to change your color:"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/aboutxo.py:26
-+msgid "About my XO"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/aboutxo.py:47
-+msgid "Identity"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/aboutxo.py:56
-+msgid "Serial Number:"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/aboutxo.py:79
-+msgid "Software"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/aboutxo.py:88
-+msgid "Build:"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/aboutxo.py:103
-+msgid "Firmware:"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/datetime.py:29
-+msgid "Date & Time"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/datetime.py:72
-+msgid "Timezone"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/frame.py:28
-+msgid "Frame"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/frame.py:30
-+msgid "never"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/frame.py:31
-+msgid "instantaneous"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/frame.py:32
-+#, python-format
-+msgid "%s seconds"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/frame.py:56
-+msgid "Activation Delay"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/frame.py:80
-+msgid "Corner"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/frame.py:115
-+msgid "Edge"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/language.py:29
-+#: ../src/controlpanel/view/language.py:74
-+msgid "Language"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/network.py:28
-+msgid "Network"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/network.py:53
-+msgid "Wireless"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/network.py:61
-+msgid "Radio:"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/network.py:94
-+msgid "Mesh"
-+msgstr ""
-+
-+#: ../src/controlpanel/view/network.py:103
-+msgid "Server:"
-+msgstr ""
-+
-+#: ../src/view/devices/network/mesh.py:108
-+msgid "Connected to a School Mesh Portal"
-+msgstr ""
-+
-+#: ../src/view/devices/network/mesh.py:110
-+msgid "Looking for a School Mesh Portal..."
-+msgstr ""
-+
-+#: ../src/view/devices/network/mesh.py:113
-+msgid "Connected to an XO Mesh Portal"
-+msgstr ""
-+
-+#: ../src/view/devices/network/mesh.py:115
-+msgid "Looking for an XO Mesh Portal..."
-+msgstr ""
-+
-+#: ../src/view/devices/network/mesh.py:118
-+msgid "Connected to a Simple Mesh"
-+msgstr ""
-+
-+#: ../src/view/devices/network/mesh.py:120
-+msgid "Starting a Simple Mesh"
-+msgstr ""
-+
-+#: ../src/view/devices/network/mesh.py:127
-+msgid "Unknown Mesh"
-+msgstr ""
-+
-+#: ../src/view/frame/activitiestray.py:224
-+msgid "Decline"
-+msgstr ""
-+
-+#: ../src/view/home/favoritesview.py:351
-+msgid "Control Panel"
-+msgstr ""
-+
-+#: ../src/view/home/favoritesview.py:362
-+msgid "Restart"
-+msgstr ""
-+
-+#: ../src/view/home/favoritesview.py:367
-+msgid "Shutdown"
-+msgstr ""
-+
-+#: ../src/view/home/favoritesview.py:373
-+msgid "Register"
-+msgstr ""
-+
-+#: ../src/view/palettes.py:41
-+msgid "Starting..."
-+msgstr ""
-+
-+#: ../src/view/palettes.py:71
-+msgid "Stop"
-+msgstr ""
-+
-+#: ../src/view/palettes.py:96
-+msgid "Start"
-+msgstr ""
-+
-+#: ../src/view/palettes.py:119
-+msgid "Remove favorite"
-+msgstr ""
-+
-+#: ../src/view/palettes.py:123
-+msgid "Make favorite"
-+msgstr ""
-+
-+#: ../src/view/palettes.py:169
-+msgid "Show contents"
-+msgstr ""
-+
-+#: ../src/view/palettes.py:193
-+#, python-format
-+msgid "%(free_space)d MB Free"
-+msgstr ""
-diff --git a/src/jarabe/.gitignore b/src/jarabe/.gitignore
-new file mode 100644
-index 0000000..4acd06b
---- /dev/null
-+++ b/src/jarabe/.gitignore
-@@ -0,0 +1 @@
-+config.py
---
-1.7.6
-
diff --git a/rpms/sugar/0000-langs.patch b/rpms/sugar/0000-langs.patch
new file mode 100644
index 0000000..01f5b19
--- /dev/null
+++ b/rpms/sugar/0000-langs.patch
@@ -0,0 +1,11 @@
+--- a/configure.ac.orig 2012-02-08 16:36:08.000000000 -0600
++++ b/configure.ac 2012-02-08 16:36:47.000000000 -0600
+@@ -18,7 +18,7 @@
+
+ # Setup GETTEXT
+ #
+-ALL_LINGUAS="af am ar ay bg bi bn_IN bn ca cpp cs da de dz el en es fa_AF fa ff fil fr gu ha he hi ht hu id ig is it ja km ko kos mg mi mk ml mn mr ms mvo nb ne nl pa pap pis pl ps pt_BR pt qu ro ru rw sd si sk sl sq sv sw ta te th tpi tr tvl tzo ug ur vi wa yo zh_CN zh_TW"
++ALL_LINGUAS="af am ar ay aym bg bi bn_IN bn ca cpp cs da de dz el en en_GB es fa_AF fa ff fil fr gu ha he hi ht hu id ig is it ja km ko kos mg mi mk ml mn mr ms mvo nb ne nl pa pap pis pl ps pt_BR pt qu quz ro ru rw sd si sk sl sq sv sw ta te th tpi tr tvl tzo ug ur vi wa yo zh_CN zh_TW"
+
+ GETTEXT_PACKAGE=sugar
+ AC_PROG_INTLTOOL([0.33])
diff --git a/rpms/sugar/0063-Add-quz-and-aym-to-ALL_LINGUAS-take-2.patch b/rpms/sugar/0063-Add-quz-and-aym-to-ALL_LINGUAS-take-2.patch
deleted file mode 100644
index eae28e7..0000000
--- a/rpms/sugar/0063-Add-quz-and-aym-to-ALL_LINGUAS-take-2.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 63900aa313843d2d36e21bafa9d2b8648c2594bb Mon Sep 17 00:00:00 2001
-From: bernie <bernie@codewiz.org>
-Date: Fri, 25 Nov 2011 20:34:51 +0000
-Subject: [PATCH 63/82] Add quz and aym to ALL_LINGUAS (take 2)
-Organization: Sugar Labs Foundation
-
-Signed-off-by: Bernie Innocenti <bernie@codewiz.org>
----
- configure.ac | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index 86f6116..8e6d871 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -18,7 +18,7 @@ PKG_CHECK_MODULES(SHELL, pygtk-2.0 gtk+-2.0 gconf-2.0)
-
- # Setup GETTEXT
- #
--ALL_LINGUAS="af am ar ay bg bi bn_IN bn ca cpp cs da de dz el en es fa_AF fa ff fil fr gu ha he hi ht hu id ig is it ja km ko kos mg mi mk ml mn mr ms mvo nb ne nl pa pap pis pl ps pt_BR pt qu ro ru rw sd si sk sl sq sv sw ta te th tpi tr tvl tzo ug ur vi wa yo zh_CN zh_TW"
-+ALL_LINGUAS="af am ar ay aym bg bi bn_IN bn ca cpp cs da de dz el en es fa_AF fa ff fil fr gu ha he hi ht hu id ig is it ja km ko kos mg mi mk ml mn mr ms mvo nb ne nl pa pap pis pl ps pt_BR pt qu quz ro ru rw sd si sk sl sq sv sw ta te th tpi tr tvl tzo ug ur vi wa yo zh_CN zh_TW"
-
- GETTEXT_PACKAGE=sugar
- AC_PROG_INTLTOOL([0.33])
---
-1.7.4.4
-
diff --git a/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch b/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch
new file mode 100644
index 0000000..81cd2f8
--- /dev/null
+++ b/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch
@@ -0,0 +1,1954 @@
+From d56362d85ecd6ce9921a67c2f4252d01c26a71af Mon Sep 17 00:00:00 2001
+From: Ajay Garg <ajay@activitycentral.com>
+Date: Tue, 4 Sep 2012 18:16:19 +0530
+Subject: [sugar PATCH] 1-to-N-feature via Peer-to-Peer mechanism; and Via-School-Server mechanism.
+Organization: Sugar Labs Foundation
+Signed-off-by: Ajay Garg <ajay@activitycentral.com>
+---
+ src/jarabe/frame/activitiestray.py | 5 +
+ src/jarabe/frame/frame.py | 3 +
+ src/jarabe/intro/window.py | 12 +
+ src/jarabe/journal/expandedentry.py | 24 ++-
+ src/jarabe/journal/journalactivity.py | 17 ++-
+ src/jarabe/journal/journaltoolbox.py | 44 ++++-
+ src/jarabe/journal/model.py | 375 ++++++++++++++++++++++-----------
+ src/jarabe/journal/palettes.py | 283 ++++++++++++++++++++++---
+ src/jarabe/journal/volumestoolbar.py | 92 ++++++---
+ src/jarabe/journal/webdavmanager.py | 172 ++++++++++-----
+ src/jarabe/view/buddymenu.py | 45 ++++-
+ src/jarabe/view/palettes.py | 38 ++--
+ src/webdav/Connection.py | 11 +-
+ src/webdav/WebdavClient.py | 16 +-
+ src/webdav/davlib.py | 9 +-
+ 15 files changed, 867 insertions(+), 279 deletions(-)
+
+diff --git a/src/jarabe/frame/activitiestray.py b/src/jarabe/frame/activitiestray.py
+index 55e0c31..7cbeefb 100644
+--- a/src/jarabe/frame/activitiestray.py
++++ b/src/jarabe/frame/activitiestray.py
+@@ -249,6 +249,8 @@ class ActivitiesTray(HTray):
+ # JournalActivity is always the first activity to be added.
+ # Broadcast the signal-of-its-creation.
+ if group is None:
++ self._journal_button = button
++ self._journal_activity = home_activity
+ self._signal_addition_of_journal_activity()
+
+ def _signal_addition_of_journal_activity(self):
+@@ -306,6 +308,9 @@ class ActivitiesTray(HTray):
+ if window:
+ window.activate(gtk.get_current_event_time())
+
++ def _show_journal_activity(self):
++ self.__activity_clicked_cb(self._journal_button, self._journal_activity)
++
+ def __remove_invite_cb(self, icon, invite):
+ self._invites.remove_invite(invite)
+
+diff --git a/src/jarabe/frame/frame.py b/src/jarabe/frame/frame.py
+index cd1dc20..821e31f 100644
+--- a/src/jarabe/frame/frame.py
++++ b/src/jarabe/frame/frame.py
+@@ -449,3 +449,6 @@ class Frame(object):
+ # Do nothing for now. Our notification UI is so simple, there's no
+ # point yet.
+ pass
++
++ def switch_to_journal_activity(self):
++ self._activities_tray._show_journal_activity()
+diff --git a/src/jarabe/intro/window.py b/src/jarabe/intro/window.py
+index df19fbf..c4ae56e 100644
+--- a/src/jarabe/intro/window.py
++++ b/src/jarabe/intro/window.py
+@@ -56,6 +56,18 @@ def create_profile(name, color=None):
+ else:
+ logging.error('Keypair exists, skip generation.')
+
++ # Also, generate SSL key and cert pair; to be used in secure
++ # sharing of webdav entries via httpd.
++ keypath = os.path.join(env.get_profile_path(), 'ssl.key')
++ certpath = os.path.join(env.get_profile_path(), 'ssl.crt')
++
++ cmd = 'openssl req -new -newkey rsa:1024 -days 365 -nodes ' + \
++ '-x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" ' + \
++ '-keyout %s -out %s' % (keypath, certpath)
++ (s, o) = commands.getstatusoutput(cmd)
++ if s != 0:
++ logging.error('Could not generate ssl key and cert: %d %s', s, o)
++
+
+ class _Page(hippo.CanvasBox):
+ __gproperties__ = {
+diff --git a/src/jarabe/journal/expandedentry.py b/src/jarabe/journal/expandedentry.py
+index 03f8cd1..1e857ba 100644
+--- a/src/jarabe/journal/expandedentry.py
++++ b/src/jarabe/journal/expandedentry.py
+@@ -166,13 +166,35 @@ class ExpandedEntry(hippo.CanvasBox):
+ self._buddy_list.append(self._create_buddy_list())
+
+ description = self._description.text_view_widget
+- description.props.buffer.props.text = metadata.get('description', '')
++
++ # TRANS: Do not translate the """%s""".
++ uploader_nick_text = self.__create_text_description(
++ _('Source XO Nick :: \n%s'), metadata.get('uploader-nick', ''))
++
++ # TRANS: Do not translate the """%s""".
++ uploader_serial_text = self.__create_text_description(
++ _('Source XO Serial Number :: \n%s'), metadata.get('uploader-serial', ''))
++
++ # TRANS: Do not translate the """%s""".
++ misc_info_text = self.__create_text_description(
++ _('Misellaneous Information :: \n%s'), metadata.get('description', ''))
++
++ description.props.buffer.props.text = uploader_nick_text + \
++ uploader_serial_text + \
++ misc_info_text
++
+ description.props.editable = model.is_editable(metadata)
+
+ tags = self._tags.text_view_widget
+ tags.props.buffer.props.text = metadata.get('tags', '')
+ tags.props.editable = model.is_editable(metadata)
+
++ def __create_text_description(self, heading, value):
++ if (value == '') or (value is None):
++ return ''
++
++ return ((heading % value) + '\n\n')
++
+ def _create_keep_icon(self):
+ keep_icon = KeepIcon(False)
+ keep_icon.connect('activated', self._keep_icon_activated_cb)
+diff --git a/src/jarabe/journal/journalactivity.py b/src/jarabe/journal/journalactivity.py
+index fc4773d..5f2a734 100644
+--- a/src/jarabe/journal/journalactivity.py
++++ b/src/jarabe/journal/journalactivity.py
+@@ -180,10 +180,14 @@ class JournalActivity(JournalWindow):
+ self._check_available_space()
+
+ def __volume_error_cb(self, gobject, message, severity):
+- alert = ErrorAlert(title=severity, msg=message)
+- alert.connect('response', self.__alert_response_cb)
+- self.add_alert(alert)
+- alert.show()
++ self.update_title_and_message(self._error_alert, severity,
++ message)
++ self._callback = None
++ self._data = None
++ self.update_alert(self._error_alert)
++
++ def _show_alert(self, message, severity):
++ self.__volume_error_cb(None, message, severity)
+
+ def _volume_error_cb(self, gobject, message, severity):
+ self.update_error_alert(severity, message, None, None)
+@@ -449,6 +453,8 @@ class JournalActivity(JournalWindow):
+ self.remove_alert(self._current_alert)
+ self.add_alert(alert)
+
++ self.remove_alert(self._current_alert)
++ self.add_alert(alert)
+ self._current_alert = alert
+ self._current_alert.show()
+ show_normal_cursor()
+@@ -475,6 +481,9 @@ class JournalActivity(JournalWindow):
+ self._data = data
+ self.update_alert(self._confirmation_alert)
+
++ def update_progress(self, fraction):
++ self.get_toolbar_box().update_progress(fraction)
++
+ def get_metadata_list(self, selected_state):
+ metadata_list = []
+
+diff --git a/src/jarabe/journal/journaltoolbox.py b/src/jarabe/journal/journaltoolbox.py
+index 6b2494e..b1c0cac 100644
+--- a/src/jarabe/journal/journaltoolbox.py
++++ b/src/jarabe/journal/journaltoolbox.py
+@@ -78,6 +78,16 @@ class MainToolbox(Toolbox):
+ self.add_toolbar(_('Search'), self.search_toolbar)
+ self.search_toolbar.show()
+
++ self._info_widget = MultiSelectEntriesInfoWidget()
++ self.add(self._info_widget)
++ self._info_widget.hide()
++
++ def update_progress(self, fraction):
++ self._info_widget.update_progress(fraction)
++
++ def hide_info_widget(self):
++ self._info_widget.hide()
++
+
+ class SearchToolbar(gtk.Toolbar):
+ __gtype_name__ = 'SearchToolbar'
+@@ -532,6 +542,9 @@ class EditToolbox(Toolbox):
+ def get_current_entry_number(self):
+ return self.edit_toolbar._get_current_entry_number()
+
++ def update_progress(self, fraction):
++ self.edit_toolbar.get_multi_select_info_widget().update_progress(fraction)
++
+
+ class EditToolbar(gtk.Toolbar):
+ def __init__(self):
+@@ -552,6 +565,9 @@ class EditToolbar(gtk.Toolbar):
+
+ self.show_all()
+
++ def get_multi_select_info_widget(self):
++ return self._multi_select_info_widget
++
+ def _set_total_number_of_entries(self, total):
+ self._multi_select_info_widget.set_total_number_of_entries(total)
+
+@@ -703,16 +719,40 @@ class MultiSelectEntriesInfoWidget(gtk.ToolItem):
+ def __init__(self):
+ gtk.ToolItem.__init__(self)
+
++ self._box = gtk.VBox()
+ self._selected_entries = 0
+
+ self._label = gtk.Label()
+- self.add(self._label)
++ self._box.pack_start(self._label, expand=False)
++
++ self._progress_label = gtk.Label()
++ self._box.pack_start(self._progress_label, expand=False)
++
++ self.add(self._box)
+
+ self.show_all()
++ self._box.show_all()
++ self._progress_label.hide()
+
+ def set_total_number_of_entries(self, total):
+ self._total = total
+
++ def update_progress(self, fraction):
++ percent = '%.02f' % (fraction * 100)
++
++ # TRANS: Do not translate %.02f
++ text = '%.02f%% complete' % (fraction * 100)
++ if (str(percent) != '100.00') and (str(percent).endswith('00')):
++ self._progress_label.set_text(text)
++ self._progress_label.show()
++ self.show_all()
++ gtk.gdk.window_process_all_updates()
++ else:
++ self._progress_label.hide()
++ from jarabe.journal.journalactivity import get_journal
++ if not get_journal().is_editing_mode_present():
++ self.hide()
++
+ def update_text(self, primary_text, secondary_text, special_action,
+ update_selected_entries):
+ # If "special_action" is None,
+@@ -749,6 +789,8 @@ class MultiSelectEntriesInfoWidget(gtk.ToolItem):
+ self._label.set_text(message)
+ self._label.show()
+
++ gtk.gdk.window_process_all_updates()
++
+ def get_current_entry_number(self):
+ return self._selected_entries
+
+diff --git a/src/jarabe/journal/model.py b/src/jarabe/journal/model.py
+index 422e947..c06b2ee 100644
+--- a/src/jarabe/journal/model.py
++++ b/src/jarabe/journal/model.py
+@@ -43,7 +43,7 @@ from sugar import dispatch
+ from sugar import mime
+ from sugar import util
+
+-from jarabe.journal.webdavmanager import get_remote_webdav_share_metadata
++from jarabe.journal import webdavmanager
+
+ DS_DBUS_SERVICE = 'org.laptop.sugar.DataStore'
+ DS_DBUS_INTERFACE = 'org.laptop.sugar.DataStore'
+@@ -58,6 +58,9 @@ PROPERTIES = ['activity', 'activity_id', 'buddies', 'bundle_id',
+ MIN_PAGES_TO_CACHE = 3
+ MAX_PAGES_TO_CACHE = 5
+
++WEBDAV_MOUNT_POINT = '/tmp/'
++LOCAL_SHARES_MOUNT_POINT = '/var/www/web1/web/'
++
+ JOURNAL_METADATA_DIR = '.Sugar-Metadata'
+
+ _datastore = None
+@@ -66,6 +69,52 @@ updated = dispatch.Signal()
+ deleted = dispatch.Signal()
+
+
++SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME_PATH = \
++ '/desktop/sugar/network/school_server_ip_address_or_dns_name'
++
++client = gconf.client_get_default()
++SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME = client.get_string(SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME_PATH) or '127.0.0.1'
++
++
++def _get_mount_point(path):
++ dir_path = os.path.dirname(path)
++ while dir_path:
++ if os.path.ismount(dir_path):
++ return dir_path
++ else:
++ dir_path = dir_path.rsplit(os.sep, 1)[0]
++ return None
++
++
++def is_mount_point_for_school_server(mount_point):
++ from jarabe.journal.journalactivity import get_journal
++ from jarabe.journal.volumestoolbar import SHARE_TYPE_SCHOOL_SERVER
++
++ mount_point_button = get_journal().get_volumes_toolbar()._get_button_for_mount_point(mount_point)
++ if mount_point_button._share_type == SHARE_TYPE_SCHOOL_SERVER:
++ return True
++ return False
++
++
++def extract_ip_address_or_dns_name_from_locally_mounted_remote_share_path(path):
++ """
++ Path is of type ::
++
++ /tmp/1.2.3.4/webdav/a.txt; OR
++ /tmp/this.is.dns.name/a.txt
++ """
++ return path.split('/')[2]
++
++
++def is_mount_point_for_locally_mounted_remote_share(mount_point):
++ """
++ The mount-point can be either of the ip-Address, or the DNS name.
++ More importantly, whatever the "name" be, it does NOT have a
++ forward-slash.
++ """
++ return mount_point.find(WEBDAV_MOUNT_POINT) == 0
++
++
+ class _Cache(object):
+
+ __gtype_name__ = 'model_Cache'
+@@ -430,8 +479,8 @@ class InplaceResultSet(BaseResultSet):
+
+
+ class RemoteShareResultSet(object):
+- def __init__(self, ip_address, query):
+- self._ip_address = ip_address
++ def __init__(self, ip_address_or_dns_name, query):
++ self._ip_address_or_dns_name = ip_address_or_dns_name
+ self._file_list = []
+
+ self.ready = dispatch.Signal()
+@@ -464,7 +513,11 @@ class RemoteShareResultSet(object):
+ self._sort = query.get('order_by', ['+timestamp'])[0]
+
+ def setup(self):
+- metadata_list_complete = get_remote_webdav_share_metadata(self._ip_address)
++ try:
++ metadata_list_complete = webdavmanager.get_remote_webdav_share_metadata(self._ip_address_or_dns_name)
++ except Exception, e:
++ metadata_list_complete = []
++
+ for metadata in metadata_list_complete:
+
+ add_to_list = False
+@@ -553,15 +606,8 @@ def _get_file_metadata(path, stat, fetch_preview=True):
+ metadata based on the file properties.
+
+ """
+- filename = os.path.basename(path)
+- dir_path = os.path.dirname(path)
+- metadata = _get_file_metadata_from_json(dir_path, filename, fetch_preview)
++ metadata = _get_file_metadata_from_json(path, fetch_preview)
+ if metadata:
+- # For Documents/Shares/Mounted-Drives.
+- # Special case: for locally-mounted-remote-files, ensure that
+- # "metadata['filesize' is already present before-hand. This
+- # will have to be done at the time of fetching
+- # webdav-properties per resource.
+ if 'filesize' not in metadata:
+ if stat is not None:
+ metadata['filesize'] = stat.st_size
+@@ -582,17 +628,26 @@ def _get_file_metadata(path, stat, fetch_preview=True):
+ 'description': path}
+
+
+-def _get_file_metadata_from_json(dir_path, filename, fetch_preview):
++def _get_file_metadata_from_json(path, fetch_preview):
+ """Read the metadata from the json file and the preview
+ stored on the external device.
+
+ If the metadata is corrupted we do remove it and the preview as well.
+
+ """
++ filename = os.path.basename(path)
++ dir_path = os.path.dirname(path)
++
++ # In case of nested mount-points, (eg. ~/Documents/in1/in2/in3.txt),
++ # "dir_path = ~/Documents/in1/in2"; while
++ # "metadata_dir_path = ~/Documents".
++ from jarabe.journal.journalactivity import get_mount_point
++ metadata_dir_path = get_mount_point()
++
+ metadata = None
+- metadata_path = os.path.join(dir_path, JOURNAL_METADATA_DIR,
++ metadata_path = os.path.join(metadata_dir_path, JOURNAL_METADATA_DIR,
+ filename + '.metadata')
+- preview_path = os.path.join(dir_path, JOURNAL_METADATA_DIR,
++ preview_path = os.path.join(metadata_dir_path, JOURNAL_METADATA_DIR,
+ filename + '.preview')
+
+ if not os.path.exists(metadata_path):
+@@ -670,7 +725,8 @@ def find(query_, page_size):
+ Regex Matching is used, to ensure that the mount-point is an
+ IP-Address.
+ """
+- return RemoteShareResultSet(mount_points[0], query)
++ ip_address = extract_ip_address_or_dns_name_from_locally_mounted_remote_share_path(mount_points[0])
++ return RemoteShareResultSet(ip_address, query)
+ else:
+ """
+ For Documents/Shares/Mounted-Drives.
+@@ -678,56 +734,13 @@ def find(query_, page_size):
+ return InplaceResultSet(query, page_size, mount_points[0])
+
+
+-def is_mount_point_for_locally_mounted_remote_share(mount_point):
+- import re
+-
+- pattern = '[1-9][0-9]{0,2}\.[0-9]{0,3}\.[0-9]{0,3}\.[0-9]{0,3}'
+- if re.match(pattern, mount_point) is None:
+- return False
+- return True
+-
+-
+-def _get_mount_point(path):
+- dir_path = os.path.dirname(path)
+- while dir_path:
+- if os.path.ismount(dir_path):
+- return dir_path
+- else:
+- dir_path = dir_path.rsplit(os.sep, 1)[0]
+- return None
+-
+-
+-def is_locally_mounted_remote_share(path):
+- return string.find(path, '/tmp/') == 0
+-
+-
+-def extract_ip_address_from_locally_mounted_remote_share_path(path):
+- """
+- Path is of type ::
+-
+- /tmp/127.0.0.1/webdav/a.txt
+- """
+- return path.split('/')[2]
+-
+-
+ def get(object_id):
+ """Returns the metadata for an object
+ """
+ if (object_id[0] == '/'):
+- """
+- For Documents/Shares/Mounted-Drives/Locally-Mounted-Remote-Shares,
+- where ".Sugar-Metadata" folder exists.
+-
+- The only thing is that, for locally-mounted-remote-shares, the
+- "file" is not physically present.
+- """
+ if os.path.exists(object_id):
+- # if the file is physically present, derive filesize-metadata
+- # by physical examination of the file.
+ stat = os.stat(object_id)
+ else:
+- # if the file is remote, derive file-metadata by fetching
+- # properties remotely (webdav properties).
+ stat = None
+
+ metadata = _get_file_metadata(object_id, stat)
+@@ -812,7 +825,21 @@ def delete(object_id):
+ def copy(metadata, mount_point):
+ """Copies an object to another mount point
+ """
++ # In all cases (except one), "copy" means the actual duplication of
++ # the content.
++ # Only in case of remote downloading, the content is first copied
++ # to "/tmp" folder. In those cases, copying would refer to a mere
++ # renaming.
++ transfer_ownership = False
++
++ from jarabe.journal.journalactivity import get_mount_point
++ current_mount_point = get_mount_point()
++
++ if is_mount_point_for_locally_mounted_remote_share(current_mount_point):
++ transfer_ownership = True
++
+ metadata = get(metadata['uid'])
++
+ if mount_point == '/' and metadata['icon-color'] == '#000000,#ffffff':
+ client = gconf.client_get_default()
+ metadata['icon-color'] = client.get_string('/desktop/sugar/user/color')
+@@ -823,7 +850,7 @@ def copy(metadata, mount_point):
+ metadata['mountpoint'] = mount_point
+ del metadata['uid']
+
+- return write(metadata, file_path, transfer_ownership=False)
++ return write(metadata, file_path, transfer_ownership=transfer_ownership)
+
+
+ def write(metadata, file_path='', update_mtime=True, transfer_ownership=True):
+@@ -845,27 +872,105 @@ def write(metadata, file_path='', update_mtime=True, transfer_ownership=True):
+ object_id = _get_datastore().create(dbus.Dictionary(metadata),
+ file_path,
+ transfer_ownership)
+- else:
+- # HACK: For documents: modify the mount-point
+- from jarabe.journal.journalactivity import get_mount_point
+- if get_mount_point() == get_documents_path():
+- metadata['mountpoint'] = get_documents_path()
++ elif metadata.get('mountpoint', '/') == WEBDAV_MOUNT_POINT:
++ filename = metadata['title']
++
++ ip_address_or_dns_name = SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME
++ webdavmanager.get_remote_webdav_share_metadata(ip_address_or_dns_name)
++
++ data_webdav_manager = \
++ webdavmanager.get_data_webdav_manager(ip_address_or_dns_name)
++ metadata_webdav_manager = \
++ webdavmanager.get_metadata_webdav_manager(ip_address_or_dns_name)
++
++
++ # If we get a resource by this name, there is already an entry
++ # on the server with this name; we do not want to do any
++ # overwrites.
++ data_resource = webdavmanager.get_resource_by_resource_key(data_webdav_manager,
++ '/webdav/' + filename)
++ metadata_resource = webdavmanager.get_resource_by_resource_key(metadata_webdav_manager,
++ '/webdav/.Sugar-Metadata/' + filename + '.metadata')
++ if (data_resource is not None) or (metadata_resource is not None):
++ raise Exception(_('Entry already present on the server with '
++ 'this name. Try again after renaming.'))
++
++ # No entry for this name present.
++ # So, first write the metadata- and preview-file to temporary
++ # locations.
++ metadata_file_path, preview_file_path = \
++ _write_metadata_and_preview_files_and_return_file_paths(metadata,
++ filename)
++
++ # Finally,
++ # Upload the data file.
++ webdavmanager.add_resource_by_resource_key(data_webdav_manager,
++ filename,
++ file_path)
++
++ # Upload the preview file.
++ if preview_file_path is not None:
++ webdavmanager.add_resource_by_resource_key(metadata_webdav_manager,
++ filename + '.preview',
++ preview_file_path)
++
++ # Upload the metadata file.
++ #
++ # Note that this needs to be the last step. If there was any
++ # error uploading the data- or the preview-file, control would
++ # not reach here.
++ #
++ # In other words, the control reaches here only if the data-
++ # and the preview- files have been uploaded. Finally, IF this
++ # file is successfully uploaded, we have the guarantee that all
++ # files for a particular journal entry are in place.
++ webdavmanager.add_resource_by_resource_key(metadata_webdav_manager,
++ filename + '.metadata',
++ metadata_file_path)
++
++
++ object_id = 'doesn\'t matter'
+
+- object_id = _write_entry_on_external_device(metadata, file_path)
++ else:
++ object_id = _write_entry_on_external_device(metadata,
++ file_path,
++ transfer_ownership)
+
+ return object_id
+
+
+-def _rename_entry_on_external_device(file_path, destination_path,
+- metadata_dir_path):
++def make_file_fully_permissible(file_path):
++ fd = os.open(file_path, os.O_RDONLY)
++ os.fchmod(fd, stat.S_IRWXU | stat.S_IRWXG |stat.S_IRWXO)
++ os.close(fd)
++
++
++def _rename_entry_on_external_device(file_path, destination_path):
+ """Rename an entry with the associated metadata on an external device."""
+ old_file_path = file_path
+ if old_file_path != destination_path:
+- os.rename(file_path, destination_path)
++ # Strangely, "os.rename" works fine on sugar-jhbuild, but fails
++ # on XOs, wih the OSError 13 ("invalid cross-device link"). So,
++ # using the system call "mv".
++ os.system('mv "%s" "%s"' % (file_path, destination_path))
++ make_file_fully_permissible(destination_path)
++
++
++ # In renaming, we want to delete the metadata-, and preview-
++ # files of the current mount-point, and not the destination
++ # mount-point.
++ # But we also need to ensure that the directory of
++ # 'old_file_path' and 'destination_path' are not same.
++ if os.path.dirname(old_file_path) == os.path.dirname(destination_path):
++ return
++
++ from jarabe.journal.journalactivity import get_mount_point
++ source_metadata_dir_path = get_mount_point() + '/.Sugar-Metadata'
++
+ old_fname = os.path.basename(file_path)
+- old_files = [os.path.join(metadata_dir_path,
++ old_files = [os.path.join(source_metadata_dir_path,
+ old_fname + '.metadata'),
+- os.path.join(metadata_dir_path,
++ os.path.join(source_metadata_dir_path,
+ old_fname + '.preview')]
+ for ofile in old_files:
+ if os.path.exists(ofile):
+@@ -876,41 +981,32 @@ def _rename_entry_on_external_device(file_path, destination_path,
+ 'for file=%s', ofile, old_fname)
+
+
+-def _write_entry_on_external_device(metadata, file_path):
+- """Create and update an entry copied from the
+- DS to an external storage device.
+-
+- Besides copying the associated file a file for the preview
+- and one for the metadata are stored in the hidden directory
+- .Sugar-Metadata.
+-
+- This function handles renames of an entry on the
+- external device and avoids name collisions. Renames are
+- handled failsafe.
++def _write_metadata_and_preview_files_and_return_file_paths(metadata,
++ file_name):
++ metadata_copy = metadata.copy()
++ metadata_copy.pop('mountpoint', None)
++ metadata_copy.pop('uid', None)
+
+- """
+- if 'uid' in metadata and os.path.exists(metadata['uid']):
+- file_path = metadata['uid']
+
+- if not file_path or not os.path.exists(file_path):
+- raise ValueError('Entries without a file cannot be copied to '
+- 'removable devices')
++ # For copying to School-Server, we need to retain this property.
++ # Else wise, I have no idea why this property is being removed !!
++ if (metadata.get('mountpoint', '/') != WEBDAV_MOUNT_POINT) and \
++ (metadata.get('mountpoint', '/') != LOCAL_SHARES_MOUNT_POINT):
++ metadata_copy.pop('filesize', None)
+
+- if not metadata.get('title'):
+- metadata['title'] = _('Untitled')
+- file_name = get_file_name(metadata['title'], metadata['mime_type'])
+-
+- destination_path = os.path.join(metadata['mountpoint'], file_name)
+- if destination_path != file_path:
+- file_name = get_unique_file_name(metadata['mountpoint'], file_name)
+- destination_path = os.path.join(metadata['mountpoint'], file_name)
+- clean_name, extension_ = os.path.splitext(file_name)
+- metadata['title'] = clean_name
++ # For journal case, there is the special treatment.
++ if metadata.get('mountpoint', '/') == '/':
++ if metadata.get('uid', ''):
++ object_id = _get_datastore().update(metadata['uid'],
++ dbus.Dictionary(metadata),
++ '',
++ False)
++ else:
++ object_id = _get_datastore().create(dbus.Dictionary(metadata),
++ '',
++ False)
++ return
+
+- metadata_copy = metadata.copy()
+- metadata_copy.pop('mountpoint', None)
+- metadata_copy.pop('uid', None)
+- metadata_copy.pop('filesize', None)
+
+ metadata_dir_path = os.path.join(metadata['mountpoint'],
+ JOURNAL_METADATA_DIR)
+@@ -939,25 +1035,64 @@ def _write_entry_on_external_device(metadata, file_path):
+ os.close(fh)
+ os.rename(fn, os.path.join(metadata_dir_path, preview_fname))
+
+- if not os.path.dirname(destination_path) == os.path.dirname(file_path):
+- shutil.copy(file_path, destination_path)
++ metadata_destination_path = os.path.join(metadata_dir_path, file_name + '.metadata')
++ make_file_fully_permissible(metadata_destination_path)
++ if preview:
++ preview_destination_path = os.path.join(metadata_dir_path, preview_fname)
++ make_file_fully_permissible(preview_destination_path)
+ else:
+- _rename_entry_on_external_device(file_path, destination_path,
+- metadata_dir_path)
++ preview_destination_path = None
+
+- # For "Shares" folder, we need to set the permissions of the newly
+- # copied file to 0777, else it will not be accessible by "httpd"
+- # service.
+- if metadata['mountpoint'] == '/var/www/web1/web':
+- fd = os.open(destination_path, os.O_RDONLY)
+- os.fchmod(fd, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
+- os.close(fd)
++ return (metadata_destination_path, preview_destination_path)
+
+- metadata_file_path = os.path.join(metadata_dir_path, file_name + '.metadata')
+- fd = os.open(metadata_file_path, os.O_RDONLY)
+- os.fchmod(fd, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
+- os.close(fd)
+
++def update_only_metadata_and_preview_files_and_return_file_paths(metadata):
++ file_name = get_file_name(metadata['title'], metadata['mime_type'])
++ _write_metadata_and_preview_files_and_return_file_paths(metadata,
++ file_name)
++
++
++def _write_entry_on_external_device(metadata, file_path,
++ transfer_ownership):
++ """Create and update an entry copied from the
++ DS to an external storage device.
++
++ Besides copying the associated file a file for the preview
++ and one for the metadata are stored in the hidden directory
++ .Sugar-Metadata.
++
++ This function handles renames of an entry on the
++ external device and avoids name collisions. Renames are
++ handled failsafe.
++
++ """
++ if 'uid' in metadata and os.path.exists(metadata['uid']):
++ file_path = metadata['uid']
++
++ if not file_path or not os.path.exists(file_path):
++ raise ValueError('Entries without a file cannot be copied to '
++ 'removable devices')
++
++ if not metadata.get('title'):
++ metadata['title'] = _('Untitled')
++ file_name = get_file_name(metadata['title'], metadata['mime_type'])
++
++ destination_path = os.path.join(metadata['mountpoint'], file_name)
++ if destination_path != file_path:
++ file_name = get_unique_file_name(metadata['mountpoint'], file_name)
++ destination_path = os.path.join(metadata['mountpoint'], file_name)
++ clean_name, extension_ = os.path.splitext(file_name)
++ metadata['title'] = clean_name
++
++ _write_metadata_and_preview_files_and_return_file_paths(metadata,
++ file_name)
++
++ if (os.path.dirname(destination_path) == os.path.dirname(file_path)) or \
++ (transfer_ownership == True):
++ _rename_entry_on_external_device(file_path, destination_path)
++ else:
++ shutil.copy(file_path, destination_path)
++ make_file_fully_permissible(destination_path)
+
+ object_id = destination_path
+ created.send(None, object_id=object_id)
+@@ -1013,7 +1148,11 @@ def is_editable(metadata):
+ # called, upon an entry in the context of a singular
+ # mount-point.
+ from jarabe.journal.journalactivity import get_mount_point
+- return os.access(get_mount_point(), os.W_OK)
++ mount_point = get_mount_point()
++
++ if is_mount_point_for_locally_mounted_remote_share(mount_point):
++ return False
++ return os.access(mount_point, os.W_OK)
+
+
+ def get_documents_path():
+diff --git a/src/jarabe/journal/palettes.py b/src/jarabe/journal/palettes.py
+index 66dcadc..91e5460 100644
+--- a/src/jarabe/journal/palettes.py
++++ b/src/jarabe/journal/palettes.py
+@@ -30,6 +30,7 @@ import gio
+ import glib
+ import time
+ import socket
++import dbus
+
+ from sugar import _sugarext
+
+@@ -44,14 +45,13 @@ from jarabe.model import friends
+ from jarabe.model import filetransfer
+ from jarabe.model import mimeregistry
+ from jarabe.journal import misc
+-from jarabe.journal import model
++from jarabe.journal import model, webdavmanager
+ from jarabe.journal.journalwindow import freeze_ui, \
+ unfreeze_ui, \
+ show_normal_cursor, \
+ show_waiting_cursor
+
+ from webdav.Connection import WebdavError
+-from jarabe.journal.webdavmanager import get_resource_by_ip_address_and_resource_key
+
+
+ friends_model = friends.get_model()
+@@ -59,6 +59,49 @@ friends_model = friends.get_model()
+ _copy_menu_helper = None
+ _current_action_item = None
+
++
++class PassphraseDialog(gtk.Dialog):
++ def __init__(self, callback, metadata):
++ gtk.Dialog.__init__(self, flags=gtk.DIALOG_MODAL)
++ self._callback = callback
++ self._metadata = metadata
++ self.set_title(_('Passphrase required'))
++ self.set_has_separator(False)
++
++ # TRANS: Please do not translate the '%s'.
++ label_text = _('Please enter the passphrase for %s' % metadata['title'])
++ label = gtk.Label(label_text)
++ self.vbox.pack_start(label)
++
++ self.add_buttons(gtk.STOCK_OK, gtk.RESPONSE_OK)
++ self.set_default_response(gtk.RESPONSE_OK)
++ self.set_has_separator(True)
++ self.add_key_entry()
++
++ self.connect('response', self._key_dialog_response_cb)
++ self.show_all()
++
++ def add_key_entry(self):
++ self._entry = gtk.Entry()
++ self._entry.connect('activate', self._entry_activate_cb)
++ self.vbox.pack_start(self._entry)
++ self.vbox.set_spacing(6)
++ self.vbox.show_all()
++
++ self._entry.grab_focus()
++
++ def _entry_activate_cb(self, entry):
++ self.response(gtk.RESPONSE_OK)
++
++ def get_response_object(self):
++ return self._response
++
++ def _key_dialog_response_cb(self, widget, response_id):
++ self.hide()
++ gobject.idle_add(self._callback, self._metadata,
++ self._entry.get_text())
++
++
+ class ObjectPalette(Palette):
+
+ __gtype_name__ = 'ObjectPalette'
+@@ -528,6 +571,7 @@ class ActionItem(gobject.GObject):
+ This is the stage, just after EVERY metadata has been
+ processed.
+ """
++ self._hide_info_widget_for_single_mode()
+
+ # Toggle the corresponding checkbox - but only for batch-mode.
+ if self._batch_mode and self._auto_deselect_source_entries:
+@@ -573,6 +617,25 @@ class ActionItem(gobject.GObject):
+ from jarabe.journal.journalactivity import get_journal
+ get_journal().get_list_view().refresh()
+
++ def _handle_single_mode_notification(self, message, severity):
++ from jarabe.journal.journalactivity import get_journal
++ journal = get_journal()
++
++ journal._show_alert(message, severity)
++ self._hide_info_widget_for_single_mode()
++
++ def _hide_info_widget_for_single_mode(self):
++ if (not self._batch_mode):
++ from jarabe.journal.journalactivity import get_journal
++ journal = get_journal()
++
++ journal.get_toolbar_box().hide_info_widget()
++
++ def _unhide_info_widget_for_single_mode(self):
++ if not self._batch_mode:
++ from jarabe.journal.journalactivity import get_journal
++ get_journal().update_progress(0)
++
+ def _handle_error_alert(self, error_message, metadata):
+ """
+ This handles any error scenarios. Examples are of entries that
+@@ -593,19 +656,11 @@ class ActionItem(gobject.GObject):
+
+ current_len = len(self._metadata_list)
+
+- # TRANS: Do not translate the two %d, and the three %s.
+- info_alert_message = _('( %d / %d ) Error while %s %s : %s') % (
+- self._metadata_list_initial_len - current_len,
+- self._metadata_list_initial_len,
+- self._get_info_alert_title(),
+- metadata['title'],
+- error_message)
+-
+ # Only show the alert, if allowed to.
+ if self._show_not_completed_ops_info:
+ from jarabe.journal.journalactivity import get_journal
+- get_journal().update_confirmation_alert(self._get_info_alert_title() + ' ...',
+- info_alert_message,
++ get_journal().update_confirmation_alert(_('Error'),
++ error_message,
+ self._process_error_skipping,
+ metadata)
+ else:
+@@ -639,19 +694,55 @@ class ActionItem(gobject.GObject):
+ if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
+ file_path = metadata['uid']
+ filename = os.path.basename(file_path)
+- ip_address = model.extract_ip_address_from_locally_mounted_remote_share_path(file_path)
+- resource = get_resource_by_ip_address_and_resource_key(ip_address, '/webdav/' + filename)
+- download_file_path = '/tmp/' + ip_address + '/' + filename
++ ip_address_or_dns_name = \
++ model.extract_ip_address_or_dns_name_from_locally_mounted_remote_share_path(file_path)
++
++ data_webdav_manager = \
++ webdavmanager.get_data_webdav_manager(ip_address_or_dns_name)
++ metadata_webdav_manager = \
++ webdavmanager.get_metadata_webdav_manager(ip_address_or_dns_name)
++
++ # Download the preview file, if it exists.
++ preview_resource = \
++ webdavmanager.get_resource_by_resource_key(metadata_webdav_manager,
++ '/webdav/.Sugar-Metadata/' + filename + '.preview')
++ preview_path = os.path.dirname(file_path) + '/.Sugar-Metadata/'+ filename + '.preview'
++
++ if preview_resource is not None:
++ try:
++ preview_resource.downloadFile(preview_path,
++ show_progress=False,
++ filesize=0)
++ except (WebdavError, socket.error), e:
++ error_message = e
++ logging.warn(error_message)
++ if self._batch_mode:
++ self._handle_error_alert(error_message, metadata)
++ else:
++ self._handle_single_mode_notification(error_message,
++ _('Error'))
++ return False
++
++ # If we manage to reach here, download the data file.
++ data_resource = \
++ webdavmanager.get_resource_by_resource_key(data_webdav_manager,
++ '/webdav/'+ filename)
+ try:
+- resource.downloadFile(download_file_path)
++ data_resource.downloadFile(metadata['uid'],
++ show_progress=True,
++ filesize=int(metadata['filesize']))
+ return True
+ except (WebdavError, socket.error), e:
++ # Delete the downloaded preview file, if it exists.
++ if os.path.exists(preview_path):
++ os.unlink(preview_path)
++
+ error_message = e
+ logging.warn(error_message)
+ if self._batch_mode:
+ self._handle_error_alert(error_message, metadata)
+ else:
+- self.emit('volume-error', error_message,
++ self._handle_single_mode_notification(error_message,
+ _('Error'))
+ return False
+
+@@ -662,7 +753,7 @@ class ActionItem(gobject.GObject):
+ if self._batch_mode:
+ self._handle_error_alert(error_message, metadata)
+ else:
+- self.emit('volume-error', error_message, _('Warning'))
++ self._handle_single_mode_notification(error_message, _('Warning'))
+ return False
+ else:
+ return True
+@@ -674,12 +765,12 @@ class ActionItem(gobject.GObject):
+ model.copy(metadata, mount_point)
+ return True
+ except Exception, e:
+- logging.exception('Error while copying the entry. %s', e)
++ logging.exception(e)
+ error_message = _('Error while copying the entry. %s') % e
+ if self._batch_mode:
+ self._handle_error_alert(error_message, metadata)
+ else:
+- self.emit('volume-error', error_message, _('Error'))
++ self._handle_single_mode_notification(error_message, _('Error'))
+ return False
+ finally:
+ self._set_bundle_installation_allowed(True)
+@@ -689,7 +780,7 @@ class ActionItem(gobject.GObject):
+ self._set_bundle_installation_allowed(False)
+
+ try:
+- model.write(metadata, update_mtime=False)
++ model.update_only_metadata_and_preview_files_and_return_file_paths(metadata)
+ return True
+ except Exception, e:
+ logging.exception('Error while writing the metadata. %s', e)
+@@ -698,7 +789,7 @@ class ActionItem(gobject.GObject):
+ if self._batch_mode:
+ self._handle_error_alert(error_message, metadata)
+ else:
+- self.emit('volume-error', error_message, _('Error'))
++ self._handle_single_mode_notification(error_message, _('Error'))
+ return False
+ finally:
+ self._set_bundle_installation_allowed(True)
+@@ -751,6 +842,30 @@ class BaseCopyMenuItem(MenuItem, ActionItem):
+ def _get_info_alert_title(self):
+ return _('Copying')
+
++ def _operate(self, metadata):
++ from jarabe.journal.journalactivity import get_mount_point
++ if(model.is_mount_point_for_locally_mounted_remote_share(get_mount_point())) \
++ and (model.is_mount_point_for_school_server(get_mount_point()) == True):
++ PassphraseDialog(self._proceed_after_receiving_passphrase, metadata)
++ else:
++ self._proceed_with_copy(metadata)
++
++ def _proceed_after_receiving_passphrase(self, metadata, passphrase):
++ if metadata['passphrase'] != passphrase:
++ error_message = _('Passphrase does not match.')
++ if self._batch_mode:
++ self._handle_error_alert(error_message, metadata)
++ else:
++ self._handle_single_mode_notification(error_message, _('Error'))
++ return False
++ else:
++ self._unhide_info_widget_for_single_mode()
++ gobject.idle_add(self._proceed_with_copy, metadata)
++
++ def _proceed_with_copy(self, metadata):
++ return NotImplementedError
++
++
+
+ class VolumeMenu(BaseCopyMenuItem):
+ def __init__(self, metadata_list, label, mount_point,
+@@ -761,9 +876,10 @@ class VolumeMenu(BaseCopyMenuItem):
+ show_progress_info_alert, batch_mode)
+ self._mount_point = mount_point
+
+- def _operate(self, metadata):
++ def _proceed_with_copy(self, metadata):
+ if not self._file_path_valid(metadata):
+ return False
++
+ if not self._metadata_copy_valid(metadata, self._mount_point):
+ return False
+
+@@ -780,7 +896,7 @@ class ClipboardMenu(BaseCopyMenuItem):
+ batch_mode)
+ self._temp_file_path_list = []
+
+- def _operate(self, metadata):
++ def _proceed_with_copy(self, metadata):
+ if not self._file_path_valid(metadata):
+ return False
+
+@@ -813,9 +929,10 @@ class DocumentsMenu(BaseCopyMenuItem):
+ show_progress_info_alert,
+ batch_mode)
+
+- def _operate(self, metadata):
++ def _proceed_with_copy(self, metadata):
+ if not self._file_path_valid(metadata):
+ return False
++
+ if not self._metadata_copy_valid(metadata,
+ model.get_documents_path()):
+ return False
+@@ -824,10 +941,41 @@ class DocumentsMenu(BaseCopyMenuItem):
+ self._post_operate_per_metadata_per_action(metadata)
+
+
+-class SharesMenu(BaseCopyMenuItem):
++class LocalSharesMenu(BaseCopyMenuItem):
++ def __init__(self, metadata_list, show_editing_alert,
++ show_progress_info_alert, batch_mode):
++ BaseCopyMenuItem.__init__(self, metadata_list, _('Local Shares'),
++ show_editing_alert,
++ show_progress_info_alert,
++ batch_mode)
++
++ def _proceed_with_copy(self, metadata):
++ if not self._file_path_valid(metadata):
++ return False
++
++ # Attach the filesize.
++ file_path = model.get_file(metadata['uid'])
++ metadata['filesize'] = os.stat(file_path).st_size
++
++ # Attach the current mount-point.
++ from jarabe.journal.journalactivity import get_mount_point
++ metadata['mountpoint'] = get_mount_point()
++
++ if not self._metadata_write_valid(metadata):
++ return False
++
++ if not self._metadata_copy_valid(metadata,
++ model.LOCAL_SHARES_MOUNT_POINT):
++ return False
++
++ # This is sync-operation. Call the post-operation now.
++ self._post_operate_per_metadata_per_action(metadata)
++
++
++class SchoolServerMenu(BaseCopyMenuItem):
+ def __init__(self, metadata_list, show_editing_alert,
+ show_progress_info_alert, batch_mode):
+- BaseCopyMenuItem.__init__(self, metadata_list, _('Shares'),
++ BaseCopyMenuItem.__init__(self, metadata_list, _('School Server'),
+ show_editing_alert,
+ show_progress_info_alert,
+ batch_mode)
+@@ -835,13 +983,75 @@ class SharesMenu(BaseCopyMenuItem):
+ def _operate(self, metadata):
+ if not self._file_path_valid(metadata):
+ return False
++
++ # If the entry is copyable, proceed with asking the
++ # upload-passphrase.
++ PassphraseDialog(self._proceed_after_receiving_passphrase, metadata)
++
++ def _proceed_after_receiving_passphrase(self, metadata, passphrase):
++ self._unhide_info_widget_for_single_mode()
++ gobject.idle_add(self._proceed_with_uploading, metadata,
++ passphrase)
++
++ def _proceed_with_uploading(self, metadata, passphrase):
++ #
++ # Attach the passphrase.
++ metadata['passphrase'] = passphrase
++
++ # Attach the filesize.
++ file_path = model.get_file(metadata['uid'])
++ metadata['filesize'] = os.stat(file_path).st_size
++
++ # Attach the current mount-point.
++ from jarabe.journal.journalactivity import get_mount_point, \
++ get_journal
++ metadata['mountpoint'] = get_mount_point()
++
++ # Attach the info of the uploader.
++ from jarabe.model.buddy import get_owner_instance
++ metadata['uploader-nick'] = get_owner_instance().props.nick
++ metadata['uploader-serial'] = self.__get_serial_number()
++
++ if not self._metadata_write_valid(metadata):
++ return False
++
+ if not self._metadata_copy_valid(metadata,
+- '/var/www/web1/web'):
++ model.WEBDAV_MOUNT_POINT):
+ return False
+
+ # This is sync-operation. Call the post-operation now.
+ self._post_operate_per_metadata_per_action(metadata)
+
++ def __get_serial_number(self):
++ _OFW_TREE = '/ofw'
++ _PROC_TREE = '/proc/device-tree'
++ _SN = 'serial-number'
++ _not_available = _('Not available')
++
++ serial_no = None
++ if os.path.exists(os.path.join(_OFW_TREE, _SN)):
++ serial_no = self.__read_file(os.path.join(_OFW_TREE, _SN))
++ elif os.path.exists(os.path.join(_PROC_TREE, _SN)):
++ serial_no = self.__read_file(os.path.join(_PROC_TREE, _SN))
++
++ if serial_no is None:
++ serial_no = _not_available
++ return serial_no
++
++ def __read_file(self, path):
++ if os.access(path, os.R_OK) == 0:
++ return None
++
++ fd = open(path, 'r')
++ value = fd.read()
++ fd.close()
++ if value:
++ value = value.strip('\n')
++ return value
++ else:
++ logging.debug('No information in file or directory: %s', path)
++ return None
++
+
+ class FriendsMenu(gtk.Menu):
+ __gtype_name__ = 'JournalFriendsMenu'
+@@ -970,12 +1180,23 @@ class CopyMenuHelper(gtk.Menu):
+ menu.append(documents_menu)
+ documents_menu.show()
+
+- if get_mount_point() != '/var/www/web1/web':
+- documents_menu = SharesMenu(metadata_list,
++ if get_mount_point() != model.LOCAL_SHARES_MOUNT_POINT:
++ local_shares_menu = LocalSharesMenu(metadata_list,
++ show_editing_alert,
++ show_progress_info_alert,
++ batch_mode)
++ local_shares_menu.set_image(Icon(icon_name='emblem-neighborhood-shared',
++ icon_size=gtk.ICON_SIZE_MENU))
++ local_shares_menu.connect('volume-error', self.__volume_error_cb)
++ menu.append(local_shares_menu)
++ local_shares_menu.show()
++
++ if not model.is_mount_point_for_locally_mounted_remote_share(get_mount_point()):
++ documents_menu = SchoolServerMenu(metadata_list,
+ show_editing_alert,
+ show_progress_info_alert,
+ batch_mode)
+- documents_menu.set_image(Icon(icon_name='emblem-neighborhood-shared',
++ documents_menu.set_image(Icon(icon_name='school-server',
+ icon_size=gtk.ICON_SIZE_MENU))
+ documents_menu.connect('volume-error', self.__volume_error_cb)
+ menu.append(documents_menu)
+diff --git a/src/jarabe/journal/volumestoolbar.py b/src/jarabe/journal/volumestoolbar.py
+index c24475d..b004657 100644
+--- a/src/jarabe/journal/volumestoolbar.py
++++ b/src/jarabe/journal/volumestoolbar.py
+@@ -37,7 +37,6 @@ from sugar.graphics.palette import Palette
+ from sugar.graphics.xocolor import XoColor
+ from sugar import env
+
+-from jarabe.frame.notification import NotificationIcon
+ from jarabe.journal import model
+ from jarabe.view.palettes import JournalVolumePalette, JournalXSPalette, RemoteSharePalette
+ import jarabe.frame
+@@ -45,6 +44,9 @@ import jarabe.frame
+
+ _JOURNAL_0_METADATA_DIR = '.olpc.store'
+
++SHARE_TYPE_PEER = 1
++SHARE_TYPE_SCHOOL_SERVER = 2
++
+
+ def _get_id(document):
+ """Get the ID for the document in the xapian database."""
+@@ -211,7 +213,13 @@ class VolumesToolbar(gtk.Toolbar):
+
+ def _set_up_volumes(self):
+ self._set_up_documents_button()
+- self._set_up_shares_button()
++ self._set_up_local_shares_button()
++
++ client = gconf.client_get_default()
++ color = XoColor(client.get_string('/desktop/sugar/user/color'))
++ self._add_remote_share_button(_('School-Server Shares'),
++ model.SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME,
++ color, SHARE_TYPE_SCHOOL_SERVER)
+
+ volume_monitor = gio.volume_monitor_get()
+ self._mount_added_hid = volume_monitor.connect('mount-added',
+@@ -242,18 +250,28 @@ class VolumesToolbar(gtk.Toolbar):
+ 'user-documents',
+ _('Documents'))
+
+- def _set_up_shares_button(self):
+- shares_dir_path = '/var/www/web1/web'
+- self._set_up_directory_button(shares_dir_path,
++ def _set_up_local_shares_button(self):
++ local_shares_path = model.LOCAL_SHARES_MOUNT_POINT
++ self._set_up_directory_button(local_shares_path,
+ 'emblem-neighborhood-shared',
+- _('Shares'))
+-
+- def _add_remote_share_button(self, buddy):
+- button = RemoteSharesButton(buddy)
++ _('Local Shares'))
++
++ def _add_remote_share_button(self, primary_text,
++ ip_address_or_dns_name, color,
++ share_type):
++ button = RemoteSharesButton(primary_text, ip_address_or_dns_name,
++ color, share_type)
++ button._share_type = share_type
+ button.props.group = self._volume_buttons[0]
+- label = glib.markup_escape_text(_('%s\'s share') % \
+- buddy.props.nick)
+- button.set_palette(RemoteSharePalette(buddy, button))
++
++ show_unmount_option = None
++ if share_type == SHARE_TYPE_PEER:
++ show_unmount_option = True
++ else:
++ show_unmount_option = False
++ button.set_palette(RemoteSharePalette(primary_text,
++ ip_address_or_dns_name, button,
++ show_unmount_option))
+ button.connect('toggled', self._button_toggled_cb)
+ button.show()
+
+@@ -262,12 +280,7 @@ class VolumesToolbar(gtk.Toolbar):
+ self._volume_buttons.append(button)
+ self.show()
+
+- frame = jarabe.frame.get_view()
+- notif_icon = NotificationIcon()
+- notif_icon.props.icon_name = 'emblem-neighborhood-shared'
+- notif_icon.props.xo_color = buddy.props.color
+- frame.add_notification(notif_icon,
+- gtk.CORNER_BOTTOM_RIGHT)
++ return button
+
+ def __mount_added_cb(self, volume_monitor, mount):
+ self._add_button(mount)
+@@ -302,13 +315,13 @@ class VolumesToolbar(gtk.Toolbar):
+
+ def _button_toggled_cb(self, button, force_toggle=False):
+ if button.props.active or force_toggle:
++ button.set_active(True)
+ from jarabe.journal.journalactivity import get_journal
+ journal = get_journal()
+
+ journal.get_list_view()._selected_entries = 0
+ journal.switch_to_editing_mode(False)
+ journal.get_list_view().inhibit_refresh(False)
+- journal.get_list_view().refresh()
+
+ self.emit('volume-changed', button.mount_point)
+
+@@ -328,6 +341,14 @@ class VolumesToolbar(gtk.Toolbar):
+ logging.error('Couldnt find button with mount_point %r', mount_point)
+ return None
+
++ def _get_button_for_mount_point(self, mount_point):
++ for button in self.get_children():
++ if button.mount_point == mount_point:
++ return button
++ logging.error('Couldnt find button with mount_point %r', mount_point)
++ return None
++
++
+ def _remove_button(self, mount):
+ button = self._get_button_for_mount(mount)
+ self._volume_buttons.remove(button)
+@@ -337,16 +358,20 @@ class VolumesToolbar(gtk.Toolbar):
+ if len(self.get_children()) < 2:
+ self.hide()
+
+- def _remove_remote_share_button(self, mount_point):
+- # Here, IP_Address is the mount_point.
++ def _remove_remote_share_button(self, ip_address_or_dns_name):
+ for button in self.get_children():
+ if type(button) == RemoteSharesButton and \
+- button.mount_point == mount_point:
++ button.mount_point == (model.WEBDAV_MOUNT_POINT + ip_address_or_dns_name):
+ self._volume_buttons.remove(button)
+ self.remove(button)
++
++ from jarabe.journal.webdavmanager import \
++ unmount_share_from_backend
++ unmount_share_from_backend(ip_address_or_dns_name)
++
+ self.get_children()[0].props.active = True
+
+- if len(sel.get_children()) < 2:
++ if len(self.get_children()) < 2:
+ self.hide()
+ break;
+
+@@ -478,6 +503,7 @@ class DirectoryButton(BaseButton):
+
+ def __init__(self, dir_path, icon_name):
+ BaseButton.__init__(self, mount_point=dir_path)
++ self._mount = dir_path
+
+ self.props.named_icon = icon_name
+
+@@ -488,16 +514,22 @@ class DirectoryButton(BaseButton):
+
+ class RemoteSharesButton(BaseButton):
+
+- def __init__(self, buddy):
+- BaseButton.__init__(self, mount_point=buddy.props.ip_address)
++ def __init__(self, primary_text, ip_address_or_dns_name, color,
++ share_type):
++ BaseButton.__init__(self, mount_point=(model.WEBDAV_MOUNT_POINT + ip_address_or_dns_name))
++
++ self._primary_text = primary_text
++ self._ip_address_or_dns_name = ip_address_or_dns_name
+
+- self._buddy = buddy
+- self.props.named_icon = 'emblem-neighborhood-shared'
+- self.props.xo_color = buddy.props.color
+- self._buddy_ip_address = buddy.props.ip_address
++ if share_type == SHARE_TYPE_PEER:
++ self.props.named_icon = 'emblem-neighborhood-shared'
++ elif share_type == SHARE_TYPE_SCHOOL_SERVER:
++ self.props.named_icon = 'school-server'
++ self.props.xo_color = color
+
+ def create_palette(self):
+- palette = RemoteSharePalette(self._buddy)
++ palette = RemoteSharePalette(self._primary_text, self._ip_address_or_dns_name,
++ self, True)
+ return palette
+
+
+diff --git a/src/jarabe/journal/webdavmanager.py b/src/jarabe/journal/webdavmanager.py
+index 6cd0713..3ff9990 100644
+--- a/src/jarabe/journal/webdavmanager.py
++++ b/src/jarabe/journal/webdavmanager.py
+@@ -1,5 +1,6 @@
+ from gettext import gettext as _
+
++import logging
+ import os
+ import sys
+
+@@ -13,11 +14,6 @@ from webdav.WebdavClient import CollectionStorer
+ def get_key_from_resource(resource):
+ return resource.path
+
+-def ensure_correct_remote_webdav_hierarchy(remote_webdav_share_resources,
+- remote_webdav_share_collections):
+- pass
+- #assert len(remote_webdav_share_collections.keys()) == 1
+-
+ class WebDavUrlManager(gobject.GObject):
+ """
+ This class holds all data, relevant to a WebDavUrl.
+@@ -50,6 +46,9 @@ class WebDavUrlManager(gobject.GObject):
+ def _get_number_of_collections(self):
+ return len(self._remote_webdav_share_collections)
+
++ def _get_root(self):
++ return self._root
++
+ def _get_resources_dict(self):
+ return self._remote_webdav_share_resources
+
+@@ -57,7 +56,13 @@ class WebDavUrlManager(gobject.GObject):
+ return self._remote_webdav_share_collections
+
+ def _get_resource_by_key(self, key):
+- return self._remote_webdav_share_resources[key]['resource']
++ if key in self._remote_webdav_share_resources.keys():
++ return self._remote_webdav_share_resources[key]['resource']
++ return None
++
++ def _add_or_replace_resource_by_key(self, key, resource):
++ self._remote_webdav_share_resources[key] = {}
++ self._remote_webdav_share_resources[key]['resource'] = resource
+
+ def _get_metadata_list(self):
+ metadata_list = []
+@@ -69,11 +74,9 @@ class WebDavUrlManager(gobject.GObject):
+ resource_container = self._remote_webdav_share_resources[resource_key]
+ return resource_container['webdav-properties']
+
+- def _set_metadata_for_resource(self, key, metadata):
+- self._remote_webdav_share_resources[key]['metadata'] = metadata
+-
+ def _fetch_resources_and_collections(self):
+ webdavConnection = CollectionStorer(self._WebDavUrl, validateResourceNames=False)
++ self._root = webdavConnection
+
+ authFailures = 0
+ while authFailures < 2:
+@@ -111,8 +114,13 @@ class WebDavUrlManager(gobject.GObject):
+ error_message = e
+ get_journal()._volume_error_cb(None, error_message,_('Error'))
+
+- # Simply return, in case of connection-not-available.
+- return False
++ # Re-raise this error.
++ # Note that since this is not an
++ # "AuthorizationError", this will not be caught
++ # by the outer except-block. Instead, it will
++ # navigate all the way back up, and will report
++ # the error in the enclosing except block.
++ raise e
+
+ else:
+ # If this indeed is an Authorization Error,
+@@ -138,25 +146,54 @@ class WebDavUrlManager(gobject.GObject):
+
+ webdav_manager = {}
+
++def get_data_webdav_manager(ip_address_or_dns_name):
++ return webdav_manager[ip_address_or_dns_name]['data']
++
++
++def get_metadata_webdav_manager(ip_address_or_dns_name):
++ return webdav_manager[ip_address_or_dns_name]['metadata']
+
+-def get_resource_by_ip_address_and_resource_key(ip_address, key):
+- global webdav_manager
+
+- if ip_address in webdav_manager.keys():
+- root_webdav = webdav_manager[ip_address]
+- resources_dict = root_webdav._get_resources_dict()
++def get_resource_by_resource_key(root_webdav, key):
++ resources_dict = root_webdav._get_resources_dict()
++ if key in resources_dict.keys():
+ resource_dict = resources_dict[key]
+ resource = resource_dict['resource']
+-
+ return resource
++ return None
+
+
+-def get_remote_webdav_share_metadata(ip_address):
+- protocol = 'dav://'
++def add_resource_by_resource_key(root_webdav, key,
++ content_file_path):
++ root = root_webdav._get_root()
+
+- root_webdav_url = '/webdav'
++ resource = root.addResource(key)
++
++ # Procure the resource-lock.
++ lockToken = resource.lock('olpc')
++
++ input_stream = open(content_file_path)
+
+- complete_root_url = protocol + ip_address + root_webdav_url
++ # Now, upload the data; but it's necessary to enclose this in a
++ # try-except-finally block here, since we need to close the
++ # input-stream, whatever may happen.
++ try:
++ resource.uploadFile(input_stream, lockToken)
++ root_webdav._add_or_replace_resource_by_key(key, resource)
++ except Exception, e:
++ logging.exception(e)
++ resource.delete(lockToken)
++ raise e
++ else:
++ resource.unlock(lockToken)
++ finally:
++ input_stream.close()
++
++
++def get_remote_webdav_share_metadata(ip_address_or_dns_name):
++ protocol = 'davs://'
++ root_webdav_url = '/webdav'
++ complete_root_url = protocol + ip_address_or_dns_name + root_webdav_url
+
+ root_webdav = WebDavUrlManager(complete_root_url, 'test', 'olpc')
+ if root_webdav._fetch_resources_and_collections() is False:
+@@ -165,7 +202,8 @@ def get_remote_webdav_share_metadata(ip_address):
+
+ # Keep reference to the "WebDavUrlManager", keyed by IP-Address.
+ global webdav_manager
+- webdav_manager[ip_address] = root_webdav
++ webdav_manager[ip_address_or_dns_name] = {}
++ webdav_manager[ip_address_or_dns_name]['data'] = root_webdav
+
+
+ # Assert that the number of collections is only one at this url
+@@ -174,12 +212,14 @@ def get_remote_webdav_share_metadata(ip_address):
+
+ root_sugar_metadata_url = root_webdav_url + '/.Sugar-Metadata'
+
+- complete_root_sugar_metadata_url = protocol + ip_address + root_sugar_metadata_url
++ complete_root_sugar_metadata_url = protocol + ip_address_or_dns_name + root_sugar_metadata_url
+ root_webdav_sugar_metadata = WebDavUrlManager(complete_root_sugar_metadata_url, 'test', 'olpc')
+ if root_webdav_sugar_metadata._fetch_resources_and_collections() is False:
+ # Return empty metadata list.
+ return []
+
++ webdav_manager[ip_address_or_dns_name]['metadata'] = root_webdav_sugar_metadata
++
+ # assert that the number of collections is zero at this url.
+ assert root_webdav_sugar_metadata._get_number_of_collections() == 0
+
+@@ -189,68 +229,82 @@ def get_remote_webdav_share_metadata(ip_address):
+ root_webdav_sugar_metadata_resources = root_webdav_sugar_metadata._get_resources_dict()
+
+ # Prepare the metadata-download folder.
+- downloaded_data_root_dir = '/tmp/' + ip_address
++ downloaded_data_root_dir = '/tmp/' + ip_address_or_dns_name
+ downloaded_metadata_file_dir = downloaded_data_root_dir + '/.Sugar-Metadata'
+ if os.path.isdir(downloaded_data_root_dir):
+ shutil.rmtree(downloaded_data_root_dir)
+ os.makedirs(downloaded_metadata_file_dir)
+
+- for root_webdav_resource_name in root_webdav_resources.keys():
+- """
+- root_webdav_resource_name is of the type ::
++ metadata_list = []
+
+- /webdav/a.txt
++ # Note that the presence of a resource in the metadata directory,
++ # is the only assurance of the entry (and its constituents) being
++ # present in entirety. Thus, always proceed taking the metadata as
++ # the "key".
++ for root_webdav_sugar_metadata_resource_name in root_webdav_sugar_metadata_resources.keys():
+ """
+- split_tokens_array = root_webdav_resource_name.split('/')
++ root_webdav_sugar_metadata_resource_name is of the type ::
+
+- # This will provide us with "a.txt"
+- basename = split_tokens_array[len(split_tokens_array) - 1]
++ /webdav/.Sugar-Metadata/a.txt.metadata, OR
++ /webdav/.Sugar-Metadata/a.txt.preview
++ """
+
+- # This will provide us with "a.txt.metadata"
+- sugar_metadata_basename = basename + '.metadata'
++ # If this is a "preview" resource, continue forward, as we only
++ # want the metadata list. The "preview" resources are anyways
++ # already present in the manager DS.
++ if root_webdav_sugar_metadata_resource_name.endswith('.preview'):
++ continue
+
+- # Thus will provide us with "/webdav/.Sugar-Metadata/a.txt.metadata"
+- sugar_metadata_url = root_sugar_metadata_url + '/' + sugar_metadata_basename
++ split_tokens_array = root_webdav_sugar_metadata_resource_name.split('/')
+
+- # Ensure that "sugar_metadata_url" is present as one of the
+- # keys in "root_webdav_sugar_metadata_resources"
+- assert sugar_metadata_url in root_webdav_sugar_metadata_resources.keys()
++ # This will provide us with "a.txt.metadata"
++ sugar_metadata_basename = split_tokens_array[len(split_tokens_array) - 1]
+
+- # Now download the metadata file, read its contents, and store
+- # the metadata in memory.
+- # It is assumed that the metadata-file is small enough to be
+- # read in one call to "read".
++ # This will provide us with "a.txt"
++ basename = sugar_metadata_basename[0:sugar_metadata_basename.index('.metadata')]
+
+ downloaded_metadata_file_path = downloaded_metadata_file_dir + '/' + sugar_metadata_basename
+- metadata_resource = root_webdav_sugar_metadata._get_resource_by_key(sugar_metadata_url)
++ metadata_resource = \
++ root_webdav_sugar_metadata._get_resource_by_key(root_webdav_sugar_metadata_resource_name)
+ metadata_resource.downloadFile(downloaded_metadata_file_path)
+
++
++ # We need to download the preview-file as well at this stage,
++ # so that it can be shown in the expanded entry.
++ downloaded_preview_file_path = downloaded_metadata_file_dir + \
++ '/' + basename + '.preview'
++ root_webdav_sugar_preview_resource_name = \
++ root_webdav_sugar_metadata_resource_name[0:root_webdav_sugar_metadata_resource_name.index('.metadata')] + \
++ '.preview'
++ preview_resource = \
++ root_webdav_sugar_metadata._get_resource_by_key(root_webdav_sugar_preview_resource_name)
++ if preview_resource is not None:
++ preview_resource.downloadFile(downloaded_preview_file_path)
++
++
+ file_pointer = open(downloaded_metadata_file_path)
+ metadata = eval(file_pointer.read())
+ file_pointer.close()
+
+- # Very critical.
+- # 1. CRITICAL ONE:
+- # Fill in the uid.
+- # Note that the file is not physically present.
++ # Fill in the missing metadata properties.
++ # Note that the file is not physically present.
+ metadata['uid'] = downloaded_data_root_dir + '/' + basename
+-
+- # 2. CRITICAL TWO:
+- # Fill in the properties, that can only be done by reading
+- # in the webdav-properties.
+- live_properties = root_webdav._get_live_properties(root_webdav_resource_name)
+- metadata['filesize'] = live_properties.getContentLength()
+- metadata['timestamp'] = live_properties.getLastModified()
+- metadata['creation_time'] = live_properties.getCreationDate()
++ metadata['creation_time'] = metadata['timestamp']
+
+ # Now, write this to the metadata-file, so that
+ # webdav-properties get gelled into sugar-metadata.
+-
+ file_pointer = open(downloaded_metadata_file_path, 'w')
+ file_pointer.write(simplejson.dumps(metadata))
+ file_pointer.close()
+
+- root_webdav._set_metadata_for_resource(root_webdav_resource_name,
+- metadata)
++ metadata_list.append(metadata)
++
++ return metadata_list
++
++
++def is_remote_webdav_loaded(ip_address_or_dns_name):
++ return ip_address_or_dns_name in webdav_manager.keys()
++
+
+- return root_webdav._get_metadata_list()
++def unmount_share_from_backend(ip_address_or_dns_name):
++ del webdav_manager[ip_address_or_dns_name]
+diff --git a/src/jarabe/view/buddymenu.py b/src/jarabe/view/buddymenu.py
+index dfbcfa3..f6af1b5 100644
+--- a/src/jarabe/view/buddymenu.py
++++ b/src/jarabe/view/buddymenu.py
+@@ -27,6 +27,7 @@ from sugar.graphics.palette import Palette
+ from sugar.graphics.menuitem import MenuItem
+ from sugar.graphics.icon import Icon
+
++from jarabe.frame.notification import NotificationIcon
+ from jarabe.model import shell
+ from jarabe.model import friends
+ from jarabe.model.session import get_session_manager
+@@ -73,11 +74,17 @@ class BuddyMenu(Palette):
+ self.menu.append(menu_item)
+ menu_item.show()
+
+- access_buddy_remote_share_menu_item = MenuItem(_('Access Share'), 'list-add')
+- access_buddy_remote_share_menu_item.connect('activate',
+- self._access_share_cb)
+- self.menu.append(access_buddy_remote_share_menu_item)
+- access_buddy_remote_share_menu_item.show()
++ remote_share_menu_item = None
++ from jarabe.journal import webdavmanager
++ if not webdavmanager.is_remote_webdav_loaded(self._buddy.props.ip_address):
++ remote_share_menu_item = MenuItem(_('Access Share'), 'list-add')
++ remote_share_menu_item.connect('activate', self._access_share_cb)
++ else:
++ remote_share_menu_item = MenuItem(_('Unmount Share'), 'list-remove')
++ remote_share_menu_item.connect('activate', self.__unmount_cb)
++
++ self.menu.append(remote_share_menu_item)
++ remote_share_menu_item.show()
+
+ self._invite_menu = MenuItem('')
+ self._invite_menu.connect('activate', self._invite_friend_cb)
+@@ -89,10 +96,36 @@ class BuddyMenu(Palette):
+ activity = home_model.get_active_activity()
+ self._update_invite_menu(activity)
+
++ def __unmount_cb(self, menuitem):
++ from jarabe.journal.journalactivity import get_journal
++ singleton_volumes_toolbar = get_journal().get_volumes_toolbar()
++ singleton_volumes_toolbar._remove_remote_share_button(self._buddy.props.ip_address)
++
+ def _access_share_cb(self, menuitem):
+ from jarabe.journal.journalactivity import get_journal
+ volumes_toolbar = get_journal().get_volumes_toolbar()
+- volumes_toolbar._add_remote_share_button(self._buddy)
++
++ # TRANS: Do not translate the """%s""".
++ primary_text = _('%s\'s Shares') % self._buddy.props.nick
++ button = volumes_toolbar._add_remote_share_button(primary_text,
++ self._buddy.props.ip_address,
++ self._buddy.props.color,
++ jarabe.journal.volumestoolbar.SHARE_TYPE_PEER)
++
++ # Now, make three levels of transitions, from the
++ # Neighborhood-view.
++
++ # 1. Switch to the home-view.
++ from jarabe.model import shell
++ from jarabe.model.shell import ShellModel
++ shell.get_model().set_zoom_level(ShellModel.ZOOM_HOME)
++
++ # 2. Switch to the journal-activity-view.
++ top_frame = jarabe.frame.get_view()
++ top_frame.switch_to_journal_activity()
++
++ # 3. Switch to the newly mounted-view.
++ volumes_toolbar._button_toggled_cb(button, force_toggle=True)
+
+ def _add_my_items(self):
+ item = MenuItem(_('Shutdown'), 'system-shutdown')
+diff --git a/src/jarabe/view/palettes.py b/src/jarabe/view/palettes.py
+index 3b26faf..f6bca48 100644
+--- a/src/jarabe/view/palettes.py
++++ b/src/jarabe/view/palettes.py
+@@ -339,33 +339,35 @@ class JournalXSPalette(Palette):
+
+
+ class RemoteSharePalette(Palette):
+- def __init__(self, buddy, button):
+- Palette.__init__(self, label=('%s\'s share' % buddy.props.nick))
+- self._buddy = buddy
++ def __init__(self, primary_text, ip_address_or_dns_name, button,
++ show_unmount_option):
++ Palette.__init__(self, label=primary_text)
+ self._button = button
++ self._ip_address_or_dns_name = ip_address_or_dns_name
+
+- self.props.secondary_text = glib.markup_escape_text(buddy.props.ip_address)
++ self.props.secondary_text = \
++ glib.markup_escape_text(self._ip_address_or_dns_name)
+
+- vbox = gtk.VBox()
+- self.set_content(vbox)
+- vbox.show()
++ if show_unmount_option == True:
++ vbox = gtk.VBox()
++ self.set_content(vbox)
++ vbox.show()
+
+- self.connect('popup', self.__popup_cb)
++ self.connect('popup', self.__popup_cb)
++ menu_item = MenuItem(pgettext('Share', 'Unmount'))
++ icon = Icon(icon_name='media-eject', icon_size=gtk.ICON_SIZE_MENU)
++ menu_item.set_image(icon)
++ icon.show()
+
+- menu_item = MenuItem(pgettext('Share', 'Unmount'))
+-
+- icon = Icon(icon_name='media-eject', icon_size=gtk.ICON_SIZE_MENU)
+- menu_item.set_image(icon)
+- icon.show()
+-
+- menu_item.connect('activate', self.__unmount_activate_cb)
+- self.menu.append(menu_item)
+- menu_item.show()
++ menu_item.connect('activate', self.__unmount_activate_cb)
++ self.menu.append(menu_item)
++ menu_item.show()
+
+ def __unmount_activate_cb(self, menu_item):
+ from jarabe.journal.journalactivity import get_journal
++
+ singleton_volumes_toolbar = get_journal().get_volumes_toolbar()
+- singleton_volumes_toolbar._remove_remote_share_button(self._buddy.props.ip_address)
++ singleton_volumes_toolbar._remove_remote_share_button(self._ip_address_or_dns_name)
+
+ def __popup_cb(self, palette):
+ pass
+diff --git a/src/webdav/Connection.py b/src/webdav/Connection.py
+index 66f7833..33719f9 100644
+--- a/src/webdav/Connection.py
++++ b/src/webdav/Connection.py
+@@ -197,7 +197,9 @@ class Connection(DAV):
+ path = _urlEncode(path)
+ try:
+ HTTPConnection.request(self, 'PUT', path, "", header)
+- self._blockCopySocket(srcfile, self, Connection.blockSize)
++ filesize = os.path.getsize(srcfile.name)
++ self._blockCopySocket(srcfile, self,
++ Connection.blockSize,filesize)
+ srcfile.close()
+ response = self.getresponse()
+ except (CannotSendRequest, socket.error, BadStatusLine, ResponseNotReady), exc:
+@@ -215,14 +217,15 @@ class Connection(DAV):
+ finally:
+ self._lock.release()
+
+- def _blockCopySocket(self, source, toSocket, blockSize):
++ def _blockCopySocket(self, source, toSocket, blockSize, filesize):
+ transferedBytes = 0
+ block = source.read(blockSize)
+- #while source.readinto(block, blockSize):
+ while len(block):
+- toSocket.send(block)
+ self.logger.debug("Wrote %d bytes." % len(block))
+ transferedBytes += len(block)
++ toSocket.send(block)
++ from jarabe.journal.journalactivity import get_journal
++ get_journal().update_progress(transferedBytes/(filesize*1.0))
+ block = source.read(blockSize)
+ self.logger.info("Transfered %d bytes." % transferedBytes)
+
+diff --git a/src/webdav/WebdavClient.py b/src/webdav/WebdavClient.py
+index ab5cec3..8ce5c77 100644
+--- a/src/webdav/WebdavClient.py
++++ b/src/webdav/WebdavClient.py
+@@ -336,6 +336,9 @@ class ResourceStorer(object):
+ else:
+ header["Content-length"] = 0
+
++ # We need to change the header["Content-length"] to a string.
++ header["Content-length"] = str(header["Content-length"])
++
+ try:
+ response = self.connection.put(self.path, content, extra_hdrs=header)
+ finally:
+@@ -367,7 +370,8 @@ class ResourceStorer(object):
+ # TODO: Other interface ? return self.connection.getfile()
+ return response
+
+- def downloadFile(self, localFileName):
++ def downloadFile(self, localFileName, show_progress=False,
++ filesize=0):
+ """
+ Copy binary data from permanent storage to a local file.
+
+@@ -377,7 +381,8 @@ class ResourceStorer(object):
+ remoteFile = self.downloadContent()
+ try:
+ socket.setdefaulttimeout(SOCKET_DEFAULT_TIMEOUT)
+- _blockCopyFile(remoteFile, localFile, Connection.blockSize)
++ _blockCopyFile(remoteFile, localFile, Connection.blockSize,
++ show_progress, filesize)
+ except socket.error, e:
+ raise e
+ remoteFile.close()
+@@ -807,7 +812,7 @@ class LockToken(object):
+ return self.value()
+
+
+-def _blockCopyFile(source, dest, blockSize):
++def _blockCopyFile(source, dest, blockSize, show_progress, filesize):
+ """
+ Copies a file in chunks of C{blockSize}.
+
+@@ -821,8 +826,11 @@ def _blockCopyFile(source, dest, blockSize):
+ transferedBytes = 0
+ block = source.read(blockSize)
+ while len(block):
+- dest.write(block)
+ transferedBytes += len(block);
++ dest.write(block)
++ if show_progress:
++ from jarabe.journal.journalactivity import get_journal
++ get_journal().update_progress(transferedBytes/(filesize * 1.0))
+ block = source.read(blockSize)
+
+ def _checkUrl(url):
+diff --git a/src/webdav/davlib.py b/src/webdav/davlib.py
+index f4dac91..a611e51 100644
+--- a/src/webdav/davlib.py
++++ b/src/webdav/davlib.py
+@@ -31,7 +31,7 @@ BLOCKSIZE = 16384
+ class HTTPProtocolChooser(httplib.HTTPSConnection):
+ def __init__(self, *args, **kw):
+ self.protocol = kw.pop('protocol')
+- if self.protocol == "https":
++ if self.__is_secure_protocol():
+ self.default_port = 443
+ else:
+ self.default_port = 80
+@@ -39,11 +39,14 @@ class HTTPProtocolChooser(httplib.HTTPSConnection):
+ apply(httplib.HTTPSConnection.__init__, (self,) + args, kw)
+
+ def connect(self):
+- if self.protocol == "https":
++ if self.__is_secure_protocol():
+ httplib.HTTPSConnection.connect(self)
+ else:
+ httplib.HTTPConnection.connect(self)
+
++ def __is_secure_protocol(self):
++ return (self.protocol == 'https') or (self.protocol == 'davs')
++
+
+ class HTTPConnectionAuth(HTTPProtocolChooser):
+ def __init__(self, *args, **kw):
+@@ -333,4 +336,4 @@ class DAV(HTTPConnectionAuth):
+ response = self.lock(url, owner, timeout, depth)
+ response.parse_lock_response()
+ return response.locktoken
+-
+\ No newline at end of file
++
+--
+1.7.4.4
+
diff --git a/rpms/sugar/0131-ac-2265-Displaying-the-laptop-model-in-the-control-p.patch b/rpms/sugar/0131-ac-2265-Displaying-the-laptop-model-in-the-control-p.patch
new file mode 100644
index 0000000..8bcec1c
--- /dev/null
+++ b/rpms/sugar/0131-ac-2265-Displaying-the-laptop-model-in-the-control-p.patch
@@ -0,0 +1,72 @@
+From 1cd84e13e0bad7fb9e7ede1261c338c0dd031ad0 Mon Sep 17 00:00:00 2001
+From: Ajay Garg <ajay@activitycentral.com>
+Date: Thu, 30 Aug 2012 18:29:04 +0530
+Subject: [PATCH] ac#2265: Displaying the laptop "model" in the control panel (UY).
+Organization: Sugar Labs Foundation
+Signed-off-by: Ajay Garg <ajay@activitycentral.com>
+---
+
+Copying the patch from
+https://git.ceibal.edu.uy/dx3-osbuilder-uy/dx3-osbuilder-uy/blobs/dx3-uy/scripts/parches/05-aboutcomputer_show_model_laptop.patch
+into dx3 osbuilder (bleeding-edge).
+
+ extensions/cpsection/aboutcomputer/model.py | 9 +++++++++
+ extensions/cpsection/aboutcomputer/view.py | 15 +++++++++++++++
+ 2 files changed, 24 insertions(+), 0 deletions(-)
+
+diff --git a/extensions/cpsection/aboutcomputer/model.py b/extensions/cpsection/aboutcomputer/model.py
+index 4510af6..27237e8 100644
+--- a/extensions/cpsection/aboutcomputer/model.py
++++ b/extensions/cpsection/aboutcomputer/model.py
+@@ -27,6 +27,8 @@ import dbus
+
+ from jarabe import config
+
++from ceibal import laptops
++
+ _NM_SERVICE = 'org.freedesktop.NetworkManager'
+ _NM_PATH = '/org/freedesktop/NetworkManager'
+ _NM_IFACE = 'org.freedesktop.NetworkManager'
+@@ -127,6 +129,13 @@ def print_build_number():
+ print get_build_number()
+
+
++def get_model_laptop():
++ model_laptop = laptops.get_model_laptop()
++ if model_laptop is None or not model_laptop:
++ model_laptop = _not_available
++ return model_laptop
++
++
+ def _parse_firmware_number(firmware_no):
+ if firmware_no is None:
+ firmware_no = _not_available
+diff --git a/extensions/cpsection/aboutcomputer/view.py b/extensions/cpsection/aboutcomputer/view.py
+index dd2f200..75b79df 100644
+--- a/extensions/cpsection/aboutcomputer/view.py
++++ b/extensions/cpsection/aboutcomputer/view.py
+@@ -110,6 +110,21 @@ class AboutComputer(SectionView):
+ box_software.set_border_width(style.DEFAULT_SPACING * 2)
+ box_software.set_spacing(style.DEFAULT_SPACING)
+
++ box_model = gtk.HBox(spacing=style.DEFAULT_SPACING)
++ label_model = gtk.Label(_('Model:'))
++ label_model.set_alignment(1, 0)
++ label_model.modify_fg(gtk.STATE_NORMAL,
++ style.COLOR_SELECTION_GREY.get_gdk_color())
++ box_model.pack_start(label_model, expand=False)
++ self._group.add_widget(label_model)
++ label_model.show()
++ label_model_no = gtk.Label(self._model.get_model_laptop())
++ label_model_no.set_alignment(0, 0)
++ box_model.pack_start(label_model_no, expand=False)
++ label_model_no.show()
++ box_software.pack_start(box_model, expand=False)
++ box_model.show()
++
+ box_build = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_build = gtk.Label(_('Build:'))
+ label_build.set_alignment(1, 0)
+--
+1.7.4.4
+
diff --git a/rpms/sugar/0132-ac-2266-Displaying-the-upgrade-version-in-the-contro.patch b/rpms/sugar/0132-ac-2266-Displaying-the-upgrade-version-in-the-contro.patch
new file mode 100644
index 0000000..be146dc
--- /dev/null
+++ b/rpms/sugar/0132-ac-2266-Displaying-the-upgrade-version-in-the-contro.patch
@@ -0,0 +1,178 @@
+From 0776ba7c0405a3bd1323f9788ea1c6a0764dde74 Mon Sep 17 00:00:00 2001
+From: Ajay Garg <ajay@activitycentral.com>
+Date: Thu, 30 Aug 2012 19:01:10 +0530
+Subject: [PATCH] ac#2266: Displaying the "upgrade version" in the control panel (UY).
+Organization: Sugar Labs Foundation
+Signed-off-by: Ajay Garg <ajay@activitycentral.com>
+---
+
+Copying the patches from
+ https://git.ceibal.edu.uy/dx3-osbuilder-uy/dx3-osbuilder-uy/blobs/dx3-uy/scripts/parches/01-uy-changes.patch
+ https://git.ceibal.edu.uy/dx3-osbuilder-uy/dx3-osbuilder-uy/blobs/dx3-uy/scripts/parches/02-uy-changes.patch
+ https://git.ceibal.edu.uy/dx3-osbuilder-uy/dx3-osbuilder-uy/blobs/dx3-uy/scripts/parches/03-uy-changes.patch
+
+into dx3 osbuilder (bleeding-edge).
+
+
+ bin/sugar-session | 6 ++++
+ extensions/cpsection/aboutcomputer/model.py | 26 +++++++++++++++++
+ extensions/cpsection/aboutcomputer/view.py | 40 +++++++++++++++++++++++++++
+ 3 files changed, 72 insertions(+), 0 deletions(-)
+
+diff --git a/bin/sugar-session b/bin/sugar-session
+index c2e3bff..7881aea 100755
+--- a/bin/sugar-session
++++ b/bin/sugar-session
+@@ -125,6 +125,11 @@ def setup_notification_service_cb():
+ from jarabe.model import notifications
+ notifications.init()
+
++def show_notifications_cb():
++ from ceibal.notifier import Notifier
++ n = Notifier()
++ n.show_messages_from_shell()
++
+ def setup_file_transfer_cb():
+ from jarabe.model import filetransfer
+ filetransfer.init()
+@@ -193,6 +198,7 @@ def file_monitor_changed_cb(monitor, one_file, other_file, event_type):
+ (one_file.get_path() == os.path.expanduser('~/.sugar/journal_created')):
+ if event_type == gio.FILE_MONITOR_EVENT_CREATED:
+ gobject.idle_add(setup_frame_cb)
++ gobject.idle_add(show_notifications_cb)
+ MONITOR_ACTION_TAKEN = True
+
+ def arrange_for_setup_frame_cb():
+diff --git a/extensions/cpsection/aboutcomputer/model.py b/extensions/cpsection/aboutcomputer/model.py
+index 27237e8..e9276b9 100644
+--- a/extensions/cpsection/aboutcomputer/model.py
++++ b/extensions/cpsection/aboutcomputer/model.py
+@@ -1,4 +1,5 @@
+ # Copyright (C) 2008 One Laptop Per Child
++# Copyright (C) 2010 Plan Ceibal <comunidad@plan.ceibal.edu.uy>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+@@ -18,6 +19,8 @@
+ import os
+ import logging
+ import re
++import ConfigParser
++import time
+ import subprocess
+ from gettext import gettext as _
+ import errno
+@@ -321,3 +324,26 @@ def get_last_updated_on_field():
+ # Everything should be fine (hopefully :-) )
+ return last_update_readable_format
+
++def get_plazo():
++ from ceibal import env
++ path_plazo = env.get_security_root()
++ try:
++ plazo = _read_file(os.path.join(path_plazo, "blacklist")).split("\n")[0].strip()
++ plazo = time.strftime( "%d-%m-%Y",time.strptime(plazo,'%Y%m%d'))
++ except:
++ plazo = _not_available
++
++ return plazo
++
++def get_act():
++ from ceibal import env
++ path_act = env.get_updates_root()
++ parser = ConfigParser.ConfigParser()
++ salida = parser.read(os.path.join(path_act, "mi_version"))
++ if salida == []:
++ version = _not_available
++ else:
++ version = ''
++ for seccion in parser.sections():
++ version = "%s%s: %s\n" %(version,seccion,parser.get(seccion,'version'))
++ return version
+diff --git a/extensions/cpsection/aboutcomputer/view.py b/extensions/cpsection/aboutcomputer/view.py
+index 75b79df..1aaef6b 100644
+--- a/extensions/cpsection/aboutcomputer/view.py
++++ b/extensions/cpsection/aboutcomputer/view.py
+@@ -79,6 +79,7 @@ class AboutComputer(SectionView):
+ vbox_identity.pack_start(box_identity, expand=False)
+ box_identity.show()
+
++ """
+ box_lease = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_lease = gtk.Label(_('Lease: '))
+ label_lease.set_alignment(1, 0)
+@@ -93,6 +94,7 @@ class AboutComputer(SectionView):
+ label_lease_ver.show()
+ vbox_identity.pack_start(box_lease, expand=False)
+ box_lease.show()
++ """
+
+ self._vbox.pack_start(vbox_identity, expand=False)
+ vbox_identity.show()
+@@ -170,6 +172,7 @@ class AboutComputer(SectionView):
+ box_software.pack_start(box_firmware, expand=False)
+ box_firmware.show()
+
++ """ It's not needed for Ceibal
+ box_wireless_fw = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_wireless_fw = gtk.Label(_('Wireless Firmware:'))
+ label_wireless_fw.set_alignment(1, 0)
+@@ -185,11 +188,47 @@ class AboutComputer(SectionView):
+ label_wireless_fw_no.show()
+ box_software.pack_start(box_wireless_fw, expand=False)
+ box_wireless_fw.show()
++ """
++
++ ##################### PLAZO ####################
++ box_plazo = gtk.HBox(spacing=style.DEFAULT_SPACING)
++ label_plazo = gtk.Label(_('Plazo:'))
++ label_plazo.set_alignment(1, 0)
++ label_plazo.modify_fg(gtk.STATE_NORMAL,
++ style.COLOR_SELECTION_GREY.get_gdk_color())
++ box_plazo.pack_start(label_plazo, expand=False)
++ self._group.add_widget(label_plazo)
++ label_plazo.show()
++ label_plazo_no = gtk.Label(self._model.get_plazo())
++ label_plazo_no.set_alignment(0, 0)
++ box_plazo.pack_start(label_plazo_no, expand=False)
++ label_plazo_no.show()
++ box_software.pack_start(box_plazo, expand=False)
++ box_plazo.show()
++
++ ######### VERSION DE ACTUALIZACION ##############
++
++ box_act = gtk.HBox(spacing=style.DEFAULT_SPACING)
++ label_act = gtk.Label(_('Versión de Actualización:'))
++ label_act.set_alignment(1, 0)
++ label_act.modify_fg(gtk.STATE_NORMAL,
++ style.COLOR_SELECTION_GREY.get_gdk_color())
++ box_act.pack_start(label_act, expand=False)
++ self._group.add_widget(label_act)
++ label_act.show()
++ label_act_no = gtk.Label(self._model.get_act())
++ label_act_no.set_alignment(0, 0)
++ box_act.pack_start(label_act_no, expand=False)
++ label_act_no.show()
++ box_software.pack_start(box_act, expand=False)
++ box_act.show()
++
+
+ # Try to fetch "Last Updated On" field from the model.
+ # If the field is not empty, display it.
+ # At present, the field is returned empty, only if "root-access"
+ # is disabled on the target-machine.
++ """
+ last_updated_on_field = self._model.get_last_updated_on_field()
+ if last_updated_on_field:
+ box_last_updated_on = gtk.HBox(spacing=style.DEFAULT_SPACING)
+@@ -207,6 +246,7 @@ class AboutComputer(SectionView):
+ label_last_updated_on_field.show()
+ box_software.pack_start(box_last_updated_on, expand=False)
+ box_last_updated_on.show()
++ """
+
+ self._vbox.pack_start(box_software, expand=False)
+ box_software.show()
+--
+1.7.4.4
+
diff --git a/rpms/sugar/0133-ac-2268-Extensions-removal-touchpad-modes-system-mon.patch b/rpms/sugar/0133-ac-2268-Extensions-removal-touchpad-modes-system-mon.patch
new file mode 100644
index 0000000..97c600b
--- /dev/null
+++ b/rpms/sugar/0133-ac-2268-Extensions-removal-touchpad-modes-system-mon.patch
@@ -0,0 +1,642 @@
+From db1c00a2b46dd4a1908e7860eba1e66fa6da361a Mon Sep 17 00:00:00 2001
+From: Ajay Garg <ajay@activitycentral.com>
+Date: Thu, 30 Aug 2012 19:45:54 +0530
+Subject: [PATCH] ac#2268: Extensions removal: touchpad modes, system monitoring and feedback (UY).
+Organization: Sugar Labs Foundation
+Signed-off-by: Ajay Garg <ajay@activitycentral.com>
+---
+ extensions/deviceicon/Makefile.am | 6 +-
+ extensions/deviceicon/feedback.py | 179 ------------------------------
+ extensions/deviceicon/resources.py | 215 ------------------------------------
+ extensions/deviceicon/touchpad.py | 142 ------------------------
+ extensions/globalkey/Makefile.am | 1 -
+ extensions/globalkey/touchpad.py | 33 ------
+ 6 files changed, 1 insertions(+), 575 deletions(-)
+ delete mode 100644 extensions/deviceicon/feedback.py
+ delete mode 100644 extensions/deviceicon/resources.py
+ delete mode 100644 extensions/deviceicon/touchpad.py
+ delete mode 100644 extensions/globalkey/touchpad.py
+
+diff --git a/extensions/deviceicon/Makefile.am b/extensions/deviceicon/Makefile.am
+index b38cbb3..67d08f9 100644
+--- a/extensions/deviceicon/Makefile.am
++++ b/extensions/deviceicon/Makefile.am
+@@ -4,10 +4,6 @@ sugar_PYTHON = \
+ __init__.py \
+ battery.py \
+ network.py \
+- resources.py \
+ speaker.py \
+- touchpad.py \
+ virtualkeyboard.py \
+- volume.py \
+- feedback.py
+-
++ volume.py
+diff --git a/extensions/deviceicon/feedback.py b/extensions/deviceicon/feedback.py
+deleted file mode 100644
+index 49db09b..0000000
+--- a/extensions/deviceicon/feedback.py
++++ /dev/null
+@@ -1,179 +0,0 @@
+-# Copyright (C) Mukesh Gupta <mukeshgupta.2006@gmail.com>
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# 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. See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-
+-import logging
+-from gettext import gettext as _
+-
+-import gconf
+-import gtk
+-
+-from sugar import profile
+-from sugar.graphics import style
+-from sugar.graphics.icon import Icon
+-from sugar.graphics.tray import TrayIcon
+-from sugar.graphics.palette import Palette
+-from sugar.graphics.menuitem import MenuItem
+-from sugar.graphics.toolbutton import ToolButton
+-
+-from jarabe.model import feedback_collector
+-
+-
+-_ICON_NAME = 'feedback-icon'
+-
+-
+-class DeviceView(TrayIcon):
+-
+- FRAME_POSITION_RELATIVE = 500
+-
+- def __init__(self):
+- TrayIcon.__init__(self, icon_name=_ICON_NAME,
+- xo_color=profile.get_color())
+- self.create_palette()
+-
+- def create_palette(self):
+- logging.debug('palette created')
+- self.palette = _Palette(_('Feedback'))
+- self.palette.set_group_id('frame')
+- return self.palette
+-
+-
+-class _Palette(Palette):
+-
+- def __init__(self, primary_text):
+- Palette.__init__(self, primary_text)
+-
+- icon = Icon()
+- icon.set_from_icon_name('emblem-favorite', gtk.ICON_SIZE_MENU)
+- icon.props.xo_color = profile.get_color()
+-
+- personalized = MenuItem(_('Personalized submit...'))
+- personalized.set_image(icon)
+- personalized.connect('activate', self.__personalized_activate_cb)
+- personalized.show()
+- self.menu.append(personalized)
+-
+- self._anonymous = MenuItem(_('Anonymous submit'), 'emblem-favorite')
+- self._anonymous.connect('activate', self.__anonymous_activate_cb)
+- self._anonymous.show()
+- self.menu.append(self._anonymous)
+-
+- def popup(self, immediate=False, state=None):
+- self._anonymous.set_sensitive(not feedback_collector.is_empty())
+- Palette.popup(self, immediate=immediate, state=state)
+-
+- def __anonymous_activate_cb(self, button):
+- feedback_collector.anonymous_submit()
+-
+- def __personalized_activate_cb(self, button):
+- window = _Window()
+- window.show()
+-
+-
+-class _Window(gtk.Window):
+-
+- __gtype_name__ = 'FeedbackWindow'
+-
+- def __init__(self):
+- gtk.Window.__init__(self)
+-
+- self.set_border_width(style.LINE_WIDTH)
+- offset = style.GRID_CELL_SIZE
+- width = gtk.gdk.screen_width() - offset * 2
+- height = gtk.gdk.screen_height() - offset * 2
+- self.set_size_request(width, height)
+- self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+- self.set_decorated(False)
+- self.set_resizable(False)
+- self.set_modal(True)
+-
+- canvas = gtk.VBox()
+- self.add(canvas)
+-
+- self._toolbar = gtk.Toolbar()
+- canvas.pack_start(self._toolbar, False)
+-
+- icon = Icon()
+- icon.set_from_icon_name('emblem-favorite', gtk.ICON_SIZE_LARGE_TOOLBAR)
+- icon.props.xo_color = profile.get_color()
+- self._add_widget(icon)
+-
+- self._add_separator(False)
+-
+- title = gtk.Label(_('Submit feedback'))
+- self._add_widget(title)
+-
+- self._add_separator(True)
+-
+- submit = ToolButton('dialog-ok', tooltip=_('Submit'))
+- submit.connect('clicked', lambda button: self._submit())
+- self._toolbar.insert(submit, -1)
+-
+- cancel = ToolButton('dialog-cancel', tooltip=_('Cancel'))
+- cancel.connect('clicked', lambda button: self.destroy())
+- self._toolbar.insert(cancel, -1)
+-
+- bg = gtk.EventBox()
+- bg.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color())
+- canvas.pack_start(bg)
+-
+- self._message = gtk.TextView()
+- scrolled = gtk.ScrolledWindow()
+- scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+- scrolled.set_border_width(style.DEFAULT_PADDING)
+- scrolled.add(self._message)
+- bg.add(scrolled)
+-
+- self.show_all()
+- self.set_focus(self._message)
+-
+- self.connect("realize", self.__realize_cb)
+-
+- def do_key_press_event(self, event):
+- if event.keyval == gtk.keysyms.Escape:
+- self.destroy()
+- elif event.keyval == gtk.keysyms.Return and \
+- event.state & gtk.gdk.CONTROL_MASK:
+- self._submit()
+- else:
+- gtk.Window.do_key_press_event(self, event)
+-
+- def _add_widget(self, widget):
+- tool_item = gtk.ToolItem()
+- tool_item.add(widget)
+- self._toolbar.insert(tool_item, -1)
+-
+- def _add_separator(self, expand):
+- separator = gtk.SeparatorToolItem()
+- separator.props.draw = False
+- if expand:
+- separator.set_expand(True)
+- else:
+- separator.set_size_request(style.DEFAULT_SPACING, -1)
+- self._toolbar.insert(separator, -1)
+-
+- def _submit(self):
+- feedback_collector.submit(self._message.props.buffer.props.text)
+- self.destroy()
+-
+- def __realize_cb(self, widget):
+- self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+- self.window.set_accept_focus(True)
+-
+-
+-def setup(tray):
+- client = gconf.client_get_default()
+- if client.get_bool('/desktop/sugar/feedback/personalized_submit'):
+- tray.add_device(DeviceView())
+diff --git a/extensions/deviceicon/resources.py b/extensions/deviceicon/resources.py
+deleted file mode 100644
+index 5e39d4e..0000000
+--- a/extensions/deviceicon/resources.py
++++ /dev/null
+@@ -1,215 +0,0 @@
+-# Copyright (C) Anish Mangal <anishmangal2002@gmail.com>
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# 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. See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-
+-from gettext import gettext as _
+-import logging
+-import os
+-
+-import gobject
+-import gtk
+-import gconf
+-
+-from sugar.graphics.tray import TrayIcon
+-from sugar.graphics.xocolor import XoColor
+-from sugar.graphics.palette import Palette
+-from sugar.graphics import style
+-
+-
+-_SYSTEM_MOODS = ['-sad', '-normal', '-happy']
+-_ICON_NAME = 'computer'
+-_UPDATE_INTERVAL = 5 * 1000
+-
+-
+-class DeviceView(TrayIcon):
+-
+- FRAME_POSITION_RELATIVE = 500
+-
+- def __init__(self):
+- client = gconf.client_get_default()
+- self._color = XoColor(client.get_string('/desktop/sugar/user/color'))
+- TrayIcon.__init__(self, icon_name=_ICON_NAME, xo_color=self._color)
+- self.create_palette()
+- self._icon_widget.connect('button-release-event', self._click_cb)
+-
+- def create_palette(self):
+- self.palette = ResourcePalette(_('System resources'))
+- self.palette.set_group_id('frame')
+- self.palette.add_timer()
+- self.palette.connect('system-mood-changed',
+- self._system_mood_changed_cb)
+- return self.palette
+-
+- def _system_mood_changed_cb(self, palette_, mood):
+- self.icon.props.icon_name = _ICON_NAME + mood
+-
+- def _click_cb(self, widget, event):
+- self.palette_invoker.notify_right_click()
+-
+-
+-class ResourcePalette(Palette):
+- __gsignals__ = {
+- 'system-mood-changed': (gobject.SIGNAL_RUN_FIRST,
+- gobject.TYPE_NONE,
+- ([str])),
+- }
+-
+- def __init__(self, primary_text):
+- Palette.__init__(self, label=primary_text)
+-
+- self.vbox = gtk.VBox()
+- self.set_content(self.vbox)
+-
+- self._cpu_text = gtk.Label()
+- self.vbox.pack_start(self._cpu_text, padding=style.DEFAULT_PADDING)
+- self._cpu_bar = gtk.ProgressBar()
+- self._cpu_bar.set_size_request(
+- style.zoom(style.GRID_CELL_SIZE * 4), -1)
+- self.vbox.pack_start(self._cpu_bar, padding=style.DEFAULT_PADDING)
+-
+- self._memory_text = gtk.Label()
+- self.vbox.pack_start(self._memory_text, padding=style.DEFAULT_PADDING)
+- self._memory_bar = gtk.ProgressBar()
+- self._memory_bar.set_size_request(
+- style.zoom(style.GRID_CELL_SIZE * 4), -1)
+- self.vbox.pack_start(self._memory_bar, padding=style.DEFAULT_PADDING)
+-
+- self._system_mood = None
+- try:
+- self._cpu_times = self._get_cpu_times_list()
+- except IOError:
+- logging.exception('An error ocurred while attempting to '
+- 'read /proc/stat')
+- self._stop_computing_statistics()
+-
+- self.vbox.show()
+- self._cpu_text.show()
+- self._cpu_bar.show()
+- self._memory_text.show()
+- self._memory_bar.show()
+-
+- def add_timer(self):
+- gobject.timeout_add(_UPDATE_INTERVAL, self.__timer_cb)
+-
+- def _get_cpu_times_list(self):
+- """Return various cpu times as read from /proc/stat
+-
+- This method returns the following cpu times measured
+- in jiffies (1/100 of a second for x86 systems)
+- as an ordered list of numbers - [user, nice,
+- system, idle, iowait] where,
+-
+- user: normal processes executing in user mode
+- nice: niced processes executing in user mode
+- system: processes executing in kernel mode
+- idle: twiddling thumbs
+- iowait: waiting for I/O to complete
+-
+- Note: For systems having 2 or more CPU's, the above
+- numbers would be the cumulative sum of these times
+- for all CPU's present in the system.
+-
+- """
+- return [int(count)
+- for count in file('/proc/stat').readline().split()[1:6]]
+-
+- def _percentage_cpu_available(self):
+- """
+- Return free CPU resources as a percentage
+-
+- """
+- _cpu_times_new = self._get_cpu_times_list()
+- _cpu_times_current = [(new - old)
+- for new, old in zip(_cpu_times_new, self._cpu_times)]
+- user_, nice_, system_, idle, iowait = _cpu_times_current
+- cpu_free = (idle + iowait) * 100.0 / sum(_cpu_times_current)
+- self._cpu_times = self._get_cpu_times_list()
+- return cpu_free
+-
+- def _percentage_memory_available(self):
+- """
+- Return free memory as a percentage
+-
+- """
+- for line in file('/proc/meminfo'):
+- name, value, unit_ = line.split()[:3]
+- if 'MemTotal:' == name:
+- total = int(value)
+- elif 'MemFree:' == name:
+- free = int(value)
+- elif 'Buffers:' == name:
+- buffers = int(value)
+- elif 'Cached:' == name:
+- cached = int(value)
+- elif 'Active:' == name:
+- break
+- return (free + buffers + cached) * 100.0 / total
+-
+- def __timer_cb(self):
+- try:
+- cpu_in_use = 100 - self._percentage_cpu_available()
+- memory_in_use = 100 - self._percentage_memory_available()
+- except IOError:
+- logging.exception('An error ocurred while trying to '
+- 'retrieve resource usage statistics')
+- self._stop_and_show_error()
+- return False
+- else:
+- self._cpu_text.set_label(_('CPU in use: %d%%' % cpu_in_use))
+- self._cpu_bar.set_fraction(float(cpu_in_use) / 100)
+- self._memory_text.set_label(_('Memory in use: %d%%' %
+- memory_in_use))
+- self._memory_bar.set_fraction(float(memory_in_use) / 100)
+-
+- # both cpu_free and memory_free lie between 0-100
+- system_mood = _SYSTEM_MOODS[
+- int(300 - (cpu_in_use + 2 * memory_in_use)) // 100]
+-
+- # check if self._system_mood exists
+- try:
+- if self._system_mood != system_mood:
+- self.emit('system-mood-changed', system_mood)
+- self._system_mood = system_mood
+- except AttributeError:
+- self.emit('system-mood-changed', system_mood)
+- self._system_mood = system_mood
+-
+- return True
+-
+- def _stop_and_show_error(self):
+- """
+- Stop computing usage statistics and display an error message
+- since we've hit an exception.
+-
+- """
+- # Use the existing _cpu_text label to display the error. Remove
+- # everything else.
+- self._cpu_text.set_size_request(
+- style.zoom(style.GRID_CELL_SIZE * 4), -1)
+- self._cpu_text.set_line_wrap(True)
+- self._cpu_text.set_text(_('Cannot compute CPU and memory usage '
+- 'statistics!'))
+- self.vbox.remove(self._cpu_bar)
+- self.vbox.remove(self._memory_text)
+- self.vbox.remove(self._memory_bar)
+- self.emit('system-mood-changed', '-error')
+-
+-
+-def setup(tray):
+- if not (os.path.exists('/proc/stat') and os.path.exists('/proc/meminfo')):
+- logging.warning('Either /proc/stat or /proc/meminfo not present. Not '
+- 'adding the CPU and memory usage icon to the frame')
+- return
+- tray.add_device(DeviceView())
+diff --git a/extensions/deviceicon/touchpad.py b/extensions/deviceicon/touchpad.py
+deleted file mode 100644
+index ba02037..0000000
+--- a/extensions/deviceicon/touchpad.py
++++ /dev/null
+@@ -1,142 +0,0 @@
+-# Copyright (C) 2010, Walter Bender, Sugar Labs
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# 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. See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-
+-
+-from gettext import gettext as _
+-import os
+-
+-import gtk
+-import gconf
+-import glib
+-
+-import logging
+-
+-from sugar.graphics.tray import TrayIcon
+-from sugar.graphics.xocolor import XoColor
+-from sugar.graphics.palette import Palette
+-from sugar.graphics import style
+-
+-from jarabe.frame.frameinvoker import FrameWidgetInvoker
+-
+-TOUCHPAD_MODE_CAPACITIVE = 'capacitive'
+-TOUCHPAD_MODE_RESISTIVE = 'resistive'
+-TOUCHPAD_MODES = [TOUCHPAD_MODE_CAPACITIVE, TOUCHPAD_MODE_RESISTIVE]
+-STATUS_TEXT = {
+- TOUCHPAD_MODE_CAPACITIVE: _('finger'),
+- TOUCHPAD_MODE_RESISTIVE: _('stylus'),
+-}
+-STATUS_ICON = {
+- TOUCHPAD_MODE_CAPACITIVE: 'touchpad-' + TOUCHPAD_MODE_CAPACITIVE,
+- TOUCHPAD_MODE_RESISTIVE: 'touchpad-' + TOUCHPAD_MODE_RESISTIVE,
+-}
+-# NODE_PATH is used to communicate with the touchpad device.
+-NODE_PATH = '/sys/devices/platform/i8042/serio1/ptmode'
+-
+-_view = None
+-
+-
+-class DeviceView(TrayIcon):
+- """ Manage the touchpad mode from the device palette on the Frame. """
+-
+- FRAME_POSITION_RELATIVE = 500
+-
+- def __init__(self):
+- """ Create the icon that represents the touchpad. """
+- icon_name = STATUS_ICON[_read_touchpad_mode()]
+-
+- client = gconf.client_get_default()
+- color = XoColor(client.get_string('/desktop/sugar/user/color'))
+- TrayIcon.__init__(self, icon_name=icon_name, xo_color=color)
+-
+- self.set_palette_invoker(FrameWidgetInvoker(self))
+- self.connect('button-release-event', self.__button_release_event_cb)
+-
+- def create_palette(self):
+- """ Create a palette for this icon; called by the Sugar framework
+- when a palette needs to be displayed. """
+- label = glib.markup_escape_text(_('My touchpad'))
+- self._palette = ResourcePalette(label, self.icon)
+- self._palette.set_group_id('frame')
+- return self._palette
+-
+- def __button_release_event_cb(self, widget, event):
+- """ Callback for button release event; used to invoke touchpad-mode
+- change. """
+- self._palette.toggle_mode()
+- return True
+-
+-
+-class ResourcePalette(Palette):
+- """ Palette attached to the decive icon that represents the touchpas. """
+-
+- def __init__(self, primary_text, icon):
+- """ Create the palette and initilize with current touchpad status. """
+- Palette.__init__(self, label=primary_text)
+-
+- self._icon = icon
+-
+- vbox = gtk.VBox()
+- self.set_content(vbox)
+-
+- self._status_text = gtk.Label()
+- vbox.pack_start(self._status_text, padding=style.DEFAULT_PADDING)
+- self._status_text.show()
+-
+- vbox.show()
+-
+- self._mode = _read_touchpad_mode()
+- self._update()
+-
+- def _update(self):
+- """ Update the label and icon based on the current mode. """
+- self._status_text.set_label(STATUS_TEXT[self._mode])
+- self._icon.props.icon_name = STATUS_ICON[self._mode]
+-
+- def toggle_mode(self):
+- """ Toggle the touchpad mode. """
+- self._mode = TOUCHPAD_MODES[1 - TOUCHPAD_MODES.index(self._mode)]
+- _write_touchpad_mode(self._mode)
+- self._update()
+-
+-
+-def setup(tray):
+- """ Initialize the device icon; called by the shell when initializing the
+- Frame. """
+- global _view
+- if os.path.exists(NODE_PATH):
+- _view = DeviceView()
+- tray.add_device(_view)
+- _write_touchpad_mode(TOUCHPAD_MODE_CAPACITIVE)
+-
+-
+-def _read_touchpad_mode():
+- """ Read the touchpad mode from the node path. """
+- node_file_handle = open(NODE_PATH, 'r')
+- text = node_file_handle.read()
+- node_file_handle.close()
+-
+- return TOUCHPAD_MODES[int(text[0])]
+-
+-
+-def _write_touchpad_mode(touchpad):
+- """ Write the touchpad mode to the node path. """
+- try:
+- node_file_handle = open(NODE_PATH, 'w')
+- except IOError, e:
+- logging.error('Error opening %s for writing: %s', NODE_PATH, e)
+- return
+- node_file_handle.write(str(TOUCHPAD_MODES.index(touchpad)))
+- node_file_handle.close()
+diff --git a/extensions/globalkey/Makefile.am b/extensions/globalkey/Makefile.am
+index e3aaa8a..b44626e 100644
+--- a/extensions/globalkey/Makefile.am
++++ b/extensions/globalkey/Makefile.am
+@@ -4,6 +4,5 @@ sugar_PYTHON = \
+ __init__.py \
+ magnifier.py \
+ screenshot.py \
+- touchpad.py \
+ viewsource.py \
+ virtualkeyboard.py
+diff --git a/extensions/globalkey/touchpad.py b/extensions/globalkey/touchpad.py
+deleted file mode 100644
+index eeaba40..0000000
+--- a/extensions/globalkey/touchpad.py
++++ /dev/null
+@@ -1,33 +0,0 @@
+-# Copyright (C) 2010, Martin Abente
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# 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. See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-
+-import logging
+-
+-BOUND_KEYS = ['<alt>m']
+-touchpad = None
+-
+-def handle_key_press(key):
+- global touchpad
+- if touchpad is None:
+- try:
+- touchpad = __import__('deviceicon.touchpad', globals(),
+- locals(), ['touchpad'])
+- except Exception:
+- logging.error('Could not import touchpad module.')
+- return
+-
+- if touchpad._view is not None:
+- touchpad._view._palette.toggle_mode()
+--
+1.7.4.4
+
diff --git a/rpms/sugar/0134-translation-fix-closes-sdxo-2218.patch b/rpms/sugar/0134-translation-fix-closes-sdxo-2218.patch
new file mode 100644
index 0000000..891dc3b
--- /dev/null
+++ b/rpms/sugar/0134-translation-fix-closes-sdxo-2218.patch
@@ -0,0 +1,28 @@
+From 576a403428b981bcfd0d9f7f4ee0f192e09c1e87 Mon Sep 17 00:00:00 2001
+From: Pootle daemon <pootle@pootle.sugarlabs.org>
+Date: Thu, 30 Aug 2012 21:34:27 +0200
+Subject: [PATCH] Commit from Sugar Labs: Translation System by user
+ RafaelOrtiz.: 380 of 380 messages translated (0 fuzzy).
+
+---
+ po/es.po | 8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/po/es.po b/po/es.po
+index a1cbd6d..32e7163 100644
+--- a/po/es.po
++++ b/po/es.po
+@@ -316,8 +316,8 @@ msgid ""
+ "server will be able to see each other, even when they aren't on the same "
+ "network."
+ msgstr ""
+-"El servidor es equivalente al cuarto en el cual se esta; la gente en el "
+-"mismo servidor podrá verse entre ellos, aun cuando no esten en la misma red."
++"El servidor es equivalente al cuarto en el cual se está; la gente en el "
++"mismo servidor podrá verse entre si, aun cuando no esten en la misma red."
+
+ #: ../extensions/cpsection/network/view.py:140
+ msgid "Server:"
+--
+1.7.4.4
+
diff --git a/rpms/sugar/0135-ac-2233-Change-the-behaviour-of-Sugar-not-connect-to.patch b/rpms/sugar/0135-ac-2233-Change-the-behaviour-of-Sugar-not-connect-to.patch
new file mode 100644
index 0000000..9d2eb94
--- /dev/null
+++ b/rpms/sugar/0135-ac-2233-Change-the-behaviour-of-Sugar-not-connect-to.patch
@@ -0,0 +1,45 @@
+From f89371d20ec99a545c23cd8b122a5188426c734e Mon Sep 17 00:00:00 2001
+From: Ajay Garg <ajay@activitycentral.com>
+Date: Fri, 31 Aug 2012 13:37:02 +0530
+Subject: [PATCH] ac#2233: Change the behaviour of Sugar: not connect to adhoc networks by default.
+Organization: Sugar Labs Foundation
+Signed-off-by: Ajay Garg <ajay@activitycentral.com>
+---
+
+This behaviour is controlled by the gconf-key
+"/desktop/sugar/network/autoconnect_to_adhoc_networks".
+
+
+ src/jarabe/desktop/meshbox.py | 9 ++++++++-
+ 1 files changed, 8 insertions(+), 1 deletions(-)
+
+diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
+index c111e7e..950ac12 100644
+--- a/src/jarabe/desktop/meshbox.py
++++ b/src/jarabe/desktop/meshbox.py
+@@ -63,6 +63,11 @@ _OLPC_MESH_ICON_NAME = 'network-mesh'
+ _AUTOSEARCH_TIMEOUT = 1000
+ _FILTERED_ALPHA = 0.33
+
++AUTOCONNECT_TO_ADHOC_NETWORKS_GCONF_KEY = '/desktop/sugar/network/autoconnect_to_adhoc_networks'
++client = gconf.client_get_default()
++AUTOCONNECT_TO_ADHOC_NETWORKS_GCONF_VALUE = client.get_bool(AUTOCONNECT_TO_ADHOC_NETWORKS_GCONF_KEY)
++
++
+
+ class _ActivityIcon(CanvasIcon):
+ def __init__(self, model, file_name, xo_color,
+@@ -621,7 +626,9 @@ class MeshBox(gtk.VBox):
+ self._add_adhoc_network_icon(1)
+ self._add_adhoc_network_icon(6)
+ self._add_adhoc_network_icon(11)
+- self._adhoc_manager.autoconnect()
++
++ if AUTOCONNECT_TO_ADHOC_NETWORKS_GCONF_VALUE == True:
++ self._adhoc_manager.autoconnect()
+
+ def remove_adhoc_networks(self):
+ for icon in self._adhoc_networks:
+--
+1.7.4.4
+
diff --git a/rpms/sugar/0136-ac-126-PART-Backporting-the-mainline-patch-that-inco.patch b/rpms/sugar/0136-ac-126-PART-Backporting-the-mainline-patch-that-inco.patch
new file mode 100644
index 0000000..c5ab654
--- /dev/null
+++ b/rpms/sugar/0136-ac-126-PART-Backporting-the-mainline-patch-that-inco.patch
@@ -0,0 +1,50 @@
+From 66b2ddf53796afecbe6d26b62957d206cb3b0ec4 Mon Sep 17 00:00:00 2001
+From: Ajay Garg <ajay@activitycentral.com>
+Date: Fri, 31 Aug 2012 14:38:33 +0530
+Subject: [PATCH 3/3] ac#126-PART: Backporting the mainline patch; that
+ incorporates Ruben's feedback to sort the countries by
+ names in the dropdown.
+Organization: Sugar Labs Foundation
+Signed-off-by: Ajay Garg <ajay@activitycentral.com>
+---
+ extensions/cpsection/modemconfiguration/model.py | 16 ++++++++++++++--
+ 1 files changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/extensions/cpsection/modemconfiguration/model.py b/extensions/cpsection/modemconfiguration/model.py
+index e0a792d..a5426e6 100644
+--- a/extensions/cpsection/modemconfiguration/model.py
++++ b/extensions/cpsection/modemconfiguration/model.py
+@@ -156,6 +156,11 @@ class CountryListStore(gtk.ListStore):
+ etree = ElementTree(file=PROVIDERS_PATH).getroot()
+ self._country_idx = None
+ i = 0
++
++ # This dictionary wil store the values, with "country-name" as
++ # the key, and "country-code" as the value.
++ temp_dict = {}
++
+ for elem in etree.findall('.//country'):
+ code = elem.attrib['code']
+ if code == self.COUNTRY_CODE:
+@@ -163,9 +168,16 @@ class CountryListStore(gtk.ListStore):
+ else:
+ i += 1
+ if code in codes:
+- self.append((codes[code], elem))
++ temp_dict[codes[code]] = elem
+ else:
+- self.append((code, elem))
++ temp_dict[code] = elem
++
++ # Now, sort the list by country-names.
++ country_name_keys = temp_dict.keys()
++ country_name_keys.sort()
++
++ for country_name in country_name_keys:
++ self.append((country_name, temp_dict[country_name]))
+
+ def get_row_providers(self, row):
+ return self[row][1]
+--
+1.7.4.4
+
diff --git a/rpms/sugar/0137-sugar-gnomekeyring.patch b/rpms/sugar/0137-sugar-gnomekeyring.patch
new file mode 100644
index 0000000..590a39c
--- /dev/null
+++ b/rpms/sugar/0137-sugar-gnomekeyring.patch
@@ -0,0 +1,33 @@
+Taken from http://pkgs.fedoraproject.org/cgit/sugar.git/tree/sugar-gnomekeyring.patch
+
+diff --git a/bin/sugar.in b/bin/sugar.in
+index 12098db..df27143 100644
+--- a/bin/sugar.in
++++ b/bin/sugar.in
+@@ -62,6 +62,26 @@ export LANGUAGE="${LANGUAGE:-${LANG}}"
+ # Set Sugar's telepathy accounts directory
+ export MC_ACCOUNT_DIR=$HOME/.sugar/$SUGAR_PROFILE/accounts
+
++# Check if the keyring exists and create a default
++# unencrypted keyring (OLPC #10290)
++keyring_path=$HOME/.gnome2/keyrings
++if [ ! -e $keyring_path/login.keyring ] &&
++ [ ! -e $keyring_path/default.keyring ]; then
++ mkdir -p $keyring_path
++ echo 'default' > $keyring_path/default
++ TIME=$(/bin/date +%s)
++ cat >> $keyring_path/default.keyring.tmp <<EOF
++[keyring]
++display-name=default
++ctime=$TIME
++mtime=$TIME
++lock-on-idle=false
++lock-timeout=0
++EOF
++
++mv $keyring_path/default.keyring{.tmp,}
++fi
++
+ # Workaround until gnome-keyring-daemon lets dbus activate it
+ # https://bugzilla.gnome.org/show_bug.cgi?id=628302
+ if test "$SUGAR_EMULATOR" = "yes" -a "$(type gnome-keyring-daemon)"; then
diff --git a/rpms/sugar/AUlangs.diff b/rpms/sugar/AUlangs.diff
deleted file mode 100644
index 09a6a75..0000000
--- a/rpms/sugar/AUlangs.diff
+++ /dev/null
@@ -1,11 +0,0 @@
---- configure.ac.orig 2012-02-08 16:36:08.000000000 -0600
-+++ configure.ac 2012-02-08 16:36:47.000000000 -0600
-@@ -18,7 +18,7 @@
-
- # Setup GETTEXT
- #
--ALL_LINGUAS="af am ar ay aym bg bi bn_IN bn ca cpp cs da de dz el en es fa_AF fa ff fil fr gu ha he hi ht hu id ig is it ja km ko kos mg mi mk ml mn mr ms mvo nb ne nl pa pap pis pl ps pt_BR pt qu quz ro ru rw sd si sk sl sq sv sw ta te th tpi tr tvl tzo ug ur vi wa yo zh_CN zh_TW"
-+ALL_LINGUAS="af am ar ay aym bg bi bn_IN bn ca cpp cs da de dz el en en_GB es fa_AF fa ff fil fr gu ha he hi ht hu id ig is it ja km ko kos mg mi mk ml mn mr ms mvo nb ne nl pa pap pis pl ps pt_BR pt qu quz ro ru rw sd si sk sl sq sv sw ta te th tpi tr tvl tzo ug ur vi wa yo zh_CN zh_TW"
-
- GETTEXT_PACKAGE=sugar
- AC_PROG_INTLTOOL([0.33])
diff --git a/rpms/sugar/sugar.spec b/rpms/sugar/sugar.spec
index 914ee09..62ce2d2 100644
--- a/rpms/sugar/sugar.spec
+++ b/rpms/sugar/sugar.spec
@@ -2,16 +2,11 @@
Summary: Constructionist learning platform
Name: sugar
-Epoch: 20120720
+Epoch: 20120907
Version: 0.94.1
-Release: 31.dx3
+Release: 33.dx3
URL: http://sugarlabs.org/
Source0: http://download.sugarlabs.org/sources/sucrose/glucose/%{name}/%{name}-%{version}.tar.bz2
-Source1: http://people.sugarlabs.org/silbe/dextrose/patchsets/%{name}-dx3-20120720.tar.gz
-
-# Insert development patches not included in patchset here
-patch0: AUlangs.diff
-
License: GPLv2+
Group: User Interface/Desktops
@@ -98,10 +93,7 @@ Requires: %{name} <= %{epoch}:%{version}-%{release}
%description control-keyboard
sugar-control-frame addon to sugar's control panel.
%prep
-%setup -T -c -a 1 -n patches
-%setup -D -q
-for patch in ../patches/* ; do patch -p1 < "${patch}" ; done
-%patch0 -p0
+%setup -q
%build
autoreconf -i
@@ -127,6 +119,9 @@ export GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source`
gconftool-2 --makefile-install-rule \
%{_sysconfdir}/gconf/schemas/sugar.schemas > /dev/null || :
+mkdir -p /home/olpc/.sugar/default
+openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" -keyout /home/olpc/.sugar/default/ssl.key -out /home/olpc/.sugar/default/ssl.crt
+
%pre
if [ "$1" -gt 1 ]; then
export GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source`
@@ -194,6 +189,12 @@ rm -rf %{buildroot}
%{_datadir}/sugar/extensions/cpsection/keyboard/*
%changelog
+* Tue Sep 04 2012 Ajay Garg <ajay@activitycentral.com> - 20120907:0.94.1-33.dx3
+- Fixed sdxo#2296. We need to have the "/home/olpc/.sugar/default" directory present, before we can generate the ssl-cert pair "into" it.
+
+* Tue Sep 04 2012 Ajay Garg <ajay@activitycentral.com> - 20120904:0.94.1-32.dx3
+- In "%post" section, added mechanism to add a ssl-key and -cert pair; for sharing entries via HTTPD-WebDAV in a secure manner.
+
* Fri Jul 20 2012 Anish Mangal <anish@activitycentral.com> - 20120720:0.94.1-31.dx3
- Added some es translations with inputs from Rafael Ortiz <rafael@activitycentral.com> and Ajay Garg <ajay@activitycentral.com>